Using ktool.py from a docker build of krux ./firmware/Kboot/build/ktool.py
to access flash on amigo.
See the loboris Kboot readme
~/krux$ python3 ./firmware/Kboot/build/ktool.py -B goE -E
...
[INFO] SPI Flash erased.
The amigo no longer shows any sign of life on its screen, but it's not quite a "brick". When pressing the power-button for 6 seconds, I assume it shuts down, because another 1 second press then blinks the white-LED as if powered on again, but it never appears to boot.
Can connect to serial console via /dev/ttyUSB1. After hitting the soft-reset button on amigo, output is:
interesting, something's wrong, boot failed with exit code 233, go to find your vendor.
We'll read from flash and save a flash_dump in /tmp:
~/krux$ python3 ./firmware/Kboot/build/ktool.py -B goE -R -a 0x0 -L 16777216 /tmp/k210.flash_dump
...
[INFO] Read 16777216 Bytes from Flash address 0x0
Read Flash: |=============================================| 100.0% 11kiB/s
[INFO] Read 16777216 Bytes in 1470.181s
What does "SPI Flash erased" really look like?
~/krux$ du -b /tmp/k210.flash_dump
16777216 /tmp/k210.flash_dump
~/krux$ hd /tmp/k210.flash_dump
00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
01000000
It looks like an erased flash, from beginning to end, is nothing but 1
s
~/krux$ git log | head -3
commit 1752f422a136479879285cad47238db07307494e
Author: Odudex <[email protected]>
Date: Tue Jul 4 17:10:44 2023 -0300
note: a previous version of this doc listed the wrong commit that was "head" while building binaries.
~/krux$ du -b ./build/*
1912576 ./build/firmware.bin
936687 ./build/kboot.kfpkg
~/krux$ sha256sum ./build/*
f234f6b1b517af8b988980c395f482cf535d07c67ef978ca3cc175bd07aa54e8 ./build/firmware.bin
2a1c5c7a19e12cc6d7db0d11febf68237a891f09ae5dbb347dcb538e40be7417 ./build/kboot.kfpkg
Note: the smaller kboot.kfpkg is a compressed archive, we'll refer to its contents later.
~/krux$ unzip -l ./build/kboot.kfpkg
Archive: ./build/kboot.kfpkg
Length Date Time Name
--------- ---------- ----- ----
647 2023-07-04 18:12 flash-list.json
608 2023-07-04 18:12 bootloader_lo.bin
8112 2023-07-04 18:12 bootloader_hi.bin
4096 2023-06-13 10:01 config.bin
1912576 2023-07-04 18:12 firmware.bin
--------- -------
1926039 5 files
~/krux$ python3 ./firmware/Kboot/build/ktool.py -B goE ./build/kboot.kfpkg
...
[INFO] Extracting KFPKG ...
[INFO] Writing bootloader_lo.bin to Flash address 0x00000000
[INFO] Flashing firmware block with SHA suffix
Programming BIN: |=============================================| 100.0%
[INFO] Flashed 645 B [1 chunks of 4096B] (00000000~00000FFF) in 0.420s
[INFO] Writing bootloader_hi.bin to Flash address 0x00001000
[INFO] Flashing firmware block with SHA suffix
Programming BIN: |=============================================| 100.0%
[INFO] Flashed 8149 B [2 chunks of 4096B] (00001000~00002FFF) in 0.848s
[INFO] Writing config.bin to Flash address 0x00004000
Programming DATA: |=============================================| 100.0%
[INFO] Flashed 4096 B [1 chunks of 4096B] (00004000~00004FFF) in 0.414s
[INFO] Writing config.bin to Flash address 0x00005000
Programming DATA: |=============================================| 100.0%
[INFO] Flashed 4096 B [1 chunks of 4096B] (00005000~00005FFF) in 0.411s
[INFO] Writing firmware.bin to Flash address 0x00080000
[INFO] Flashing firmware block with SHA suffix
Programming BIN: |=============================================| 100.0% 10kiB/s
[INFO] Flashed 1912613 B [30 chunks of 65536B] (00080000~0025FFFF) in 183.011s
[INFO] Rebooting...
The amigo boots krux as expected.
This time we'll read individual flash sectors w/ krux freshly installed, booted once, unused.
Commands to do so are below, w/o any of their output:
~/krux$ python3 ./firmware/Kboot/build/ktool.py -B goE -R -a 0x0 -L 4096 /tmp/k210.0_Kboot
~/krux$ python3 ./firmware/Kboot/build/ktool.py -B goE -R -a 0x1000 -L 12288 /tmp/k210.1_Kboot
~/krux$ python3 ./firmware/Kboot/build/ktool.py -B goE -R -a 0x4000 -L 4096 /tmp/k210.2_main
~/krux$ python3 ./firmware/Kboot/build/ktool.py -B goE -R -a 0x5000 -L 4096 /tmp/k210.3_backup
~/krux$ python3 ./firmware/Kboot/build/ktool.py -B goE -R -a 0x6000 -L 40960 /tmp/k210.4_reserved
~/krux$ python3 ./firmware/Kboot/build/ktool.py -B goE -R -a 0x10000 -L 16711680 /tmp/k210.5_app_user
The flash file-dump sizes are as expected. Individual sector dumps sum to the same size as the full flash dump.
~/krux$ du -b /tmp/k210.*
4096 /tmp/k210.0_Kboot
12288 /tmp/k210.1_Kboot
4096 /tmp/k210.2_main
4096 /tmp/k210.3_backup
40960 /tmp/k210.4_reserved
16711680 /tmp/k210.5_app_user
16777216 /tmp/k210.flash_dump
~/krux$ python3 -c 'print(4096+12288+4096+4096+40960+16711680)'
16777216
These might be useful to know if something that shouldn't change, thru usage, does change later.
~/krux$ sha256sum /tmp/k210.[0-5]*
33ea1b4fdd86330dfac92f5147451c5315d308517e1e8a6b9d3c89d437b9721a /tmp/k210.0_Kboot
c4d1e8bae5f524d759995820ce487612c20d9ad7a13ccdf35fdde8b9900a3d51 /tmp/k210.1_Kboot
c9b9c4adcabe9c353a907f44c101c3b29756b30762e4b282d87d2a92400e2198 /tmp/k210.2_main
c9b9c4adcabe9c353a907f44c101c3b29756b30762e4b282d87d2a92400e2198 /tmp/k210.3_backup
5acd2700bacfed75f41c8f0df2dd7e9f11b3a214677ce2ef525a369c151e60da /tmp/k210.4_reserved
35b3972c990f90870e17681e6b5a4c8ca7ca57e88d879abb05f677f9c69c8837 /tmp/k210.5_app_user
This is Kboot app stage0, 4096 bytes starting at 0x0 in flash
This contains bootloader_lo.bin from ./build/kboot.kfpkg.
~/krux$ unzip -p ./build/kboot.kfpkg bootloader_lo.bin | hd | head -3
00000000 6f 00 40 00 f3 27 40 f1 81 27 17 07 00 00 23 27 |o.@..'@..'....#'|
00000010 f7 20 95 cb 97 07 00 00 93 87 07 20 98 43 85 46 |. ......... .C.F|
00000020 17 06 00 00 23 28 d6 1e 01 e7 01 00 98 43 75 df |....#(.......Cu.|
~/krux$ hd /tmp/k210.0_Kboot | head -3
00000000 00 60 02 00 00 6f 00 40 00 f3 27 40 f1 81 27 17 |.`...o.@..'@..'.|
00000010 07 00 00 23 27 f7 20 95 cb 97 07 00 00 93 87 07 |...#'. .........|
00000020 20 98 43 85 46 17 06 00 00 23 28 d6 1e 01 e7 01 | .C.F....#(.....|
It looks like bootloader_lo.bin in flash, with an offset because of a 5 byte header.
See https://github.com/loboris/ktool/blob/0345aa90d9b3830641373fb4e3ce4edf45d0a46f/ktool.py#L1161 Format is header + content + footer where header=AES byte + 4byte little endian size of content, and footer is sha256(header+content). ie: 0x00000260=608
Previously, we saw that bootloader_lo.bin is only 608 bytes while the flash dump sector is 4096. Let's be sure that bootloader_lo.bin is really there.
~/krux$ unzip -p ./build/kboot.kfpkg bootloader_lo.bin | sha256sum
2e050a92efdcb172cb5c6f7cb0b669ba654d2d20219f810fd9fc543f7ef05c3e -
~/krux$ tail -c +6 /tmp/k210.0_Kboot | head -c 608 | sha256sum
2e050a92efdcb172cb5c6f7cb0b669ba654d2d20219f810fd9fc543f7ef05c3e -
The rest of this flash sector is the 32 byte sha256 hash of all 613 bytes -- including the 5 byte header, followed by 0x00 bytes to fill the sector.
~/krux$ head -c 613 /tmp/k210.0_Kboot | sha256sum
4d1c6cf53b7b2fea3ea86c327753c745636b3b3db33473cf63faa30b443a3cb6 -
~/krux$ tail -c +614 /tmp/k210.0_Kboot | hd
00000000 4d 1c 6c f5 3b 7b 2f ea 3e a8 6c 32 77 53 c7 45 |M.l.;{/.>.l2wS.E|
00000010 63 6b 3b 3d b3 34 73 cf 63 fa a3 0b 44 3a 3c b6 |ck;=.4s.c...D:<.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000d90 00 00 00 00 00 00 00 00 00 00 00 |...........|
00000d9b
This is Kboot app stage1, 12288 bytes starting at 0x1000 in flash
This contains bootloader_hi.bin from ./build/kboot.kfpkg w/ a 5 byte header and 32 byte hash footer (described above), followed by some 0x00 bytes to fill a 4096 block and an untouched 4096 block of 0xff bytes from our flash erase.
~/krux$ head -c 5 /tmp/k210.1_Kboot | hd
00000000 00 b0 1f 00 00 |.....|
00000005
~/krux$ python3 -c 'print(0x00001fb0)'
8112
~/krux$ tail -c +6 /tmp/k210.1_Kboot | head -c 8112 | sha256sum
f005f7c8b13aa2719cad58492a8432f14b68b2f845b58e5b5e81ed6309be6172 -
~/krux$ unzip -p ./build/kboot.kfpkg bootloader_hi.bin | sha256sum
f005f7c8b13aa2719cad58492a8432f14b68b2f845b58e5b5e81ed6309be6172 -
~/krux$ head -c 8117 /tmp/k210.1_Kboot | sha256sum
a0b2872077b62b18ac88e4f42ea74b6e26146e8b3d70811d5f56cc0c1f77c753 -
~/krux$ tail -c +8118 /tmp/k210.1_Kboot | hd
00000000 a0 b2 87 20 77 b6 2b 18 ac 88 e4 f4 2e a7 4b 6e |... w.+.......Kn|
00000010 26 14 6e 8b 3d 70 81 1d 5f 56 cc 0c 1f 77 c7 53 |&.n.=p.._V...w.S|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000040 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff |................|
00000050 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00001040 ff ff ff ff ff ff ff ff ff ff ff |...........|
0000104b
This is main boot configuration, 4096 bytes starting at 0x4000 in flash
~/krux$ hd /tmp/k210.2_main
00000000 5a a5 d0 c5 00 08 00 00 00 1a a0 00 24 c6 ab aa |Z...........$...|
00000010 66 69 72 6d 77 61 72 65 00 00 00 00 00 00 00 00 |firmware........|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000120 5a a5 d0 cf 00 00 00 00 00 00 00 00 00 00 00 00 |Z...............|
00000130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001000
This is backup boot configuration, 4096 bytes starting at 0x5000 in flash
It is identical to the main boot configuration above. Both are ./firmware/Kboot/build/config.bin, also contained in the kboot.kfpkg archive:
~/krux$ sha256sum /tmp/k210.[23]* ./firmware/Kboot/build/config.bin
c9b9c4adcabe9c353a907f44c101c3b29756b30762e4b282d87d2a92400e2198 /tmp/k210.2_main
c9b9c4adcabe9c353a907f44c101c3b29756b30762e4b282d87d2a92400e2198 /tmp/k210.3_backup
c9b9c4adcabe9c353a907f44c101c3b29756b30762e4b282d87d2a92400e2198 ./firmware/Kboot/build/config.bin
~/krux$ unzip -p ./build/kboot.kfpkg config.bin | sha256sum
c9b9c4adcabe9c353a907f44c101c3b29756b30762e4b282d87d2a92400e2198 -
This is a reserved / user data sector???
This is unchanged since flash was erased above.
~/krux$ hd /tmp/k210.4_reserved
00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
0000a000
This is default app and user data, 16711680 bytes starting at 0x10000 in flash
Logs seen while flashing krux firmware indicate that this really starts at 0x80000 so we'll expect an offset of 0x70000 in the dumped file.
~/krux$ hd /tmp/k210.5_app_user | head -5
00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00070000 00 00 2f 1d 00 21 a8 ef be ad de 01 00 01 00 00 |../..!..........|
00070010 00 00 00 00 00 00 00 00 00 00 00 00 00 73 50 30 |.............sP0|
00070020 30 73 50 20 30 73 50 40 30 73 50 40 34 97 02 00 |0sP 0sP@0sP@4...|
The first 0x70000 bytes are indeed unchanged from when flash was originally erased.
~/krux$ hd ./build/firmware.bin | head -3
00000000 21 a8 ef be ad de 01 00 01 00 00 00 00 00 00 00 |!...............|
00000010 00 00 00 00 00 00 00 00 73 50 30 30 73 50 20 30 |........sP00sP 0|
00000020 73 50 40 30 73 50 40 34 97 02 00 00 93 82 82 0f |sP@0sP@4........|
So it looks like our dump has a 5 byte header, but then we see what looks like firmware.bin
See https://github.com/loboris/ktool/blob/0345aa90d9b3830641373fb4e3ce4edf45d0a46f/ktool.py#L1161 Format is header + content + footer where header=AES byte + 4byte little endian size of content, and footer is sha256(header+content). ie: 0x001d2f00=1912576
We also learned that the length of the firmware write was 1912613 bytes long, exactly 37 bytes larger than ./build/firmware.bin because of the 5 byte header and 32 byte hash footer.
Is this really the firmware that we expect?
Some math for the flash dump offset: known offset of 0x70000 + 5 = 458757 to be skipped, and for the length, because the firmware is 1912576 bytes:
~/krux$ tail -c +458758 /tmp/k210.5_app_user | head -c 1912576 | sha256sum
f234f6b1b517af8b988980c395f482cf535d07c67ef978ca3cc175bd07aa54e8 -
~/krux$ sha256sum ./build/firmware.bin
f234f6b1b517af8b988980c395f482cf535d07c67ef978ca3cc175bd07aa54e8 ./build/firmware.bin
Yes, it is indeed ./build/firmware.bin
Immediately following the firmware is the 32 byte sha256 hash of all 1912581 bytes of firmware -- including prefixed 5 byte header, then 0x00 bytes to fill the block.
TODO explain the spurious bytes other than the expected 0xff values from the flash erase. I have a theory, that this is "filesystem" space. I now believe that I had an sdcard inserted when I originally did this analysis (but I could be mistaken). Since then, I've found settings.json in this space when re-running the same analysis, but I have yet to find any "secrets" or even unexplained bytes, which was the primary goal of this excercise... I'll certainly keep watching for that.
~/krux$ tail -c +458753 /tmp/k210.5_app_user | head -c 1912581 | sha256sum
9cd40f850a46b4537b4c49a847fa03d2fbf3fd03741ebe73dfe5093fb4463990 -
~/krux$ tail -c +2371334 /tmp/k210.5_app_user | hd
00000000 9c d4 0f 85 0a 46 b4 53 7b 4c 49 a8 47 fa 03 d2 |.....F.S{LI.G...|
00000010 fb f3 fd 03 74 1e be 73 df e5 09 3f b4 46 39 90 |....t..s...?.F9.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
0000d0f0 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff |................|
0000d100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00aae0f0 ff ff ff ff ff ff ff 31 15 00 00 ff ff ff ff ff |.......1........|
00aae100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00ace0f0 ff ff ff ff ff ff ff 3e 15 00 00 ff ff ff ff ff |.......>........|
00ace100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00aee0f0 ff ff ff ff ff ff ff 3f 15 00 00 ff ff ff ff ff |.......?........|
00aee100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00b0e0f0 ff ff ff ff ff ff ff 3c 15 00 00 ff ff ff ff ff |.......<........|
00b0e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00b2e0f0 ff ff ff ff ff ff ff 3d 15 00 00 ff ff ff ff ff |.......=........|
00b2e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00b4e0f0 ff ff ff ff ff ff ff 3a 15 00 00 ff ff ff ff ff |.......:........|
00b4e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00b6e0f0 ff ff ff ff ff ff ff 3b 15 00 00 ff ff ff ff ff |.......;........|
00b6e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00b8e0f0 ff ff ff ff ff ff ff 38 15 00 00 ff ff ff ff ff |.......8........|
00b8e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00bae0f0 ff ff ff ff ff ff ff 39 15 00 00 ff ff ff ff ff |.......9........|
00bae100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00bce0f0 ff ff ff ff ff ff ff 26 15 00 00 ff ff ff ff ff |.......&........|
00bce100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00bee0f0 ff ff ff ff ff ff ff 27 15 00 00 ff ff ff ff ff |.......'........|
00bee100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00c0e0f0 ff ff ff ff ff ff ff 24 15 00 00 ff ff ff ff ff |.......$........|
00c0e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00c2e0f0 ff ff ff ff ff ff ff 25 15 00 00 ff ff ff ff ff |.......%........|
00c2e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00c4e0f0 ff ff ff ff ff ff ff 22 15 00 00 ff ff ff ff ff |......."........|
00c4e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00c6e0f0 ff ff ff ff ff ff ff 23 15 00 00 ff ff ff ff ff |.......#........|
00c6e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00c8e0f0 ff ff ff ff ff ff ff 20 15 00 00 ff ff ff ff ff |....... ........|
00c8e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00cae0f0 ff ff ff ff ff ff ff 21 15 00 00 ff ff ff ff ff |.......!........|
00cae100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00cce0f0 ff ff ff ff ff ff ff 2e 15 00 00 ff ff ff ff ff |................|
00cce100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00cee0f0 ff ff ff ff ff ff ff 2f 15 00 00 ff ff ff ff ff |......./........|
00cee100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00d0e0f0 ff ff ff ff ff ff ff 2c 15 00 00 ff ff ff ff ff |.......,........|
00d0e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00d2e0f0 ff ff ff ff ff ff ff 2d 15 00 00 ff ff ff ff ff |.......-........|
00d2e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00d4e0f0 ff ff ff ff ff ff ff 2a 15 00 00 ff ff ff ff ff |.......*........|
00d4e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00d6e0f0 ff ff ff ff ff ff ff 2b 15 00 00 ff ff ff ff ff |.......+........|
00d6e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00d8e0f0 ff ff ff ff ff ff ff 28 15 00 00 ff ff ff ff ff |.......(........|
00d8e100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00dad0f0 ff ff ff ff ff ff ff ff ff ff ff |...........|
00dad0fb
And what exactly does Sipeed mean by "16MB Flash"?
Is it really 2**24
== 16777216 like has been assumed above?
If this truly were the physical limit, perhaps accessing any addresses equal to or greater than 0x1000000 would not have access to those higher address bits. If so we'd see errors, or we'd be wrapping back to the flash addresses starting at 0x0. Can we prove this by reading from any addresses that are a multiple of 16MB and find that we're really just getting copies of flash that we've already seen below 16MB?
~/krux$ python3 ./firmware/Kboot/build/ktool.py -B goE -R -a 0x4000000 -L 16777216 /tmp/k210.flash_dump
...
[INFO] Read 16777216 Bytes from Flash address 0x4000000
Read Flash: |=============================================| 100.0% 11kiB/s
[INFO] Read 16777216 Bytes in 1470.181s
~/krux$ sha256sum /tmp/k210.flash_dump
d5927418971e813890a50c0ac8492ca9a796a80ee2d47ad441eac50846cdcb85 /tmp/k210.flash_dump
~/krux$ cat /tmp/k210.[0-5]* | sha256sum
d5927418971e813890a50c0ac8492ca9a796a80ee2d47ad441eac50846cdcb85 -
It appears that any flash addresses with high-order bits beyond the 24th bit are indeed ignored. Accessing 16MB of flash as 2**24
does appear to be a physical upper limit of flash storage.