Skip to content

Instantly share code, notes, and snippets.

@jdlcdl
Last active March 14, 2024 10:47
Show Gist options
  • Save jdlcdl/f3c5225efa55d1d0b02bad6b46930cb1 to your computer and use it in GitHub Desktop.
Save jdlcdl/f3c5225efa55d1d0b02bad6b46930cb1 to your computer and use it in GitHub Desktop.
krux upgrade v22 to v23

Upgrading krux from v22.08.2 to v23.09.0 on maixpy_amigo_tft


To start with a clean slate, erased the entire 16MB SPI-Flash so that all bytes are 0xff.

python3 ./firmware/Kboot/build/ktool.py -B goE -b 1500000 -E
...
[INFO] Erasing the whole SPI Flash.
[INFO] SPI Flash erased.

Downloaded krux-v22.08.2.zip from https://github.com/selfcustody/krux/releases/tag/v22.08.2

unzip -l ~/Downloads/krux-v22.08.2.zip
...
Archive:  ~/Downloads/krux-v22.08.2.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2022-09-13 05:14   krux-v22.08.2/
        0  2022-09-13 05:34   krux-v22.08.2/maixpy_bit/
       70  1980-01-01 00:00   krux-v22.08.2/maixpy_bit/firmware.bin.sig
  1705088  2022-09-13 05:03   krux-v22.08.2/maixpy_bit/firmware.bin
   894855  2022-09-13 05:03   krux-v22.08.2/maixpy_bit/kboot.kfpkg
  7806062  2022-09-13 04:22   krux-v22.08.2/ktool-win.exe
  6313696  2022-09-13 04:22   krux-v22.08.2/ktool-mac-10
  7222448  2022-09-13 04:22   krux-v22.08.2/ktool-mac
        0  2022-09-13 05:34   krux-v22.08.2/maixpy_amigo_tft/
       70  1980-01-01 00:00   krux-v22.08.2/maixpy_amigo_tft/firmware.bin.sig
  1716288  2022-09-13 04:52   krux-v22.08.2/maixpy_amigo_tft/firmware.bin
   897074  2022-09-13 04:52   krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg
        0  2022-09-13 05:33   krux-v22.08.2/maixpy_m5stickv/
       70  1980-01-01 00:00   krux-v22.08.2/maixpy_m5stickv/firmware.bin.sig
  1712000  2022-09-13 04:31   krux-v22.08.2/maixpy_m5stickv/firmware.bin
   896570  2022-09-13 04:31   krux-v22.08.2/maixpy_m5stickv/kboot.kfpkg
 16478872  2022-09-13 04:22   krux-v22.08.2/ktool-linux
        0  2022-09-13 05:34   krux-v22.08.2/maixpy_amigo_ips/
       70  1980-01-01 00:00   krux-v22.08.2/maixpy_amigo_ips/firmware.bin.sig
  1716288  2022-09-13 04:41   krux-v22.08.2/maixpy_amigo_ips/firmware.bin
   897059  2022-09-13 04:41   krux-v22.08.2/maixpy_amigo_ips/kboot.kfpkg
        0  2022-09-13 05:34   krux-v22.08.2/maixpy_dock/
       70  1980-01-01 00:00   krux-v22.08.2/maixpy_dock/firmware.bin.sig
  1705088  2022-09-13 05:14   krux-v22.08.2/maixpy_dock/firmware.bin
   894856  2022-09-13 05:14   krux-v22.08.2/maixpy_dock/kboot.kfpkg
---------                     -------
 50856594                     25 files

Inflated kboot.kfpkg and got sha256 hashes of binaries contained within.

unzip -e ~/Downloads/krux-v22.08.2.zip krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg
...
inflating: krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg

sha256sum krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg
...
11669c3addf05af3dc102d22c942b80483fa839a7cfb07ad9cfe60ade5067cfd  krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg

unzip -l krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg
...
Archive:  krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg
  Length      Date    Time    Name
---------  ---------- -----   ----
      647  2022-09-13 04:52   flash-list.json
      608  2022-09-13 04:52   bootloader_lo.bin
     8112  2022-09-13 04:52   bootloader_hi.bin
     4096  2022-03-30 15:38   config.bin
  1716288  2022-09-13 04:52   firmware.bin
---------                     -------
  1729751                     5 files

unzip -p krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg bootloader_lo.bin | sha256sum
...
2e050a92efdcb172cb5c6f7cb0b669ba654d2d20219f810fd9fc543f7ef05c3e  -

unzip -p krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg bootloader_hi.bin | sha256sum
...
f005f7c8b13aa2719cad58492a8432f14b68b2f845b58e5b5e81ed6309be6172  -

unzip -p krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg config.bin | sha256sum
c9b9c4adcabe9c353a907f44c101c3b29756b30762e4b282d87d2a92400e2198  -

unzip -p krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg firmware.bin | sha256sum
5067429beb16bd0eac55401ea673f55f9cc97585b1a0607d64f8e5f486d4988b  -

Using usb, flashed the device with v22.08.2 kboot.kfpkg

python3 ./firmware/Kboot/build/ktool.py -B goE -b 1500000 krux-v22.08.2/maixpy_amigo_tft/kboot.kfpkg
...
[INFO] Flashed 1716325 B [27 chunks of 65536B] (00080000~0022FFFF) in 22.967s 
[INFO] Rebooting...

Connecting to the amigo via usb console and interrupting krux, stopping WDT, to work in python REPL.

screen /dev/ttyUSB1 115200
...
<ctrl>-C
...
KeyboardInterrupt: 
MicroPython v1.11 on 2022-09-13; Sipeed_M1 with kendryte-k210
Type "help()" for more information.
>>> 
>>> from machine import WDT;WDT().stop()
>>>

Cutting and pasting scripts for analyzing SPI-Flash.

Btw, it's <ctrl>-E to enter cut/paste mode, <ctrl>-D when done.

I do it in small chunks to avoid un-explained syntax errors with large cut/pastes.

