Skip to content

install: the split NOR layout, and OpenIPC/u-boot for the gk7205v200 family - #154

Merged
widgetii merged 3 commits into
masterfrom
install/nor-split
Oct 17, 2026
Merged

widgetii merged 3 commits into
masterfrom
install/nor-split

Conversation

@widgetii

Copy link
Copy Markdown
Member

gk7202v300, gk7205v200, gk7205v300 and gk7605v100 now boot OpenIPC/u-boot (openipc-hisilicon), published per flash type as u-boot-<soc>-nor.bin and -nand.bin. Their firmware also ships the split NOR layout (OpenIPC/firmware#2617, #2621) as openipc.<board>-nor-<variant>-split.tgz: one firmware.bin written at 0x50000, which the kernel divides into kernel, rootfs and rootfs_data at boot (OpenIPC/linux#96).

What changes

  • U-Boot: the four SoCs join PER_FLASH_TYPE_UBOOT, so burn, install and restore fetch -nor.bin/-nand.bin. Before this they fetched the old -universal.bin from the retired u-boot-gk7205v200 repo.
  • Environment: that U-Boot works out the NOR layout at every boot and sets mtdparts and the root device itself. It has no bootcmdnor, so the env stage's setenv bootcmd ${bootcmdnor} would have left these cameras without a bootcmd. On these SoCs the env stage now loads the defaults (env default -a) and carries ethaddr and totalmem across.
    • totalmem is the DRAM size U-Boot measured. Without the saved value, Linux assumes 64 MB.
  • Split package: install recognises it by its contents.
    • The image is checked for its shape (FIT, then a squashfs at the next 64 KiB, nothing after it) and for the board it names.
    • The rootfs stage writes it at 0x50000 and erases to the end of the chip. The kernel and rootfs-data stages have nothing of their own to do.
    • The size check is the image end plus one block of overlay against the detected chip.
    • Refused: another SoC, NAND, a stock-U-Boot migration, and --wipe-rootfs-data without the rootfs stage. A plan without the uboot stage gets a warning.
  • Flash size: this U-Boot's sf probe 0 prints nothing at the prompt. Before this, the size fell back to 8 MiB, so a 16 MB board would have been laid out as 8 MB. When the probe gives no size, 16-byte sf reads just below 32, 16 and 8 MiB ask the chip: sf read refuses offsets past the end.
  • sf lock: its sf has no lock subcommand. The console's echo of sf lock 0 above the usage table was taken for a table entry, which made the unlock a hard failure. Only lines from Usage: on count now.

Tests

  • tests/test_install_nor_split.py drives run_install against a fake NOR console that keeps every byte of an 8 MiB chip. It answers sf probe/sf lock as this U-Boot does and refuses out-of-range reads. It covers the split and fixed-slot packages, the package checks and the refusals.
  • New helper tests cover the size reads and the sf lock echo. test_firmware.py is updated for the new U-Boot names.
  • The full suite passes, and so do ruff and mypy.

Verified on hardware

defib install with the split packages built from OpenIPC/firmware master, and the published U-Boot (g7e52056f):

  • GK7205V200 (8 MiB): U-Boot and firmware.bin written and CRC-verified, erased 0x50000+0x7B0000. It boots with Verifying Hash Integrity ... crc32+ sha1+ OK, and the partitions are where expected: kernel 0x50000–0x230000, rootfs from 0x230000, rootfs_data from 0x730000.
  • GK7205V300 (16 MiB, detected by the reads): erased 0x50000+0xFB0000, rootfs_data from 0x8D0000. After the totalmem fix, the first boot picks the CMA allocator with a 96 MB zone, as before the install.

…family

gk7202v300, gk7205v200, gk7205v300 and gk7605v100 now boot OpenIPC/u-boot
(openipc-hisilicon), published per flash type as u-boot-<soc>-nor.bin and
-nand.bin; the -universal.bin they used came from the retired
u-boot-gk7205v200 repository. They join PER_FLASH_TYPE_UBOOT, so burn,
install and restore fetch the new build.

That U-Boot works out the NOR layout at every boot -- fixed slots or the
split layout -- and sets mtdparts and the root device itself. Its
environment has no bootcmdnor, so the env stage's `setenv bootcmd
${bootcmdnor}` would have left these cameras without a bootcmd. On these
SoCs the env stage now loads the U-Boot defaults (env default -a) and
carries the ethaddr across, as the NAND UBI layout already does.

Their firmware also ships openipc.<board>-nor-<variant>-split.tgz
(OpenIPC/firmware#2617): one firmware.bin.<board>, a hashed FIT and then
the squashfs at the next 64 KiB, written at 0x50000; the kernel divides
it into kernel, rootfs and rootfs_data at boot. install recognises the
package by its contents:
- the image is checked for that shape and the board it names;
- the rootfs stage writes it at 0x50000 and erases the rest of the chip,
  so nothing of the old layout is left for U-Boot's scan or the overlay;
- the kernel and rootfs-data stages have nothing of their own to do;
- the size check is the image end plus one block of overlay against the
  detected chip;
- refused: another SoC, NAND, a stock-U-Boot migration, and
  --wipe-rootfs-data without the rootfs stage. A plan without the uboot
  stage warns that the flashed U-Boot must boot the layout.

Tests: tests/test_install_nor_split.py drives run_install against a
byte-accurate 8 MiB NOR console for the split and fixed-slot packages.
…05v200 family

Found installing the split layout on the lab GK7205V200 and GK7205V300
with the published OpenIPC/u-boot:

- That U-Boot probes the flash at boot and its `sf probe 0` prints nothing
  at the prompt, so the size fell back to 8 MiB: right by luck on the 8 MB
  board, and a 16 MB board would have been laid out as 8. When the probe
  reports no size, a 16-byte `sf read` just below 32, 16 and 8 MiB asks
  the chip: `sf read` refuses an offset past the end ("Offset exceeds
  device limit"), and the largest that reads is the size.
- Its `sf` has no lock subcommand and answers `sf lock 0` with the usage
  table, which carries `sf protect` but no `sf lock`. The console echo of
  the command sat above "Usage:" and was taken for a table entry, so the
  unlock was a hard failure. Only lines from "Usage:" on count now.
- `env default -a` dropped totalmem, which this U-Boot sets in RAM from
  the DRAM it measured. Linux sizes its media memory from the saved value
  (set_allocator) and without one assumes 64 MB: the GK7205V300 came up
  with a 32 MB gk allocator instead of 96 MB of CMA. The value is read
  before the reset and set again after it, like ethaddr.

Verified: defib install of openipc.gk7205v200-nor-lite-split.tgz on the
GK7205V200 (8 MiB) and openipc.gk7205v300-nor-ultimate-split.tgz on the
GK7205V300 (16 MiB, detected; erase 0x50000+0xFB0000). Both boot with the
FIT hashes checked and kernel/rootfs/rootfs_data split as computed; the
V300's first boot picks CMA with a 96 MB zone.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Support split NOR firmware and per-flash U-Boot on GK7205V200-family SoCs

✨ Enhancement 🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Select NOR or NAND OpenIPC U-Boot builds for four GK-family SoCs.
• Validate and install split NOR firmware while retaining fixed-slot support and guarding
 incompatible plans.
• Detect silent NOR probes and preserve boot-critical environment values; add integration coverage.
Diagram

graph TD
  A["SoC assets"] --> B["Package loader"] --> C{"Split NOR?"} -->|split| D["Install stages"] --> E["NOR flash"] --> H["U-Boot scan"]
  C -->|fixed slots| F["Fixed slots"] --> D
  D --> G["Boot defaults"] --> H
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Dedicated NOR layout strategy
  • ➕ Separates split-image flashing and capacity rules from fixed-slot installation.
  • ➕ Could simplify adding further layouts.
  • ➖ Requires a broader installer refactor.
  • ➖ Increases regression risk for existing install paths.

Recommendation: Keep the scoped extension to the existing installer: it supports both layouts for the four affected SoCs without restructuring other install paths. Consider a dedicated layout strategy if additional split formats or SoCs substantially expand the branching.

Files changed (9) +581 / -26

Enhancement (3) +217 / -12
firmware.pySelect per-flash U-Boot assets for four GK-family SoCs +23/-6

Select per-flash U-Boot assets for four GK-family SoCs

• Moves the SoCs from universal U-Boot assets to NOR/NAND-specific builds. Adds a capability check for split NOR support, including chip aliases.

src/defib/firmware.py

firmware.pyRecognize and validate single-image split NOR packages +70/-0

Recognize and validate single-image split NOR packages

• Adds a split flag to firmware bundles and checks the FIT-to-squashfs image shape. Validates available MD5 and board information, rejects mixed packages, and identifies split NOR packages mistakenly supplied for NAND.

src/defib/install/firmware.py

orchestrator.pyInstall split images and preserve scanning U-Boot defaults +124/-6

Install split images and preserve scanning U-Boot defaults

• Guards incompatible split install plans, checks image and overlay capacity, and writes the single image at 0x50000 while erasing to the chip end. Falls back to bounded reads when sf probe reports no size; on supported SoCs, loads U-Boot defaults while retaining ethaddr and measured totalmem.

src/defib/install/orchestrator.py

Bug fix (1) +41 / -2
layout.pyAdd split-board matching and NOR console compatibility helpers +41/-2

Add split-board matching and NOR console compatibility helpers

• Resolves acceptable board names for aliased SoCs and builds last-block NOR size probes. Restricts sf lock detection to usage-table entries, so an echoed command is not mistaken for supported syntax.

src/defib/install/layout.py

Tests (3) +282 / -4
test_firmware.pyCover updated per-flash U-Boot asset names +6/-4

Cover updated per-flash U-Boot asset names

• Extends per-flash asset expectations to the four GK-family SoCs. Keeps universal-asset assertions on a SoC that still publishes one.

tests/test_firmware.py

test_install_flash_helpers.pyTest silent-probe sizing and echoed sf lock usage +31/-0

Test silent-probe sizing and echoed sf lock usage

• Checks last-16-byte NOR read commands and accepted or rejected read responses. Covers a console that echoes sf lock before a usage table without a lock subcommand.

tests/test_install_flash_helpers.py

test_install_nor_split.pyExercise split NOR installation against a byte-accurate fake chip +245/-0

Exercise split NOR installation against a byte-accurate fake chip

• Tests package validation, full-region erase and image placement, boot environment preservation, fixed-slot compatibility, and no-op stages. Also checks capacity failures and incompatible SoC, NAND, and wipe-stage requests.

tests/test_install_nor_split.py

Documentation (2) +41 / -8
CLAUDE.mdDocument split NOR and flash-specific U-Boot conventions +12/-7

Document split NOR and flash-specific U-Boot conventions

• Adds the four OpenIPC/u-boot SoCs to the firmware architecture notes. Explains their split NOR package and U-Boot-owned environment.

CLAUDE.md

README.mdExplain split NOR installation and boot behavior +29/-1

Explain split NOR installation and boot behavior

• Documents the flash map, install command, stage behavior, and requirement for split-aware U-Boot. Clarifies that these SoCs do not need installer-persisted mtdparts.

README.md

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Truncated images can be flashed as valid ✓ Resolved
Description
split_image_end() rejects bytes beyond the rounded squashfs end but does not reject an image that
ends before the squashfs bytes_used boundary. A truncated archive image can therefore pass bundle
loading and the capacity check, after which the rootfs stage writes its incomplete bytes to NOR.
Code

src/defib/install/firmware.py[55]

+    if not used or end < len(image):
Evidence
The validator calculates end from bytes_used but checks only end < len(image), so an image
shorter than its declared squashfs payload passes. Bundle loading invokes that validator, while the
installer checks capacity using the calculated end but stages and flashes the original image bytes.

src/defib/install/firmware.py[47-60]
src/defib/install/firmware.py[113-135]
src/defib/install/orchestrator.py[891-899]
src/defib/install/orchestrator.py[958-964]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Split image validation accepts an image shorter than the squashfs size declared in its superblock, allowing an incomplete firmware payload to be flashed.
## Fix Focus Areas
- src/defib/install/firmware.py[53-60]
- tests/test_install_nor_split.py[164-171]
## Recommended Fix
Require the image to contain at least `squash + used` bytes while retaining the check that rejects data beyond the rounded squashfs end. Add a test with an image truncated within the declared squashfs payload.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. NAND installs fail on aliased cameras ✓ Resolved
Description
Adding the new SoCs to PER_FLASH_TYPE_UBOOT sends their aliases through UBI-only NAND
installation, but ubi_nand_boards() does not map those aliases to the board name used by their
firmware. For example, a gk7201v200 install selects the gk7205v200 NAND U-Boot and then rejects
a package containing rootfs.ubi.gk7205v200 as the wrong board.
Code

src/defib/firmware.py[55]

+    "gk7202v300", "gk7205v200", "gk7205v300", "gk7605v100",
Evidence
The alias table maps gk7201v200 to gk7205v200, and per-flash U-Boot lookup applies that mapping.
NAND installation now uses the UBI-only loader, whose board allowlist comes from a separate mapping
that omits this alias; the loader rejects a board suffix outside that allowlist.

src/defib/firmware.py[101-107]
src/defib/firmware.py[153-156]
src/defib/install/orchestrator.py[159-163]
src/defib/install/orchestrator.py[237-245]
src/defib/install/layout.py[58-68]
src/defib/install/firmware.py[151-160]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New per-flash NAND installs select an aliased SoC's published U-Boot but reject the correspondingly named UBI firmware image.
## Fix Focus Areas
- src/defib/install/layout.py[58-68]
- src/defib/install/orchestrator.py[240-245]
## Recommended Fix
Include the chip's `CHIP_TO_FIRMWARE` target in the allowed NAND package board names, preserving the existing gk7205v500-family mapping. Test a NAND install for an alias such as `gk7201v200` with `rootfs.ubi.gk7205v200`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Size check aborts installs in download-command mode ✓ Resolved
Description
The new size check loop calls _cmd(nor_size_probe_read(...)). In download_process mode, _cmd
sends any command that returns [EOT](ERROR) to close_and_fail, so a refused read never reaches
sf_read_succeeded. On a chip smaller than 32 MiB whose sf probe output has no size, the first 32
MiB read is refused and the whole install exits; before this change it fell back to 8 MiB.
Code

src/defib/install/orchestrator.py[R869-873]

+            for candidate in NOR_SIZE_CANDIDATES_MB:
+                read_resp = await _cmd(nor_size_probe_read(ram_addr, candidate), timeout=5.0)
+                if sf_read_succeeded(read_resp):
+                    detected_nor_size = candidate
+                    break
Evidence
In download mode, _cmd uses _cmd_result with allow_failure=False, which calls close_and_fail
when ok is False. DownloadCommandClient.send_command returns False on [EOT](ERROR). The size
check expects a refused read to come back as a normal response so it can try the next size, but in
this mode the refusal ends the install. Download mode is chosen for any U-Boot that prints 'start
download process', whatever the chip.

src/defib/install/orchestrator.py[669-695]
src/defib/install/orchestrator.py[606-616]
src/defib/protocol/download_cmd.py[57-130]
src/defib/install/orchestrator.py[865-873]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The NOR size check sends `sf read` commands that are expected to be refused on smaller chips. In download_process mode, `_cmd` sends any failed command to `close_and_fail`, so the first refused read (32 MiB) aborts the install instead of moving on to 16/8 MiB.
## Fix Focus Areas
- src/defib/install/orchestrator.py[866-873]
- src/defib/install/orchestrator.py[669-695]
## Recommended Fix
Call `ok, read_resp = await _cmd_result(nor_size_probe_read(ram_addr, candidate), timeout=5.0, allow_failure=True)` and treat the read as successful only when `ok and sf_read_succeeded(read_resp)` holds. In download mode a successful read returns `[EOT](OK)` and may not print `Read: OK`, so either accept `ok` alone there or adjust `sf_read_succeeded` to match. Add a test that runs the size check through the download-mode client.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Whole-chip erase on 32 MiB boards can time out ✓ Resolved
Description
On the split layout, r_sz is set to nor_size*1MiB - k_off (0x1FB0000 on 32 MiB) and erased
through tftp_and_flash, which runs sf erase with a 180 s timeout. That code was sized for the
fixed-slot rootfs partition, while the existing rootfs_data erase allows 300 s for a smaller region;
if the erase takes longer, send_command(require_prompt=True) stops the install after the new
U-Boot is written but before firmware.bin is.
Code

src/defib/install/orchestrator.py[R924-928]

+        if split:
+            # firmware.bin goes where the kernel slot starts, and the erase
+            # runs to the end of the chip: nothing of the old layout survives
+            # to be found by U-Boot's scan or mistaken for an overlay.
+            r_off, r_sz = k_off, nor_size * 1024 * 1024 - k_off
Evidence
The split branch makes the rootfs erase run from 0x50000 to the end of the chip. tftp_and_flash
uses timeout=180.0 for NOR erase. The rootfs_data erase, which covers only the region after the
fixed rootfs slot, uses timeout=300.0. The shell _cmd requires the prompt to return, so a slow
erase becomes a transport failure. Hardware testing covered 8 and 16 MiB chips only.

src/defib/install/orchestrator.py[1259-1278]
src/defib/install/orchestrator.py[1606-1608]
src/defib/install/orchestrator.py[709-728]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The split rootfs stage erases nearly the whole chip through `tftp_and_flash`, which uses a fixed 180 s timeout meant for the fixed-slot rootfs partition. On 32 MiB chips with slow block erase this can time out partway through the install.
## Fix Focus Areas
- src/defib/install/orchestrator.py[1259-1278]
- src/defib/install/orchestrator.py[924-928]
## Recommended Fix
Work out the erase timeout from `erase_len`, e.g. `max(180.0, erase_len / nor_erase_block * 1.0)` (about 1 s per 64 KiB block), or at least match the 300 s used by the rootfs_data erase when `split` is set.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can see how risky a PR is at a glance with blast radius labels

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/defib/install/firmware.py Outdated
Comment thread src/defib/firmware.py
Comment thread src/defib/install/orchestrator.py
Comment thread src/defib/install/orchestrator.py
…d mode, erase time

From review of the split NOR install:

- An image that ends inside the squashfs its superblock declares is
  refused as truncated; only bytes past the rounded end were refused.
- ubi_nand_boards() also accepts the board an aliased chip is published
  under: gk7201v200 now installs the gk7205v200 NAND U-Boot and must take
  its rootfs.ubi.gk7205v200.
- The NOR size reads go through _cmd_result(allow_failure=True). In
  download-command mode a refused read came back as a failed command,
  which _cmd turns into the end of the install; a read that fits is the
  command's OK status there, "Read: OK" in the shell.
- The erase timeout grows with the region, about a second per 64 KiB
  block with 180 s as the floor: the split layout erases from 0x50000 to
  the end of the chip, 0x1FB0000 on 32 MiB.

The shape test's parameters are bytes, and their generated ids reached
PYTEST_CURRENT_TEST, past Windows' 32767-character limit on an
environment variable; they carry short ids now.
widgetii added a commit to OpenIPC/website that referenced this pull request Oct 17, 2026
…nand.bin

Review of the previous commit: Bootloader("nand") falls back to
uboot_filename, so moving these SoCs to u-boot-<soc>-nor.bin handed that
NOR build to NAND installs and NAND full images.

OpenIPC/u-boot publishes a NAND build for each of them too,
u-boot-<soc>-nand.bin in latest, and that build is the UBI-only layout
(768k boot, 256k env, the rest one UBI device), the same as u-boot-xmedia's.
So the catalogue names it as uboot_nand_filename, which is what moves a
SoC's NAND installs onto that layout; defib (OpenIPC/defib#154) installs
these SoCs on NAND the same way. The retired -universal.bin, and its split
NAND layout, is not offered for them again.

The fixture index gains the four published -nand.bin. boards.json carries
them; the gk7202v300 NAND row of the image reference is dropped, since it
is the split NAND layout this SoC no longer installs (hi3516av100's row
still covers that layout). The documents golden is regenerated.
@widgetii
widgetii merged commit 5997375 into master Oct 17, 2026
13 checks passed
widgetii added a commit to OpenIPC/website that referenced this pull request Oct 17, 2026
…yout (#482)

* Wizard: the GK7205V200 family on OpenIPC/u-boot, and the split NOR layout

GK7202V300, GK7205V200, GK7205V210, GK7205V300 and GK7605V100 now install
OpenIPC/u-boot's u-boot-<soc>-nor.bin (OpenIPC/u-boot#18, #19), published
in latest, in place of the -universal.bin of the retired u-boot-gk7205v200
repository. That bootloader scans the NOR layout at boot, so these SoCs
take the #477 install: each image written at its offset, no uknor/urnor
macros, no sf lock.

The same bootloader boots the split NOR layout (OpenIPC/linux#96,
OpenIPC/firmware#2617, #2621): one firmware.bin -- a hashed FIT, then the
squashfs at the next 64 KiB -- at 0x50000, which the kernel divides into
kernel, rootfs and rootfs_data at boot. Their firmware publishes it as
openipc.<board>-nor-<edition>-split.tgz beside the fixed-slot package.
The catalogue marks these SoCs nor_split; where the -split package is
published for the board and edition, the Linux step writes that one
image at 0x50000 and erases to the end of the chip in the same guarded
line (0x7b0000 on 8 MB, 0xfb0000 on 16 MB), and the page links the
-split package. Where it is not, the two-image install stays. The full
image and the backup/restore steps are unchanged: the bootloader boots
the fixed slots the full image carries.

The fixture index gains the four published u-boot-<soc>-nor.bin, so the
availability reference stands; boards.json and the documents golden are
regenerated for the five SoCs. TestSplitNORInstall covers the split
lines, gk7205v210 through its gk7205v200 build, the SD path, and the
fall-back when no -split package is published.

The split install was verified on the lab GK7205V200 (8 MB) and GK7205V300
(16 MB) with these bootloaders and the 2026-10-17 nightly's images, by
the same U-Boot write: boots with the FIT hashes checked and kernel,
rootfs and rootfs_data where the image puts them.

* Wizard: the GK7205V200 family's NAND bootloader is OpenIPC/u-boot's -nand.bin

Review of the previous commit: Bootloader("nand") falls back to
uboot_filename, so moving these SoCs to u-boot-<soc>-nor.bin handed that
NOR build to NAND installs and NAND full images.

OpenIPC/u-boot publishes a NAND build for each of them too,
u-boot-<soc>-nand.bin in latest, and that build is the UBI-only layout
(768k boot, 256k env, the rest one UBI device), the same as u-boot-xmedia's.
So the catalogue names it as uboot_nand_filename, which is what moves a
SoC's NAND installs onto that layout; defib (OpenIPC/defib#154) installs
these SoCs on NAND the same way. The retired -universal.bin, and its split
NAND layout, is not offered for them again.

The fixture index gains the four published -nand.bin. boards.json carries
them; the gk7202v300 NAND row of the image reference is dropped, since it
is the split NAND layout this SoC no longer installs (hi3516av100's row
still covers that layout). The documents golden is regenerated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant