Repository navigation
openipc: a split kernel that fails its CRC goes to recovery - #56
Conversation
The scan clears bootfail once it finds the split layout, from the
uImage's magic and where the squashfs sits. A kernel whose header is
sound but whose payload is damaged then fails bootm ("Bad Data CRC",
reset), and nothing asks for recovery: fwrecovery sees no bootfail, and
the boot-limit fallback boots the same image again. The camera loops.
The split branch of firmware_scan now reads the kernel back from the
flash and checks its header and data CRC. On a mismatch it sets bootfail,
keeping everything else the scan set for the split layout, so
bootflash's fwrecovery fetches the firmware file and writes it where the
firmware starts. Without the memory for the check, the kernel is taken
as it is, and bootm still checks it. This is shared code, so it covers
every board with CONFIG_OPENIPC_NOR_SPLIT. Fixed slots are unchanged.
The check reads the uImage once more at boot, about 1.9 MiB on today's
split images.
Tested in qemu-hisilicon (gk7205v500, 8 MB, split lite firmware.bin):
- intact image: the scan passes it, bootm verifies it, root on 31:4, login;
- one byte flipped 1 MiB into the kernel payload: "Firmware is
absent/corrupt (kernel at 0x50000 fails its CRC)", fwupd fetches
firmware.bin.gk7205v500 over TFTP, erases 0x50000 to the end and
writes it (byte-identical on flash), and the next boot reaches login
on 31:4;
- the same damaged image under the current U-Boot: "Bad Data CRC", "can't
get kernel image!", reset, with no recovery;
- fixed slots: unchanged, cmdlinepart, root on 31:3.
Builds for gk7205v500, hi3516cv300 and hi3516ev300 with no new warnings.
Not run on hardware.
PR Summary by QodoRecover when a split NOR kernel fails its CRC
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo
1.
|
… buffer From review: - The check's read buffer is malloc_cache_aligned, as the scanner's is: the FMC driver reads by DMA and invalidates whole cache lines around the buffer. - nor_split_layout takes the uImage's size only from a header that passes its CRC. A damaged size field no longer makes a split image look like fixed slots, which cleared bootfail. A uImage whose header fails its CRC boots in neither layout (bootm refuses it whatever verify says), so the scan now sets bootfail for it and recovery takes over. Tested in qemu-hisilicon (gk7205v500, 8 MB): ih_size corrupted in the split kernel's header gives "Firmware is absent/corrupt (kernel header at 0x50000 fails its CRC)", then recovery over TFTP rewrites firmware.bin (byte-identical) and the next boot reaches login on 31:4. An intact split image and fixed slots boot as before. Builds for gk7205v500, hi3516cv300 and hi3516cv500 (no split support) with no new warnings.
* nor: split layout on the GK710x The GK7101, GK7101S, GK7102 and GK7102S kernels register the split NOR layout from the images themselves since OpenIPC/linux#152 (goke-gk710x), and OpenIPC/firmware#2692 ships gk7102 and gk7102s split packages. This U-Boot booted them only because it loads the kernel from 0x50000; it had no split scan, fwupd or recovery for them. - common/openipc.c as on openipc-hisilicon now: the split scan, the kernel CRC check that sends a damaged split kernel to recovery (#56), fwsize set before recovery (#62), verify dropped for recovery only, the saved-environment migrations. One change: the fallback kernel offset is OPENIPC_KERNADDR, which both branches define, rather than CONFIG_ENV_KERNADDR, an ad-hoc CONFIG_ this branch's check-config refuses (openipc-hisilicon turned that check off). - common/Kconfig: OPENIPC_NOR_SPLIT, enabled in the four gk710x configs. - openipc-common.h: with it, fwupd takes firmware.bin.<soc> when the server has one and writes it over the whole firmware area (fwwrite refuses a file that does not fit), else the fixed-slot pair as before; the legacy fwupd is this branch's "run mtdslite; run ur; run uk". OPENIPC_FW_FILE was "firmware.${soc}", never used until now and naming no file any package carries; it is now "firmware.bin." CONFIG_PRODUCT_SOC, spelled out at build time as urfile is, since U-Boot does not expand a variable inside another's value. Tested in qemu-hisilicon (gk7102, 8 MB, 64 MB RAM; the flash byte-swapped as the controller stores it) with a gk7102_lite build on the split kernel (firmware.bin 5248K): - split image: "Found Kernel at 0x00050000", "Found RootFS at 0x001b0000", the kernel's split layout, root on 31:4; a second boot reads the seed the first saved in the overlay; - fixed slots: found at 0x250000, 6 cmdlinepart partitions, root on 31:3; - fwupd over TFTP from fixed slots: firmware.bin.gk7102 fetched, the firmware area erased and written, the split layout booted; - a split kernel with one byte flipped: "fails its CRC", recovery fetches and writes firmware.bin.gk7102, the split layout booted; - after both, the flash at 0x50000 is byte-identical to firmware.bin. Built for gk7101, gk7101s, gk7102 and gk7102s; only gk7102 run. Not run on hardware. * nor: an oversized firmware file falls back to the fixed-slot pair fwupd took the firmware file whenever the download succeeded, and fwwrite then refused one larger than the firmware area and wrote nothing: recovery reset and fetched the same file again. fwupd now runs fwwrite only for a file that downloaded and fits (0 < filesize <= fwsize), and otherwise installs the fixed-slot pair, as for a missing file. qemu-hisilicon (gk7102): a 9 MB firmware.bin.gk7102 beside the pair on the server -> the pair written at 0x250000 and 0x50000, fixed slots booted (root on 31:3); a firmware.bin that fits -> written at 0x50000, the split layout booted (root on 31:4).
Follow-up to the finding on #52 ("Damaged kernels halt without recovery").
The scan clears
bootfailonce it finds the split layout, which it judges from the uImage's magic and where the squashfs sits. A kernel with a sound header but a damaged payload then failsbootm(Bad Data CRC, reset), and nothing asks for recovery.fwrecoverysees nobootfail, and the boot-limit fallback boots the same image again.The split branch of
firmware_scannow reads the kernel back from the flash and checks its header and data CRC (nor_split_kernel_ok).nor_split_layoutonly trusts the size from a header that passes its CRC, and a uImage whose header fails it getsbootfailin either layout, becausebootmrefuses it regardless ofverify. On a mismatch it setsbootfailand keeps everything else the scan set for the split layout.bootflash'sfwrecoverythen fetchesfirmware.bin.<soc>and writes it where the firmware starts. Without the memory for the check, the kernel is taken as it is, andbootmstill checks it. This is shared code incommon/openipc.c, so it covers every board withCONFIG_OPENIPC_NOR_SPLIT. Fixed slots are unchanged.Cost: the scan reads the uImage (about 1.9 MiB on today's split images) once more at boot. That was not measured on hardware.
Tested in qemu-hisilicon (gk7205v500, 8 MB, split lite
firmware.bin):bootmverifies OK, root on 31:4, loginFirmware is absent/corrupt (kernel at 0x50000 fails its CRC),fwupdfetchesfirmware.bin.gk7205v500over TFTP, erases 0x50000 to the end and writes it (byte-identical on flash), next boot reaches login on 31:4ih_sizecorrupted in the kernel headerkernel header at 0x50000 fails its CRC, the same recovery, next boot reaches login on 31:4Bad Data CRC,can't get kernel image!, reset, with no recoveryBuilds for gk7205v500, hi3516cv300, hi3516ev300 and hi3516cv500 (no split support) with no new warnings. Not run on hardware.