TODO: publish scripts when they're mature enough for others to use.

Click to see hacky/prototype code.
class MockedMaixUtils:
   def flash_read(self, address, length):
       with open('/tmp/k210.flash_dump', 'rb') as f:
            f.seek(address)
            return f.read(length)

try: from Maix import utils
except: utils = MockedMaixUtils()

def decremented_bool(value):
  '''returns value as a bool or an int > 0'''

  if type(value) == int:
      if value > 0:
          return value - 1

      elif value == 0:
          return False

      else:
          raise TypeError('if value is <int>, must be >= 0: found %d' % value)

  elif type(value) == bool:
      return value

  else:
      raise TypeError('value must be <int> >= 0 or <bool> found %s' % value)

def hash_flash(begin=0x00, length=2**24, block_size=2**12, verbose=False):
  '''
  hash the entirety of flash memory

  assumes that utils.flash_read() behaves as if imported from Maix
  '''

  from math import ceil
  from hashlib import sha256
  from binascii import hexlify

  assert block_size % block_size == 0, 'block_size must be divisible by 4096'
  _hash = sha256()

  if verbose:
      print('Hashing %s bytes of flash at %s...' % (length, hex(begin)), end='')

  bytes_read = 0
  while bytes_read < length:
      if bytes_read + block_size < length:
          _hash.update(utils.flash_read(begin+bytes_read, block_size))
          bytes_read += block_size
      else:
          _hash.update(utils.flash_read(begin+bytes_read, length-bytes_read))
          bytes_read += length - bytes_read

      if verbose:
          print('.', end='')

  answer = _hash.digest()

  if verbose:
      print('\nsha256 of %s bytes at %s:\n%s' % (bytes_read, hex(begin), hexlify(answer).decode()
      ))

  return answer

def all_bytes_are(byte, begin, length, block_size=2**12, verbose=False):
  '''
  returns True if all bytes in flash are the same as byte, otherwise False

  assumes that utils.flash_read() behaves as if imported from Maix
  '''

  from binascii import hexlify

  answer = True

  if verbose:
      print("Checking if %s bytes of flash at %s are all 0x%s..." % (
          length, hex(begin), hexlify(byte).decode()), end='')

  bytes_read = 0
  while bytes_read < length:
      if bytes_read + block_size < length:
          if utils.flash_read(begin+bytes_read, block_size) != byte * block_size:
              answer = False
              break
          bytes_read += block_size
      else:
          if utils.flash_read(begin+bytes_read, length-bytes_read) != byte * (length - bytes_read):
              answer = False
              break
          bytes_read += length - bytes_read

      if verbose:
          print('.', end='')

  if verbose:
      print("\nthe %s bytes at %s are %s 0x%s." % (
          length, hex(begin), 'ALL' if answer else 'NOT all', hexlify(byte).decode()))

  return answer

def validate_aes_size_app_sha(begin, verbose=False):
  '''
  verify a ktool sector as (0x0 aes byte + 4B-lil-size + appdata + shasuffix) for standard sectors

  assumes that utils.flash_read() behaves as if imported from Maix
  '''

  from binascii import hexlify

  sectors = {
      # address, block_size, sector_name
      0x0: (0x1000, 'Kboot stage-0'),
      0x1000: (0x1000, 'Kboot stage-1'),
      0x80000: (0x10000, 'firmware slot1'),
      0x280000: (0x10000, 'firmware slot2'),
  }
  bytes_read = 0

  if verbose:
      print('Validating sector format (aes+size+app+sha) at %s...' % hex(begin))

  if begin not in sectors:
      if verbose:
          print('%s not in %s.' % (begin, sectors))
      return None, bytes_read
  block_size, sector_name = sectors[begin]
  if verbose:
      print('sector known as "%s", will use blocks_size %s,' % (sector_name, block_size))

  header = utils.flash_read(begin, 5)
  bytes_read += 5
  if not header[0] == 0x00:
      if verbose:
          print('first (aes) byte of header 0x%s is not 0x00.' % (hexlify(header).decode()))
      return None, bytes_read
  length = int.from_bytes(header[1:5], 'little')
  bytes_read += length
  if verbose:
      print('header indicates %s bytes of data,' % length)

  hash_suffix = utils.flash_read(begin+5+length, 32)
  bytes_read += 32
  _hash = hash_flash(begin, length=5+length, block_size=block_size, verbose=decremented_bool(verbose))
  if _hash != hash_suffix:
      if verbose:
          print('hash of %s bytes of header+data does not match suffix:\n  suffix: %s\n   found: %s' % (
               5+length, hexlify(hash_suffix).decode(), hexlify(_hash).decode()))
          hash_flash(begin + 5, length, block_size=block_size, verbose=1)
      return None, bytes_read
  if verbose:
      print('sha256(header + data) == suffix, is expected format for this sector,')

  partial = (5 + length + 32) % block_size
  if partial:
      padding = block_size - partial
      if not all_bytes_are(b'\x00', begin+5+length+32, block_size-partial, verbose=decremented_bool(verbose)):
          if verbose:
              print('%s bytes to pad rest of sector are not all 0x00 bytes.' % padding)
          return None, bytes_read
      bytes_read += padding
      if verbose:
          print('%s bytes to pad rest of sector are ALL 0x00 bytes.' % padding)

  return True, bytes_read

