rockusb: read flash over USB, and reset a stale usbplug to MaskROM - #134
Conversation
The one command that had no -c/--chip, which is also the one thing
missing before any write can be attempted safely: there was no way to
back up a board whose boot ROM only answers on USB.
defib dump-flash -c rv1106 --ddr ... --usbplug ... \
--partition rootfs -o rootfs.bin
--chip is optional, so the serial path is untouched for every chip that
already worked. Given one whose profile says USB, -p is not consulted.
Capacity comes from READ_FLASH_INFO rather than a guess or a flag. On an
RV1106 that reports 255.5 MiB for a 256 MiB part — the difference being
the translation layer's own reserve — along with a 128 KiB erase block
and 2 KiB page, which match what the kernel puts in /proc/mtd on the
same board. A reply claiming zero capacity is refused: the loader is
then running but has not brought flash up, and dumping from it would
produce a convincing file full of nothing. A range running past the
reported end is refused too, since the LBA commands simply stop
answering there and a dump ending in a stall is worse than one that
declines to start.
--partition names a region from the profile instead of pulling the whole
device, which for a 255 MiB part is usually what you want. The usbplug's
LBA space maps directly onto the kernel's mtd partitions, so a partition
read this way compares byte for byte with `cat /dev/mtdN` on a booted
board.
Reads stream to disk rather than accumulating in memory.
PR Summary by QodoAdd RockUSB flash dumping for USB-only boards
AI Description
Diagram
High-Level Assessment
Files changed (6)
|
Code Review by Qodo
1.
|
A usbplug a previous process left running wedges on the next command from a fresh process, so every tool in this space re-uploads the loader each run. _open_usb_target now notices a device still in loader mode, sends it back to MaskROM (RockchipRecovery.return_to_maskrom) and re-acquires it there before uploading — so a re-run after an abandoned transfer recovers on its own instead of failing on the first command. If the loader refuses to reset it says so and points at a BOOT + replug.
|
Folded the stale-usbplug recovery in as a second commit (rather than a separate PR): |
_dump_flash_usb_async opened the destination with "wb" and streamed straight into it, so a read/write/callback failure part-way through truncated any existing backup at that path and left a partial image in its place — the worst outcome for a tool whose whole job is a safe backup. Stream to a temp file beside the destination and atomically replace it only once the transfer and close both succeed; remove the temp on every failure path.
|
Addressed the atomic-dump finding (commit bbd307a): |
What
Adds
defib dump-flashreading over the RockUSB path, so a board whose boot ROMonly answers on USB (e.g. RV1106) can be backed up — the one thing missing
before any USB write can be attempted safely.
--chipis optional; the serial path is untouched for chips that alreadyworked. For a USB-only profile,
-pisn't consulted.READ_FLASH_INFO, not a guess or flag. A reply claimingzero capacity is refused (loader up but flash not brought up → a file full of
nothing), and a range past the reported end is refused (the LBA commands just
stall there).
--partitionreads one region from the profile; the usbplug's LBA space mapsdirectly onto the kernel's mtd partitions, so it compares byte-for-byte with
cat /dev/mtdNon a booted board.Evidence
Exercised on an RV1106 (Luckfox Pico Max, 256 MB SPI-NAND) this session:
READ_FLASH_INFOreported255.5 MiB (523264 sectors), block 128 KiB, page 2048 B— the 0.5 MiB gap being the FTL reserve, and the block/page matching/proc/mtdon the same board booted. Partition reads matched byte-for-byte.Tests:
tests/test_rockusb_flashinfo.py(flash-info parse, zero-capacity andout-of-range refusal). Full suite 755 passed, 2 skipped.
Notes
Rebased onto current master (post #133). Depends on nothing outside it. A
separate return-to-MaskROM recovery enhancement (handling a stale usbplug a
prior run left running) is still WIP on my side and not included here.