def analyze_spi_flash(verbose=False):
  '''
  Analyze the entirety of SPI flash

  assumes that utils.flash_read() behaves as if imported from Maix
  '''

  from binascii import hexlify

  def ktool_app_size(address):
      size = int.from_bytes(utils.flash_read(address+1, 4), 'little')
      if size > 2**24 - address: return 0
      else: return size

  def be_verbose(msg='', *args):
      messages = {
          'ktool_sector': '\nChecking "%s" from %s to %s-1', # 3 args: name, start, end+1
          'validated': 'SPI flash from %s to %s-1 is %s.', # 3 args: start, end+1, 'valid'|'invalid'
          'hashed': 'sha256 hash of SPI flash from %s to %s-1 is:\n%s', # 3 args: start, end+1, hash
          'filesizehash': 'sha256 hash of "%s" having %s bytes is:\n%s', # 3 args: name, size, hash
      }
      if msg in messages and len(args):
          print(messages[msg] % args)
      else:
          print(msg)

  spi_flash_size = 2**24
  cursor = 0x0

  # 4096 bytes at 0x0 are of aes_size_app_sha format
  be_verbose('ktool_sector', 'Kboot stage-0', hex(cursor), hex(cursor+4096))
  valid, bytes_read = validate_aes_size_app_sha(cursor, verbose=decremented_bool(verbose))
  be_verbose('validated', hex(cursor), hex(cursor+bytes_read), 'valid' if valid else 'INVALID')
  assert valid and bytes_read, 'checking "Kboot stage-0"'
  _size = ktool_app_size(cursor)
  _hash = hash_flash(cursor+5, _size, verbose=decremented_bool(verbose))
  be_verbose('filesizehash', 'bootloader_lo.bin', _size, hexlify(_hash).decode())
  cursor += bytes_read

  # 8192 bytes at 0x1000 are of aes_size_app_sha format and the next 4096 are 0xff
  be_verbose('ktool_sector', 'Kboot stage-1', hex(cursor), hex(cursor+12288))
  valid, bytes_read = validate_aes_size_app_sha(cursor, verbose=decremented_bool(verbose))
  be_verbose('validated', hex(cursor), hex(cursor+bytes_read), 'valid' if valid else 'INVALID')
  assert valid and bytes_read, 'checking "Kboot stage-1"'
  _size = ktool_app_size(cursor)
  _hash = hash_flash(cursor+5, _size, verbose=decremented_bool(verbose))
  be_verbose('filesizehash', 'bootloader_hi.bin', _size, hexlify(_hash).decode())
  cursor += bytes_read

  valid = all_bytes_are(b'\xff', cursor, 4096, verbose=decremented_bool(verbose))
  if type(valid) == bool:
      bytes_read = 4096
  be_verbose('validated', hex(cursor), hex(cursor+bytes_read), 'all 0xff' if valid else 'NOT all 0xff!')
  assert valid and bytes_read, 'checking last third of "Kboot stage-1"'
  cursor += bytes_read

  # 4096 bytes at 0x4000 are main config
  be_verbose('ktool_sector', 'main config', hex(cursor), hex(cursor+4096))
  _hash = hash_flash(cursor, 4096, verbose=decremented_bool(verbose))
  if len(_hash) == 32:
       valid, bytes_read = True, 4096
  be_verbose('filesizehash', 'config.bin', 4096, hexlify(_hash).decode())
  assert valid and bytes_read, 'hashing "main config"'
  cursor += bytes_read

  # 4096 bytes at 0x5000 are config backup
  be_verbose('ktool_sector', 'backup config', hex(cursor), hex(cursor+4096))
  _other_hash = hash_flash(cursor, 4096, verbose=decremented_bool(verbose))
  if len(_hash) == 32:
       valid, bytes_read = True, 4096
  be_verbose('hashed', hex(cursor), hex(cursor+bytes_read), hexlify(_other_hash).decode())
  assert valid and bytes_read, 'hashing "backup config"'
  cursor += bytes_read

  # 40960 bytes at 0x6000 are reserved
  be_verbose('ktool_sector', 'reserved', hex(cursor), hex(cursor+40960))
  valid = all_bytes_are(b'\xff', cursor, 40960, verbose=decremented_bool(verbose))
  if type(valid) == bool:
      bytes_read = 40960
  be_verbose('validated', hex(cursor), hex(cursor+bytes_read), 'all 0xff' if valid else 'NOT all 0xff!')
  assert valid and bytes_read, 'checking that "reserved" is unused'
  cursor += bytes_read

  # the first 0x70000 bytes are unused
  be_verbose('ktool_sector', 'unused app/user', hex(cursor), hex(cursor+0x70000))
  valid = all_bytes_are(b'\xff', cursor, 0x70000, verbose=decremented_bool(verbose))
  if type(valid) == bool:
      bytes_read = 0x70000
  be_verbose('validated', hex(cursor), hex(cursor+bytes_read), 'all 0xff' if valid else 'NOT all 0xff!')
  assert valid and bytes_read, 'checking that "app/user" is unused'
  cursor += bytes_read

  # variable bytes at firmware slot1 0x80000 are firmware
  valid, bytes_read = validate_aes_size_app_sha(cursor, verbose=decremented_bool(verbose))
  be_verbose('ktool_sector', 'firmware_slot1', hex(cursor), hex(cursor+bytes_read))
  be_verbose('validated', hex(cursor), hex(cursor+bytes_read), 'valid' if valid else 'INVALID')
  _size = ktool_app_size(cursor)
  _hash = hash_flash(cursor+5, _size, verbose=decremented_bool(verbose))
  be_verbose('filesizehash', 'firmware.bin', _size, hexlify(_hash).decode())
  assert valid and bytes_read, 'checking firmware slot1'
  cursor += bytes_read

  # variable bytes up to firmware slot2 are unused
  _size = 0x280000 - cursor
  be_verbose('ktool_sector', 'unused app/user', hex(cursor), hex(cursor+_size))
  valid = all_bytes_are(b'\xff', cursor, _size, verbose=decremented_bool(verbose))
  if type(valid) == bool:
      bytes_read = _size
  be_verbose('validated', hex(cursor), hex(cursor+_size), 'all 0xff' if valid else 'NOT all 0xff!')
  assert valid and bytes_read, 'checking that "app/user" is unused'
  cursor += bytes_read

  # variable bytes at firmware slot2 0x280000 are firmware
  valid, bytes_read = validate_aes_size_app_sha(cursor, verbose=decremented_bool(verbose))
  be_verbose('ktool_sector', 'firmware_slot2', hex(cursor), hex(cursor+bytes_read))
  be_verbose('validated', hex(cursor), hex(cursor+bytes_read), 'valid' if valid else 'INVALID')
  if valid:
      _size = ktool_app_size(cursor)
      _hash = hash_flash(cursor+5, _size, verbose=decremented_bool(verbose))
      be_verbose('filesizehash', 'firmware.bin', _size, hexlify(_hash).decode())
      cursor += bytes_read

  # bytes between firmware and spiffs are unused
  _size = 0xd00000 - cursor
  be_verbose('ktool_sector', 'unused app/user', hex(cursor), hex(cursor+_size))
  valid = all_bytes_are(b'\xff', cursor, _size, verbose=decremented_bool(verbose))
  if type(valid) == bool:
      bytes_read = _size
  be_verbose('validated', hex(cursor), hex(cursor+_size), 'all 0xff' if valid else 'NOT all 0xff!')
  assert valid and bytes_read, 'checking that "app/user" is unused'
  cursor += bytes_read
  
  # 0x300000 spiffs bytes at 0xD00000
  _size = 0x300000
  be_verbose('ktool_sector', 'SPI Flash Filing System', hex(cursor), hex(cursor+_size))
  _hash = hash_flash(cursor, _size, verbose=decremented_bool(verbose))
  if len(_hash) == 32:
       valid, bytes_read = True, _size
  be_verbose('filesizehash', 'SPI Flash Filing System', _size, hexlify(_hash).decode())
  assert valid and bytes_read, 'hashing SPIFFS'
  cursor += bytes_read

  # hash entirety of SPI flash
  be_verbose('ktool_sector', 'SPI flash', hex(0x0), hex(spi_flash_size))
  _hash = hash_flash(0x0, spi_flash_size, verbose=decremented_bool(verbose))
  be_verbose('filesizehash', '16MB SPI flash', spi_flash_size, hexlify(_hash).decode())

class HexDumpSPIFlash:
  '''
  hex dump for maixpy 16MB SPI Flash

  assumes that utils.flash_read() behaves as if imported from Maix
  '''

  size = 2**24
  def __init__(self, begin=0x0, width=16, lines=16, squeeze=True):
      self.cursor = begin
      self.configure(width=width, lines=lines, squeeze=squeeze)

  def next(self):
      pass

  def prev(self):
      page_size = self.width * self.lines
      self.cursor = (self.size + self.cursor - (page_size * 2)) % self.size

  def seek(self, address):
      self.cursor = address % self.size

  def configure(self, width=None, lines=None, squeeze=True):
      if type(width) == int and width > 0: 
          self.width = width

      if type(lines) == int and lines > 0: 
          self.lines = lines

      if type(squeeze) == bool:
          self.squeeze = squeeze

      byte_format = '  '.join([' '.join(['{:02x}']*4)]*(self.width//4))
      if self.width % 4:
           byte_format = '  '.join([byte_format, ' '.join(['{:02x}']*(self.width%4))])
      self.fmt = '{}  {}  |{}|'.format('{:06x}', byte_format, '{:.1s}'*self.width)

  def read(self, update_cursor=False):
      def format_record(address, record):
          if len(record) == self.width:
              return self.fmt.format(
                  *[address]
                  +[x for x in record]
                  +[len(repr(str(chr(x))))==3 and str(chr(x)) or '.' for x in record]
              )
          else:
              return '{:06x}  {} [EOR]'.format(
                  address, 
                  ' '.join(['{:02x}'.format(x) for x in record])
                  )
      first = self.cursor
      answer, buf, i_buf, line_no, repeats, last_record = [], (None, b''), 0, 0, 0, (None, b'')
      while line_no < self.lines:
          if i_buf + 1 >= len(buf[1]):
              buf = (first, utils.flash_read(first, self.width*self.lines))
              i_buf = 0

          record = (first, buf[1][i_buf:i_buf+self.width])
          if repeats:
              if record[1] != last_record[1]:
                  answer.extend([
                      '... {:d} squeezed'.format(repeats-1) if repeats>1 else '', 
                      format_record(*last_record), 
                      format_record(*record)
                  ]) 
                  repeats = 0
                  line_no += 3
              else:
                  repeats += 1
          else:
              if self.squeeze and record[1] == last_record[1]:
                  repeats += 1
              else:
                  answer.append(format_record(*record))
                  line_no += 1
          i_buf += len(record[1])
          first = (first + len(record[1])) % self.size
          last_record = record
      if repeats:
          answer.extend([
              '... {:d} squeezed'.format(repeats-1) if repeats>1 else '', 
              format_record(*record)
          ]) 
      if update_cursor:
          self.cursor = first
      return '\n'.join(answer)

  def run(self):
      def set_lines():
          self.configure(lines=int(input('Enter number of lines: ')))

      def set_width():
          self.configure(width=int(input('Enter number of bytes per line: ')))

      def toggle_squeeze():
          self.configure(squeeze=not self.squeeze)

      def seek():
          address = input('Enter an address: ')
          if address[:2] == '0b':
               address = int(address[2:], 2)
          elif address[:2] == '0x':
               address = int(address[2:], 16)
          else:
               address = int(address)
          self.seek(address)

      repl = {
      'j': self.next,
      'k': self.prev,
      'l': set_lines,
      'w': set_width,
      's': toggle_squeeze,
      '/': seek,
      }
      print(self.read(update_cursor=True))
      while True:
          _in = input('\b')
          if _in and _in[0] in repl:
              repl[_in]()
              print(self.read(update_cursor=True))
          elif _in == 'q':
              return
          else: print('Try one of %s or "q" to quit.' % [x for x in repl.keys()])

Running the analyze_spi_flash function:

>>> analyze_spi_flash()

Checking "Kboot stage-0" from 0x0 to 0x1000-1
SPI flash from 0x0 to 0x1000-1 is valid.
sha256 hash of "bootloader_lo.bin" having 608 bytes is:
2e050a92efdcb172cb5c6f7cb0b669ba654d2d20219f810fd9fc543f7ef05c3e

Checking "Kboot stage-1" from 0x1000 to 0x4000-1
SPI flash from 0x1000 to 0x3000-1 is valid.
sha256 hash of "bootloader_hi.bin" having 8112 bytes is:
f005f7c8b13aa2719cad58492a8432f14b68b2f845b58e5b5e81ed6309be6172
SPI flash from 0x3000 to 0x4000-1 is all 0xff.

Checking "main config" from 0x4000 to 0x5000-1
sha256 hash of "config.bin" having 4096 bytes is:
c9b9c4adcabe9c353a907f44c101c3b29756b30762e4b282d87d2a92400e2198

Checking "backup config" from 0x5000 to 0x6000-1
sha256 hash of SPI flash from 0x5000 to 0x6000-1 is:
c9b9c4adcabe9c353a907f44c101c3b29756b30762e4b282d87d2a92400e2198

Checking "reserved" from 0x6000 to 0x10000-1
SPI flash from 0x6000 to 0x10000-1 is all 0xff.

Checking "unused app/user" from 0x10000 to 0x80000-1
SPI flash from 0x10000 to 0x80000-1 is all 0xff.

Checking "firmware_slot1" from 0x80000 to 0x230000-1
SPI flash from 0x80000 to 0x230000-1 is valid.
sha256 hash of "firmware.bin" having 1716288 bytes is:
5067429beb16bd0eac55401ea673f55f9cc97585b1a0607d64f8e5f486d4988b

Checking "unused app/user" from 0x230000 to 0x280000-1
SPI flash from 0x230000 to 0x280000-1 is all 0xff.

Checking "firmware_slot2" from 0x280000 to 0x280005-1
SPI flash from 0x280000 to 0x280005-1 is INVALID.

Checking "unused app/user" from 0x280000 to 0xd00000-1
SPI flash from 0x280000 to 0xd00000-1 is all 0xff.

Checking "SPI Flash Filing System" from 0xd00000 to 0x1000000-1
sha256 hash of "SPI Flash Filing System" having 3145728 bytes is:
e945c6bf2b3bdcf927b19a24e911f0cac73fb39a95a606cb6c043e335433b118

Checking "SPI flash" from 0x0 to 0x1000000-1
sha256 hash of "16MB SPI flash" having 16777216 bytes is:
ee874f63fbeab613db997a60408c332848f619c833e27ef1778e85f2fd23c6fb

Downloaded krux-v23.09.0.zip from https://github.com/selfcustody/krux/releases/tag/v23.09.0

unzip -l ~/Downloads/krux-v23.09.0.zip
...
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2023-09-12 22:17   krux-v23.09.0/
 14691000  2023-09-12 22:14   krux-v23.09.0/ktool-linux
  6314320  2023-09-12 22:14   krux-v23.09.0/ktool-mac
  6313696  2023-09-12 22:14   krux-v23.09.0/ktool-mac-10
  6843031  2023-09-12 22:14   krux-v23.09.0/ktool-win.exe
        0  2023-09-12 22:21   krux-v23.09.0/maixpy_m5stickv/
  1897920  2023-09-12 22:14   krux-v23.09.0/maixpy_m5stickv/firmware.bin
   935564  2023-09-12 22:14   krux-v23.09.0/maixpy_m5stickv/kboot.kfpkg
       70  2023-09-12 22:23   krux-v23.09.0/maixpy_m5stickv/firmware.bin.sig
        0  2023-09-12 22:23   krux-v23.09.0/maixpy_amigo_ips/
  1902592  2023-09-12 22:15   krux-v23.09.0/maixpy_amigo_ips/firmware.bin
   935735  2023-09-12 22:15   krux-v23.09.0/maixpy_amigo_ips/kboot.kfpkg
       70  2023-09-12 22:23   krux-v23.09.0/maixpy_amigo_ips/firmware.bin.sig
        0  2023-09-12 22:24   krux-v23.09.0/maixpy_amigo_tft/
  1902592  2023-09-12 22:16   krux-v23.09.0/maixpy_amigo_tft/firmware.bin
   935729  2023-09-12 22:16   krux-v23.09.0/maixpy_amigo_tft/kboot.kfpkg
       70  2023-09-12 22:24   krux-v23.09.0/maixpy_amigo_tft/firmware.bin.sig
        0  2023-09-12 22:24   krux-v23.09.0/maixpy_bit/
  1890816  2023-09-12 22:17   krux-v23.09.0/maixpy_bit/firmware.bin
   933632  2023-09-12 22:17   krux-v23.09.0/maixpy_bit/kboot.kfpkg
       70  2023-09-12 22:24   krux-v23.09.0/maixpy_bit/firmware.bin.sig
        0  2023-09-12 22:24   krux-v23.09.0/maixpy_dock/
  1890816  2023-09-12 22:17   krux-v23.09.0/maixpy_dock/firmware.bin
   933619  2023-09-12 22:17   krux-v23.09.0/maixpy_dock/kboot.kfpkg
       70  2023-09-12 22:24   krux-v23.09.0/maixpy_dock/firmware.bin.sig
---------                     -------
 48321412                     25 files

Inflated firmware.bin and firmware.bin.sig, and got sha256 hashes for those binaries.

unzip -e ~/Downloads/krux-v23.09.0.zip krux-v23.09.0/maixpy_amigo_tft/firmware.bin
unzip -e ~/Downloads/krux-v23.09.0.zip krux-v23.09.0/maixpy_amigo_tft/firmware.bin.sig

sha256sum krux-v23.09.0/maixpy_amigo_tft/*
2da65b95435eff19a10fb0d88479bd7a7a86134577a972ab9012790dcac7e3c9  krux-v23.09.0/maixpy_amigo_tft/firmware.bin
4c51d4cc2facffb2e59db08266396095a30cd66108262b723ac1ba13759928cf  krux-v23.09.0/maixpy_amigo_tft/firmware.bin.sig

and put both files in root directory of a vfat microsd card.

Booting amigo with microsd card, confirmed new firmware w/ correct hash.

upgrading firmware
backing up bootloader
updating bootloader
shutting down.

Removed sdcard, held power for 6 seconds, powered back on, now krux shows version 23.09.0.


Back in the usb console to analyze_spi_flash after upgrading from v22.08.2 to v23.9.0

>>> analyze_spi_flash()

Checking "Kboot stage-0" from 0x0 to 0x1000-1
SPI flash from 0x0 to 0x1000-1 is valid.
sha256 hash of "bootloader_lo.bin" having 608 bytes is:
2e050a92efdcb172cb5c6f7cb0b669ba654d2d20219f810fd9fc543f7ef05c3e

Checking "Kboot stage-1" from 0x1000 to 0x4000-1
SPI flash from 0x1000 to 0x3000-1 is valid.
sha256 hash of "bootloader_hi.bin" having 8112 bytes is:
f005f7c8b13aa2719cad58492a8432f14b68b2f845b58e5b5e81ed6309be6172
SPI flash from 0x3000 to 0x4000-1 is all 0xff.

Checking "main config" from 0x4000 to 0x5000-1
sha256 hash of "config.bin" having 4096 bytes is:
7d454bbe28244529f4bca414883a208b60f860b00cdaf8ab50bc4fafa038819c

Checking "backup config" from 0x5000 to 0x6000-1
sha256 hash of SPI flash from 0x5000 to 0x6000-1 is:
c9b9c4adcabe9c353a907f44c101c3b29756b30762e4b282d87d2a92400e2198

Checking "reserved" from 0x6000 to 0x10000-1
SPI flash from 0x6000 to 0x10000-1 is all 0xff.

Checking "unused app/user" from 0x10000 to 0x80000-1
SPI flash from 0x10000 to 0x80000-1 is all 0xff.

Checking "firmware_slot1" from 0x80000 to 0x230000-1
SPI flash from 0x80000 to 0x230000-1 is valid.
sha256 hash of "firmware.bin" having 1716288 bytes is:
5067429beb16bd0eac55401ea673f55f9cc97585b1a0607d64f8e5f486d4988b

Checking "unused app/user" from 0x230000 to 0x280000-1
SPI flash from 0x230000 to 0x280000-1 is all 0xff.

Checking "firmware_slot2" from 0x280000 to 0x460000-1
SPI flash from 0x280000 to 0x460000-1 is valid.
sha256 hash of "firmware.bin" having 1902592 bytes is:
2da65b95435eff19a10fb0d88479bd7a7a86134577a972ab9012790dcac7e3c9

Checking "unused app/user" from 0x460000 to 0xd00000-1
SPI flash from 0x460000 to 0xd00000-1 is all 0xff.

Checking "SPI Flash Filing System" from 0xd00000 to 0x1000000-1
sha256 hash of "SPI Flash Filing System" having 3145728 bytes is:
eb438b1b25cdc59e90c28072c88910e913fc4b36abf165025055f0202d6fed55

Checking "SPI flash" from 0x0 to 0x1000000-1
sha256 hash of "16MB SPI flash" having 16777216 bytes is:
73283f944f73b980120e3684daa756f73dc94696bff24c71c18bb6ac3a846fb5

Summary of what changed:

  • kboot stage0 is unchanged
  • kboot stage1 is unchanged
  • main config has changed
  • backup config is unchanged, but only because it got backed-up from main config during the upgrade.
  • v22.08.2 firmware is still in slot1
  • v23.09.0 firmware is now in slot2
  • SPIFFS has changed but I never took a look originally. It's expected with any new settings.

Hex dumping the main config which changed, and the backup config which has the original.

>>> hd = HexDumpSPIFlash(0x4000, lines=45, width=32)
>>> hd.run()

004000  5a a5 d0 cd  00 28 00 00  00 1d 08 00  24 c6 ab aa  66 69 72 6d  77 61 72 65  00 00 00 00  00 00 00 00  |Z....(......$...firmware........|
004020  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
... 6 squeezed
004100  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
004120  5a a5 d0 cf  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |Z...............................|
004140  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
... 116 squeezed
004fe0  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
005000  5a a5 d0 c5  00 08 00 00  00 1a a0 00  24 c6 ab aa  66 69 72 6d  77 61 72 65  00 00 00 00  00 00 00 00  |Z...........$...firmware........|
005020  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
... 6 squeezed
005100  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
005120  5a a5 d0 cf  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |Z...............................|
005140  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
... 116 squeezed
005fe0  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|

Main config starts at 0x4000. Backup config starts at 0x5000

Docs are https://github.com/loboris/Kboot/blob/master/Kboot.md

Each config entry is 32 bytes, an entire line above, and kboot supports 8 entries.

The first 4 bytes always start like "0x5aa5d0c*" and the last nible is a 4 bit mask called "Entry flags", they are

  • 0001 = This is the ACTIVE flag, if set, this is the active configuration to use.
  • 0010 = this is the CRC32 flag, if set, the app's calculated CRC32 value must match the configuration's CRC32 value.
  • 0100 = This is the AES256 flag, if set, the app's calculated AES256 value must match after the application sha256 hash.
  • 1000 = this is the SIZE flag, if set, the app's size must match the configuration's size value.

We can see that main configuration has Entry flags of "D"=1101 (Check SIZE, Check AES256, Ignore CRC32, Is ACTIVE) We can see its backup configuration had Entry flags of "5"=0101 (Ignore SIZE, Check AES256, Ignore CRC32, Is ACTIVE)

The next 4 bytes, as a big-endian int, are the location of the application in SPI Flash. We can see that it was at 0x80000 in the backup config and that it is now at 0x280000 in main config.

The next 4 bytes, as a big-endian int, are the application size. We can see that the backup config indicates the application size was 1744896 when up above we see that it was really 1716288, but because the configuration entry flag was "5"=0101, the highest SIZE flag was not set and there were no problems. In the new configuration which uses "D"=1101, the highest SIZE flag is set and we have a matching size in configuration of 1902592 in slot 2.

The next 4 bytes are the application's CRC32 value, in both cases above they are 0x24 0xc6 0xab 0xaa bytes, but according to the configuration, they're not used and I don't know what they mean, just that they came from config.bin within the kboot.kfpkg archive.

The next 16 bytes are the application name or description, in our case, it's "firmware" follwed by 8 null bytes.


Hex dumping the SPI Flash File System

>>> hd = HexDumpSPIFlash(0xd00000, lines=45, width=32)
>>> hd.run()

d00000  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  01 80 01 00  ff ff ff ff  ff ff ff ff  |................................|
d00020  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 124 squeezed
d00fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d00fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  31 15 00 00  |............................1...|
d01000  01 80 00 00  7e 00 00 00  2f 00 00 00  01 2f 73 65  74 74 69 6e  67 73 2e 6a  73 6f 6e 00  00 00 00 00  |....~.../..../settings.json.....|
d01020  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
... 1 squeezed
d01060  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
d01080  00 00 00 00  00 00 00 00  00 00 00 00  00 00 02 00  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d010a0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 121 squeezed
d01fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d02000  01 00 00 00  7e 7b 22 73  65 74 74 69  6e 67 73 22  3a 20 7b 22  61 70 70 65  61 72 61 6e  63 65 22 3a  |....~{"settings": {"appearance":|
d02020  20 7b 22 74  68 65 6d 65  22 3a 20 22  44 61 72 6b  22 7d 7d 7d  ff ff ff ff  ff ff ff ff  ff ff ff ff  | {"theme": "Dark"}}}............|
d02040  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 124 squeezed
d02fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d03000  01 80 00 00  7e 00 00 00  51 00 00 00  01 2f 73 65  74 74 69 6e  67 73 2e 6a  73 6f 6e 00  00 00 00 00  |....~...Q..../settings.json.....|
d03020  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
... 1 squeezed
d03060  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
d03080  00 00 00 00  00 00 00 00  00 00 00 00  00 00 04 00  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d030a0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 121 squeezed
d03fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d04000  01 00 00 00  7e 7b 22 73  65 74 74 69  6e 67 73 22  3a 20 7b 22  74 6f 75 63  68 73 63 72  65 65 6e 22  |....~{"settings": {"touchscreen"|
d04020  3a 20 7b 22  74 68 72 65  73 68 6f 6c  64 22 3a 20  32 32 7d 2c  20 22 61 70  70 65 61 72  61 6e 63 65  |: {"threshold": 22}, "appearance|
d04040  22 3a 20 7b  22 74 68 65  6d 65 22 3a  20 22 44 61  72 6b 22 7d  7d 7d ff ff  ff ff ff ff  ff ff ff ff  |": {"theme": "Dark"}}}..........|
d04060  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 123 squeezed
d04fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d05000  01 80 00 00  7e 00 00 00  7b 00 00 00  01 2f 73 65  74 74 69 6e  67 73 2e 6a  73 6f 6e 00  00 00 00 00  |....~...{..../settings.json.....|
d05020  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
... 1 squeezed
d05060  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
d05080  00 00 00 00  00 00 00 00  00 00 00 00  00 00 06 00  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d050a0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 121 squeezed
d05fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d06000  01 00 00 00  7e 7b 22 73  65 74 74 69  6e 67 73 22  3a 20 7b 22  61 70 70 65  61 72 61 6e  63 65 22 3a  |....~{"settings": {"appearance":|
d06020  20 7b 22 74  68 65 6d 65  22 3a 20 22  44 61 72 6b  22 7d 2c 20  22 6c 6f 67  22 3a 20 7b  22 70 61 74  | {"theme": "Dark"}, "log": {"pat|
d06040  68 22 3a 20  22 2f 73 64  2f 2e 6b 72  75 78 2e 6c  6f 67 22 2c  20 22 6c 65  76 65 6c 22  3a 20 39 39  |h": "/sd/.krux.log", "level": 99|
d06060  7d 2c 20 22  69 31 38 6e  22 3a 20 7b  22 6c 6f 63  61 6c 65 22  3a 20 22 65  6e 2d 55 53  22 7d 7d 7d  |}, "i18n": {"locale": "en-US"}}}|
d06080  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d060a0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 121 squeezed
d06fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d07000  01 80 00 00  7e 00 00 00  9d 00 00 00  01 2f 73 65  74 74 69 6e  67 73 2e 6a  73 6f 6e 00  00 00 00 00  |....~......../settings.json.....|
d07020  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
... 1 squeezed
d07060  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
d07080  00 00 00 00  00 00 00 00  00 00 00 00  00 00 08 00  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d070a0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 121 squeezed
d07fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d08000  01 00 00 00  7e 7b 22 73  65 74 74 69  6e 67 73 22  3a 20 7b 22  61 70 70 65  61 72 61 6e  63 65 22 3a  |....~{"settings": {"appearance":|
d08020  20 7b 22 74  68 65 6d 65  22 3a 20 22  44 61 72 6b  22 7d 2c 20  22 6c 6f 67  22 3a 20 7b  22 70 61 74  | {"theme": "Dark"}, "log": {"pat|
d08040  68 22 3a 20  22 2f 73 64  2f 2e 6b 72  75 78 2e 6c  6f 67 22 2c  20 22 6c 65  76 65 6c 22  3a 20 39 39  |h": "/sd/.krux.log", "level": 99|
d08060  7d 2c 20 22  74 6f 75 63  68 73 63 72  65 65 6e 22  3a 20 7b 22  74 68 72 65  73 68 6f 6c  64 22 3a 20  |}, "touchscreen": {"threshold": |
d08080  32 32 7d 2c  20 22 69 31  38 6e 22 3a  20 7b 22 6c  6f 63 61 6c  65 22 3a 20  22 65 6e 2d  55 53 22 7d  |22}, "i18n": {"locale": "en-US"}|
d080a0  7d 7d ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |}}..............................|
d080c0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 120 squeezed
d08fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d09000  01 80 00 00  7e 00 00 00  bb 00 00 00  01 2f 73 65  74 74 69 6e  67 73 2e 6a  73 6f 6e 00  00 00 00 00  |....~......../settings.json.....|
d09020  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
... 1 squeezed
d09060  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
d09080  00 00 00 00  00 00 00 00  00 00 00 00  00 00 0a 00  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d090a0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 121 squeezed
d09fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d0a000  01 00 00 00  7e 7b 22 73  65 74 74 69  6e 67 73 22  3a 20 7b 22  6c 6f 67 67  69 6e 67 22  3a 20 7b 22  |....~{"settings": {"logging": {"|
d0a020  6c 65 76 65  6c 22 3a 20  22 4e 4f 4e  45 22 7d 2c  20 22 74 6f  75 63 68 73  63 72 65 65  6e 22 3a 20  |level": "NONE"}, "touchscreen": |
d0a040  7b 22 74 68  72 65 73 68  6f 6c 64 22  3a 20 32 32  7d 2c 20 22  61 70 70 65  61 72 61 6e  63 65 22 3a  |{"threshold": 22}, "appearance":|
d0a060  20 7b 22 74  68 65 6d 65  22 3a 20 22  44 61 72 6b  22 7d 2c 20  22 6c 6f 67  22 3a 20 7b  22 70 61 74  | {"theme": "Dark"}, "log": {"pat|
d0a080  68 22 3a 20  22 2f 73 64  2f 2e 6b 72  75 78 2e 6c  6f 67 22 2c  20 22 6c 65  76 65 6c 22  3a 20 39 39  |h": "/sd/.krux.log", "level": 99|
d0a0a0  7d 2c 20 22  69 31 38 6e  22 3a 20 7b  22 6c 6f 63  61 6c 65 22  3a 20 22 65  6e 2d 55 53  22 7d 7d 7d  |}, "i18n": {"locale": "en-US"}}}|
d0a0c0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 120 squeezed
d0afe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d0b000  01 80 00 00  f8 00 00 00  db 00 00 00  01 2f 73 65  74 74 69 6e  67 73 2e 6a  73 6f 6e 00  00 00 00 00  |............./settings.json.....|
d0b020  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
... 1 squeezed
d0b060  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  |................................|
d0b080  00 00 00 00  00 00 00 00  00 00 00 00  00 00 0c 00  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d0b0a0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 121 squeezed
d0bfe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d0c000  01 00 00 00  fc 7b 22 73  65 74 74 69  6e 67 73 22  3a 20 7b 22  6c 6f 67 67  69 6e 67 22  3a 20 7b 22  |.....{"settings": {"logging": {"|
d0c020  6c 65 76 65  6c 22 3a 20  22 4e 4f 4e  45 22 7d 2c  20 22 62 69  74 63 6f 69  6e 22 3a 20  7b 22 6e 65  |level": "NONE"}, "bitcoin": {"ne|
d0c040  74 77 6f 72  6b 22 3a 20  22 6d 61 69  6e 22 7d 2c  20 22 74 6f  75 63 68 73  63 72 65 65  6e 22 3a 20  |twork": "main"}, "touchscreen": |
d0c060  7b 22 74 68  72 65 73 68  6f 6c 64 22  3a 20 32 32  7d 2c 20 22  61 70 70 65  61 72 61 6e  63 65 22 3a  |{"threshold": 22}, "appearance":|
d0c080  20 7b 22 74  68 65 6d 65  22 3a 20 22  44 61 72 6b  22 7d 2c 20  22 6c 6f 67  22 3a 20 7b  22 70 61 74  | {"theme": "Dark"}, "log": {"pat|
d0c0a0  68 22 3a 20  22 2f 73 64  2f 2e 6b 72  75 78 2e 6c  6f 67 22 2c  20 22 6c 65  76 65 6c 22  3a 20 39 39  |h": "/sd/.krux.log", "level": 99|
d0c0c0  7d 2c 20 22  69 31 38 6e  22 3a 20 7b  22 6c 6f 63  61 6c 65 22  3a 20 22 65  6e 2d 55 53  22 7d 7d 7d  |}, "i18n": {"locale": "en-US"}}}|
d0c0e0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 2678 squeezed
d20fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d20fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  3e 15 00 00  |............................>...|
d21000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
d40fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d40fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  3f 15 00 00  |............................?...|
d41000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
d60fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d60fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  3c 15 00 00  |............................<...|
d61000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
d80fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
d80fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  3d 15 00 00  |............................=...|
d81000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
da0fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
da0fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  3a 15 00 00  |............................:...|
da1000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
dc0fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
dc0fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  3b 15 00 00  |............................;...|
dc1000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
de0fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
de0fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  38 15 00 00  |............................8...|
de1000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
e00fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
e00fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  39 15 00 00  |............................9...|
e01000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
e20fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
e20fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  26 15 00 00  |............................&...|
e21000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
e40fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
e40fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  27 15 00 00  |............................'...|
e41000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
e60fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
e60fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  24 15 00 00  |............................$...|
e61000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
e80fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
e80fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  25 15 00 00  |............................%...|
e81000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
ea0fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
ea0fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  22 15 00 00  |............................"...|
ea1000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
ec0fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
ec0fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  23 15 00 00  |............................#...|
ec1000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
ee0fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
ee0fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  20 15 00 00  |............................ ...|
ee1000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
f00fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
f00fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  21 15 00 00  |............................!...|
f01000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
f20fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
f20fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  2e 15 00 00  |................................|
f21000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
f40fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
f40fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  2f 15 00 00  |............................/...|
f41000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
f60fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
f60fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  2c 15 00 00  |............................,...|
f61000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
f80fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
f80fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  2d 15 00 00  |............................-...|
f81000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
fa0fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
fa0fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  2a 15 00 00  |............................*...|
fa1000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
fa1020  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4092 squeezed
fc0fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
fc0fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  2b 15 00 00  |............................+...|
fc1000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 4093 squeezed
fe0fc0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
fe0fe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  28 15 00 00  |............................(...|
fe1000  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|
... 3966 squeezed
ffffe0  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  |................................|

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment