Skip to content

gk7205v200: kernel and rootfs in one NOR partition, split at boot - #2617

Merged
widgetii merged 2 commits into
masterfrom
nor/fit-split
Oct 17, 2026
Merged

widgetii merged 2 commits into
masterfrom
nor/fit-split

Conversation

@widgetii

@widgetii widgetii commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Today each image has to fit its own fixed slot: kernel 2 MiB, rootfs 5 MiB (8 MB parts) or 8 MiB. Slack in one slot is lost to the other, and every build becomes a round of trimming. On the gk7205v200 family, a camera can now carry both in one firmware partition, which the kernel splits at boot. Only the sum has to fit the chip.

Depends on OpenIPC/linux#96 (mtdsplit) and OpenIPC/u-boot#18 (boots the layout), both merged.

What ships

  • openipc.<soc>-nor-<variant>.tgz is unchanged: the fixed-slot uImage and rootfs, size-gated as before. Every camera in the field upgrades from it with its own sysupgrade, and the openipc.org installer reads it.
  • openipc.<soc>-nor-<variant>-split.tgz is new and holds firmware.bin:
    • a crc32+sha1 FIT (zImage and the board DTB) followed by the squashfs at the next 64 KiB;
    • gated against the chip, less boot, env and a 256 KiB overlay;
    • no older sysupgrade looks for this name.

The space win arrives once the plain package can be retired.

sysupgrade

  • When it acts: a bootloader that boots the layout appends openipc_nor_fit=1 to the command line. The default URL then names the -split package.
  • How it writes: firmware.bin goes down through mtdblock at 0x50000, either over firmware or, coming from fixed slots, across kernel, rootfs and rootfs_data. Each write runs dd conv=fsync, then is read back through the MTD character device. Without the fsync, the last block written into the mounted rootfs stayed in mtdblock's cache and was lost at the reboot (measured on GK7205V300).
  • Settings: the overlay moves with the squashfs end. Its contents travel as a blob (OPENIPC-OVL1, a 12-digit length, a gzipped tar) written where the new rootfs_data starts. /init restores it before it mounts the overlay. -n writes a blob of length 0, which only erases.
  • Refused, with nothing written:
    • a split image on a bootloader without the token;
    • another SoC's image;
    • an image that leaves no block for settings;
    • a separate kernel and rootfs on a camera already on the split layout.

Tests

  • test_sysupgrade.sh covers the split write and overlay offset, -n, the move from fixed slots, each refusal, a write that never reached the chip, and the default URL.
  • test_init_overlay.sh runs the carry-over itself.
  • Both pass in plain and comment-stripped form.

Verified on hardware

GK7205V200 (8 MB) and GK7205V300 (16 MB) NOR, on OpenIPC U-Boot with CONFIG_OPENIPC_NOR_FIT_SPLIT:

  • Boot: FIT hashes are checked, and /proc/mtd is split at the computed offsets.
  • Upgrades: from fixed slots, split to split, to a bigger image and to a smaller one, all with the sysupgrade inside the image. Claim, SSH keys and a marker file carried over each time.
  • -n: the camera comes up on defaults.
  • Legacy: the new kernel built as a uImage boots the fixed-slot layout unchanged.
  • Refusals: the plain package on a split camera, and a split image on a token-less bootloader, are both refused with nothing written and no reboot.

gk7202v300 and gk7605v100 get the kernel options and a -split package too. Their U-Boot doesn't enable the layout yet, so sysupgrade keeps them on the plain package.

Hardware evidence (serial console)

All runs below use the images built from this branch, upgrading with the sysupgrade inside them.

GK7205V200 (8 MB), fixed slots → split:

Split NOR layout: firmware.bin at 0x50000, the kernel divides it at boot
Writing /tmp/firmware.bin.gk7205v200 at 0x50000
Settings staged at 0x730000 for the first boot
   Verifying Hash Integrity ... crc32+ sha1+ OK
Kernel command line: mem=32M ... root=/dev/mtdblock4 init=/init mtdparts=sfc:256k(u-boot),64k(env),-(firmware) mmz_allocator=gk openipc_nor_fit=1
0x000000050000-0x000000800000 : "firmware"
0x000000050000-0x000000230000 : "kernel"
0x000000230000-0x000000800000 : "rootfs"
1 squashfs-split partitions found on MTD device rootfs
0x000000730000-0x000000800000 : "rootfs_data"
Restoring settings carried over by an upgrade...
Settings restored.

A marker file written to /etc before the upgrade read back afterwards, and SSH key login still worked.

GK7205V300 (16 MB), split → split:

Writing /tmp/firmware.bin.gk7205v300 at 0x50000
Settings staged at 0x8d0000 for the first boot
   Verifying Hash Integrity ... crc32+ sha1+ OK
0x000000050000-0x000001000000 : "firmware"
0x000000050000-0x000000230000 : "kernel"
Restoring settings carried over by an upgrade...
Settings restored.

/proc/mtd afterwards: mtd5: 00730000 00010000 "rootfs_data"

GK7205V200, sysupgrade -n:

Settings staged at 0x730000 for the first boot
Clearing settings after an upgrade...
gk7205v200-imx307 login:

The hostname is back to its default, so the overlay was cleared.

GK7205V200, the new kernel as a uImage on fixed slots:

0x000000050000-0x000000250000 : "kernel"
0x000000250000-0x000000750000 : "rootfs"
0x000000050000-0x000000750000 : "firmware"
0x000000750000-0x000000800000 : "rootfs_data"
VFS: Mounted root (squashfs filesystem) readonly on device 31:3.

The firmware alias holds a uImage and is not split.

GK7205V300, the plain package on a split camera (no reboot; uptime unchanged):

This camera runs the split NOR layout and upgrades from firmware.bin (openipc.gk7205v300-nor-ultimate-split.tgz), not a separate kernel and rootfs. Nothing was written. Aborting.

Sizes (build output):

gk7205v200_lite:     uImage [1877KB/2048KB], rootfs.squashfs [5084KB/5120KB], firmware.bin [7040KB/7616KB]
gk7205v300_ultimate: uImage [1886KB/2048KB], rootfs.squashfs [6748KB/8192KB], firmware.bin [8704KB/15808KB]

The fixed slots -- kernel 2 MiB at 0x50000, rootfs 5 MiB after it -- each
cap their image on their own, so slack in one is lost to the other and
every build is a round of trimming. On the gk7205v200 family the kernel
now splits one "firmware" partition at boot (mtdsplit, OpenIPC/linux):
the FIT at its start, the squashfs at the next 64 KiB, rootfs_data from
the squashfs end. Only the sum has to fit the chip.

Build: the kernel enables MTD_SPLIT_FIRMWARE, the FIT and squashfs
parsers and MTD_ROOTFS_ROOT_DEV; legacy fixed-slot command lines are
left unsplit. post-image.sh packs firmware.bin, a crc32+sha1 FIT (zImage
and the board DTB, nor-fit.its, described "OpenIPC <soc>") then the
squashfs.

Packages: the plain openipc.<soc>-nor-<variant>.tgz stays the fixed-slot
uImage and rootfs, gated as before -- every camera in the field upgrades
from it with its own sysupgrade, and the openipc.org installer reads it.
firmware.bin goes into openipc.<soc>-nor-<variant>-split.tgz, a name no
older sysupgrade looks for, gated against the chip less boot, env and a
256 KiB overlay. The space win arrives when the plain package is retired.

sysupgrade: a bootloader that boots the layout says so with
openipc_nor_fit=1 (OpenIPC/u-boot, CONFIG_OPENIPC_NOR_FIT_SPLIT), and
the default URL then names the -split package. firmware.bin goes down
through mtdblock at 0x50000, over the "firmware" partition or, from
fixed slots, across kernel, rootfs and rootfs_data. The overlay moves
with the squashfs end, so its contents travel as a blob ("OPENIPC-OVL1",
12-digit length, gzipped tar) written where the new rootfs_data starts;
-n writes a blob of length 0. dd runs with conv=fsync: from fixed slots
the mounted root holds "rootfs" open, mtdblock keeps its last block
cached until a flush, and a plain sync does not send one -- the blob was
lost at the reboot without it (GK7205V300). Both writes are then read
back through the MTD character device. Refused before anything is
written: a split image on a bootloader without the token, another SoC's
image, one that leaves no block for settings, and a separate kernel and
rootfs on a camera already on the split layout.

/init restores the blob before it mounts rootfs_data: erase the
partition, mount it, untar, unmount. Length 0 only erases.

Tests: test_sysupgrade.sh covers the split write, the overlay offset,
-n, the move from fixed slots, the refusals, the read-back and the
default URL; test_init_overlay.sh runs the carry-over itself.

Verified on GK7205V200 (8 MB) and GK7205V300 (16 MB) NOR with OpenIPC
U-Boot built with CONFIG_OPENIPC_NOR_FIT_SPLIT: FIT hashes checked at
boot, /proc/mtd split as computed; upgrades to a bigger and a smaller
image, from fixed slots, and split to split carry claim, keys and a
marker file, using the sysupgrade inside the image; -n comes up on
defaults; the new kernel as a uImage boots the fixed-slot layout
unchanged; the plain package on a split camera and a split image on a
token-less bootloader are refused with nothing written and no reboot.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add split-NOR firmware packaging and upgrades for Goke cameras

✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Package FIT and squashfs together so split-layout cameras can share available NOR space.
• Keep fixed-slot packages for existing cameras; select split packages only with bootloader support.
• Preserve settings across moving overlay boundaries and test upgrades, refusals, and first-boot
 restoration.
Diagram

graph TD
  Build["Image build"] --> Split["Split package"] --> Upgrade["sysupgrade"] --> Flash[("NOR firmware")] --> Kernel["MTD split"] --> Init["Overlay init"]
  Build --> Plain["Fixed package"] -->|"legacy cameras"| Upgrade
  Boot["Bootloader token"] --> Upgrade
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Replace the fixed-slot package immediately
  • ➕ Makes the shared-space benefit available without maintaining two packages.
  • ➖ Existing bootloaders cannot boot the split image.
  • ➖ Breaks consumers expecting the unchanged plain package.
2. Resize fixed partitions instead
  • ➕ Could retain separate kernel and rootfs upgrade paths.
  • ➖ Still imposes per-image limits.
  • ➖ Requires coordinated bootloader partition changes across deployed devices.

Recommendation: Keep the dual-package approach. It introduces the shared-space layout without changing the upgrade artifact used by existing cameras; bootloader-token gating and pre-write refusals provide a safer migration path than replacing or resizing deployed fixed slots.

Files changed (15) +628 / -1

Enhancement (5) +351 / -1
MakefilePublish a separately size-gated split-NOR archive +26/-0

Publish a separately size-gated split-NOR archive

• Preserves the fixed-slot package and adds a firmware.bin-only split package. Gates the combined image against chip capacity while reserving space for boot, environment, and overlay.

Makefile

nor-fit.itsDefine the hashed NOR FIT image +53/-0

Define the hashed NOR FIT image

• Defines a SoC-identified FIT containing the zImage and board DTB, each with CRC32 and SHA-1 hashes.

br-ext-chip-goke/board/gk7205v200/nor-fit.its

post-image.shAssemble aligned combined NOR firmware +33/-0

Assemble aligned combined NOR firmware

• Builds the board-specific FIT from kernel outputs, places squashfs at the next 64 KiB boundary, and pads firmware.bin to an erase-block boundary.

br-ext-chip-goke/board/gk7205v200/post-image.sh

initRestore relocated settings before overlay mount +32/-0

Restore relocated settings before overlay mount

• Detects a staged settings blob at the new NOR rootfs_data start. Erases and restores its archive before the normal mount, or erases without restoring for an empty blob.

general/overlay/init

sysupgradeSafely migrate and upgrade split-NOR firmware +207/-1

Safely migrate and upgrade split-NOR firmware

• Selects split packages only for capable bootloaders and rejects incompatible layouts, SoCs, and images before writing. Writes across either NOR partition layout with fsync and character-device read-back, staging settings at the new overlay offset.

general/overlay/usr/sbin/sysupgrade

Tests (2) +253 / -0
test_init_overlay.shTest first-boot settings carry-over +57/-0

Test first-boot settings carry-over

• Exercises restoration of a staged overlay blob, verifies erase-before-mount ordering, and checks empty and absent blobs.

.github/scripts/test_init_overlay.sh

test_sysupgrade.shCover split-NOR upgrades and refusals +196/-0

Cover split-NOR upgrades and refusals

• Adds synthetic flash layouts and combined images to test writes, settings offsets, fixed-slot migration, read-back failures, unsafe-image refusals, and default package URLs.

.github/scripts/test_sysupgrade.sh

Other (8) +24 / -0
gk7202v300.generic.configEnable firmware splitting for GK7202V300 +5/-0

Enable firmware splitting for GK7202V300

• Enables MTD firmware, FIT, and squashfs splitting and root-device selection for the shared firmware partition.

br-ext-chip-goke/board/gk7205v200/gk7202v300.generic.config

gk7205v200.generic.configEnable firmware splitting for GK7205V200 +5/-0

Enable firmware splitting for GK7205V200

• Enables MTD firmware, FIT, and squashfs splitting and root-device selection for the shared firmware partition.

br-ext-chip-goke/board/gk7205v200/gk7205v200.generic.config

gk7205v300.generic.configEnable firmware splitting for GK7205V300 +5/-0

Enable firmware splitting for GK7205V300

• Enables MTD firmware, FIT, and squashfs splitting and root-device selection for the shared firmware partition.

br-ext-chip-goke/board/gk7205v200/gk7205v300.generic.config

gk7605v100.generic.configEnable firmware splitting for GK7605V100 +5/-0

Enable firmware splitting for GK7605V100

• Enables MTD firmware, FIT, and squashfs splitting and root-device selection for the shared firmware partition.

br-ext-chip-goke/board/gk7205v200/gk7605v100.generic.config

gk7205v200_lite_defconfigBuild split firmware for GK7205V200 lite +1/-0

Build split firmware for GK7205V200 lite

• Registers the Goke post-image script so this configuration produces firmware.bin alongside its legacy images.

br-ext-chip-goke/configs/gk7205v200_lite_defconfig

gk7205v200_ultimate_defconfigBuild split firmware for GK7205V200 ultimate +1/-0

Build split firmware for GK7205V200 ultimate

• Registers the Goke post-image script so this configuration produces firmware.bin alongside its legacy images.

br-ext-chip-goke/configs/gk7205v200_ultimate_defconfig

gk7205v300_lite_defconfigBuild split firmware for GK7205V300 lite +1/-0

Build split firmware for GK7205V300 lite

• Registers the Goke post-image script so this configuration produces firmware.bin alongside its legacy images.

br-ext-chip-goke/configs/gk7205v300_lite_defconfig

gk7205v300_ultimate_defconfigBuild split firmware for GK7205V300 ultimate +1/-0

Build split firmware for GK7205V300 ultimate

• Registers the Goke post-image script so this configuration produces firmware.bin alongside its legacy images.

br-ext-chip-goke/configs/gk7205v300_ultimate_defconfig

@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 (1) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Hardware verification lacks measured output 📘 Rule violation ≡ Correctness
Description
sysupgrade adds a new split-NOR firmware path that changes what runs on the camera, but the PR
description reports only narrative pass claims rather than board output or before/after
measurements. The gk7205v200/gk7205v300 and related configurations therefore have no dmesg, logs,
stream results, or measured comparison to substantiate the claimed boot and upgrade behavior.
Code

general/overlay/usr/sbin/sysupgrade[R919-922]

+do_update_firmware_split() {
+	local x=$1 ovl end blob=/tmp/overlay.blob tgz=/tmp/overlay.tgz mp
+	echo "Split NOR layout: firmware.bin at 0x50000, the kernel divides it at boot"
+	[ "$(fit_soc "$x")" = "$model" ] ||
Evidence
The new split-NOR path changes firmware behavior on cameras, while the PR description claims
hardware verification without showing the required board-specific logs, dmesg, stream behavior, or
before/after measurements.

Rule 3: Hardware evidence is present and honest
general/overlay/usr/sbin/sysupgrade[919-922]
br-ext-chip-goke/configs/gk7205v200_lite_defconfig[40-40]

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 PR changes the camera's boot and firmware-upgrade behavior, but its hardware verification section provides narrative claims without before/after output from the affected boards.
## Fix Focus Areas
- general/overlay/usr/sbin/sysupgrade[919-922]
- br-ext-chip-goke/configs/gk7205v200_lite_defconfig[40-40]
## Recommended Fix
Add concrete hardware evidence to the PR description for the affected boards, including representative boot or dmesg output and upgrade results, plus before/after measurements where applicable. Ensure every verification or test checkbox is checked and identify the board associated with each result.

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


2. Invalid images can replace split firmware ✓ Resolved
Description
check_combined_fits() falls through to the generic firmware-size check when nor_split_image()
cannot recognize a combined image, even on a camera running the split layout. A malformed or
incompatible firmware.bin can therefore pass preflight and reach the generic whole-partition
flashcp path without FIT, squashfs, or SoC validation.
Code

general/overlay/usr/sbin/sysupgrade[348]

+	if nor_split_image "$x"; then
Evidence
The added condition validates only images it already recognizes. With no separate kernel or rootfs
device, the existing fallback checks size and then writes the blob to firmware.

general/overlay/usr/sbin/sysupgrade[345-379]
general/overlay/usr/sbin/sysupgrade[969-1016]
general/overlay/usr/sbin/sysupgrade[1729-1733]

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

## Issue description
An unrecognized combined image falls through to whole-partition flashing on a running split-layout camera.
## Fix Focus Areas
- general/overlay/usr/sbin/sysupgrade[348-358]
- general/overlay/usr/sbin/sysupgrade[972-975]
## Recommended Fix
When the camera runs the split layout, require a valid split FIT, matching SoC, and squashfs before accepting any combined image; do not use the generic firmware fallback for that layout.

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


3. A damaged carry-over erases settings ✓ Resolved
Description
overlay_carry_in() erases rootfs_data after copying the declared archive length without checking
that the copy or archive is complete. If the staged blob is truncated or corrupt, extraction fails
only after the erase, so the boot cannot recover settings still present in that partition.
Code

general/overlay/init[R112-115]

+	dd if="$chr" bs=65536 count=$blocks 2>/dev/null | tail -c +25 | head -c "$len" > /overlay/settings.tgz
+	flash_eraseall -j "$chr"
+	if mount -t jffs2 "$blk" /mnt; then
+		gunzip -c /overlay/settings.tgz | tar -x -C /mnt && echo "Settings restored."
Evidence
Detection checks only the marker and length; read errors are suppressed, the erase precedes
extraction, and extraction failure does not stop boot.

general/overlay/init[97-120]
general/overlay/usr/sbin/sysupgrade[937-948]

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

## Issue description
A marker and declared length are enough to trigger an erase even when the saved archive cannot be restored.
## Fix Focus Areas
- general/overlay/init[97-120]
## Recommended Fix
Verify the length and gzip/tar contents in temporary storage before erasing rootfs_data; on validation failure, leave flash untouched and report the failure.

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



Remediation recommended

4. Oversized images can leave flash partial ✓ Resolved
Description
check_combined_fits() bounds the new overlay offset but never bounds the full firmware.bin file
length against the flash end. An image with trailing data beyond its squashfs can pass preflight,
then nor_write_at() commits its earlier blocks before discovering that the remaining bytes have no
covered partition.
Code

general/overlay/usr/sbin/sysupgrade[R350-351]

+		[ $((ovl + 65536)) -le "$end" ] ||
+			die "$x does not fit the flash with room for settings: it ends at $(printf 0x%x "$ovl"), the flash at $(printf 0x%x "$end"). Nothing was written."
Evidence
The overlay calculation uses squashfs bytes_used, while the writer uses the complete file size and
writes intersecting partitions sequentially.

general/overlay/usr/sbin/sysupgrade[843-852]
general/overlay/usr/sbin/sysupgrade[870-883]
general/overlay/usr/sbin/sysupgrade[937-947]

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-image size check measures the squashfs boundary, not all bytes subsequently written.
## Fix Focus Areas
- general/overlay/usr/sbin/sysupgrade[348-352]
- general/overlay/usr/sbin/sysupgrade[940-946]
## Recommended Fix
Before the first write, verify that the complete firmware file ends within the covered flash area and does not overlap the settings destination.

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


5. A failed temporary mount can lose settings ✓ Resolved
Description
overlay_carry_in() returns normally when its temporary tmpfs mount fails, leaving the staged blob
unrestored. The caller continues into ordinary JFFS2 handling, where a failed mount can format
rootfs_data because the carry-over marker is not recognized by overlay_is_ours().
Code

general/overlay/init[111]

+	mount -t tmpfs tmpfs /overlay || return 0
Evidence
The new function returns on tmpfs failure, its caller ignores that outcome, and the existing
formatting path recognizes only filesystem markers, not OPENIPC-OVL1.

general/overlay/init[110-128]
general/overlay/init[159-184]

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

## Issue description
Failure to allocate temporary storage falls through to a path that can erase the unconsumed carry-over blob.
## Fix Focus Areas
- general/overlay/init[110-120]
- general/overlay/init[159-184]
## Recommended Fix
Propagate the mount failure and prevent ordinary overlay formatting while an unconsumed carry-over marker remains; boot with a non-destructive fallback.

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


6. Wrong-SoC or oversized upgrades reboot the camera ✓ Resolved
Description
check_combined_fits() validates split-image geometry but leaves the FIT SoC comparison and actual
settings-size check to do_update_firmware_split(), after enter_ramfs has pivoted. A wrong-SoC
image or settings blob larger than the space remaining after squashfs then reaches die(), which
reboots the camera without writing anything and can make the refused upgrade look successful to a
watcher.
Code

general/overlay/usr/sbin/sysupgrade[R922-923]

+	[ "$(fit_soc "$x")" = "$model" ] ||
+		die "$x is built for $(fit_soc "$x"), this camera is a $model. Nothing was written."
Evidence
flash_and_reboot calls do_update_firmware_split() after the pivot, and preflight_image_sizes
notes that die() must reboot at that point. check_combined_fits() checks only that at least one
64 KiB block remains after squashfs, while the SoC comparison and settings-size check occur in the
later writer. The wrong-SoC test does not assert ! rebooted, unlike the bootloader-refusal test.

general/overlay/usr/sbin/sysupgrade[345-358]
general/overlay/usr/sbin/sysupgrade[369-398]
general/overlay/usr/sbin/sysupgrade[919-953]
general/overlay/usr/sbin/sysupgrade[3081-3087]
general/overlay/usr/sbin/sysupgrade[3161-3165]
.github/scripts/test_sysupgrade.sh[3279-3288]
general/overlay/usr/sbin/sysupgrade[116-140]
general/overlay/usr/sbin/sysupgrade[345-352]
general/overlay/usr/sbin/sysupgrade[919-925]
general/overlay/usr/sbin/sysupgrade[3477-3497]

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-NOR preflight does not check the FIT SoC or whether the settings blob fits. Those refusals happen after the ramfs pivot, where `die()` reboots the camera despite nothing having been written.
## Fix Focus Areas
- general/overlay/usr/sbin/sysupgrade[348-353]
- general/overlay/usr/sbin/sysupgrade[919-943]
## Recommended Fix
In the `nor_split_image` branch of `check_combined_fits()`, compare `fit_soc "$x"` with `$model` and refuse a mismatch before the pivot. Estimate the settings blob size there—for example, the compressed overlay tar size plus 24 bytes, rounded up to 64 KiB, or 64 KiB when `-n` is set—and refuse if `ovl + blob > end`. Retain the flash-phase checks as safeguards, and add a `! rebooted` assertion to the wrong-SoC test.

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


View medium (2)
7. Split cameras cannot upgrade by channel ✓ Resolved
Description
Only default_upgrade_url was taught to name the -split archive. The --channel/--build path
in download_firmware still calls resolve_url "$build_id" "$platform" "$(pkg_flash)", and that
has no way to pick the split package. push_build.py's FIRMWARE_ASSET_RE does not match
openipc.-nor--split.tgz, so a channel resolves to the plain fixed-slot archive, and on a camera
already on the split layout preflight_image_sizes then refuses it every time.
Code

general/overlay/usr/sbin/sysupgrade[R2966-2968]

+	local split=
+	[ "$repo" = firmware ] && [ "$(pkg_flash)" = nor ] && nor_split_family && nor_split_boot && split=-split
+	echo "https://github.com/OpenIPC/$repo/releases/download/latest/openipc.$model-$(pkg_flash)-$osr$split.tgz"
Evidence
The manifest branch of download_firmware sets url from resolve_url, which is keyed only on
platform and flash ('nor'), so default_upgrade_url is never consulted. The publishing regex needs
the edition to be followed directly by .tgz, so -split assets yield no platform. The new
nor_split_running refusal rejects the uImage/rootfs that the plain package delivers.

general/overlay/usr/sbin/sysupgrade[1686-1701]
general/overlay/usr/sbin/sysupgrade[1152-1156]
.github/scripts/push_build.py[44-46]
general/overlay/usr/sbin/sysupgrade[398-404]

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

## Issue description
On a split-layout camera, `--channel`/`--build` resolves the manifest entry for (platform, nor), which is the plain fixed-slot package. preflight then refuses it, so a split camera can never upgrade by channel.
## Fix Focus Areas
- general/overlay/usr/sbin/sysupgrade[1686-1698]
- general/overlay/usr/sbin/sysupgrade[2963-2968]
- .github/scripts/push_build.py[44-46]
## Recommended Fix
Put the split predicate (`nor_split_family && nor_split_boot` with nor flash) in one helper. In the manifest branch, when that helper is true, rewrite the resolved URL's basename from `...-nor-<osr>.tgz` to `...-nor-<osr>-split.tgz`, or resolve a distinct flash key such as `nor-split` once the manifest publishes one. Extend FIRMWARE_ASSET_RE with an optional `(-split)?` suffix so the asset is attributed to its platform, and add tests.

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


8. Settings restore can erase a mirrored flash ✓ Resolved
Description
init calls overlay_carry_in() before flash_aliased(), allowing the carry-over path to run
flash_eraseall -j on rootfs_data before the alias guard runs. When a mis-sized NOR chip presents
an aliased rootfs_data with a carry-over marker, that erase can wrap past the chip’s real end onto
u-boot, env, the kernel and rootfs instead of being diverted to tmpfs.
Code

general/overlay/init[R159-160]

+		grep -q 'nand' /proc/cmdline || overlay_carry_in /dev/$mtdchrdev /dev/$mtdblkdev
  if ! grep -q 'nand' /proc/cmdline && flash_aliased; then
Evidence
The comment above flash_aliased() warns that erasing mirrored rootfs_data also erases
bootloader, env, kernel and rootfs data. The new carry-in call precedes that guard and can erase
after finding the marker; nor_split_end uses the kernel-reported chip end from sysfs, so a blob
can be staged on a chip whose reported size exceeds its real size.

general/overlay/init[10-25]
general/overlay/init[97-120]
general/overlay/init[153-166]
general/overlay/usr/sbin/sysupgrade[808-838]
general/overlay/init[10-20]
general/overlay/init[104-115]
general/overlay/init[156-167]

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 settings carry-over path can erase `rootfs_data` before init checks whether mis-sized NOR flash aliases it onto boot and firmware data.
## Fix Focus Areas
- general/overlay/init[156-167]
## Recommended Fix
Compute `aliased` once with `flash_aliased` before any carry-over operation. Call `overlay_carry_in` only when the flash is neither NAND nor aliased, and reuse the cached alias result in the existing branch so aliased flash skips both restoration and erasure.

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



Informational

9. A failed settings restore is never reported ✓ Resolved
Description
overlay_carry_in erases rootfs_data with flash_eraseall -j before it extracts the tarball, which
lives only in tmpfs. If mount -t jffs2 fails or gunzip | tar -x fails, it prints nothing. The
blob is already gone, so the camera boots on defaults with nothing in the console or kmsg to say
why, unlike the existing branches, which write their reason to /dev/kmsg.
Code

general/overlay/init[R113-118]

+	flash_eraseall -j "$chr"
+	if mount -t jffs2 "$blk" /mnt; then
+		gunzip -c /overlay/settings.tgz | tar -x -C /mnt && echo "Settings restored."
+		sync
+		umount /mnt
+	fi
Evidence
Only the success path prints anything ("Settings restored."). Neither the mount failure nor the
extraction failure has an else branch, although the erase above has already destroyed the only copy
on flash.

general/overlay/init[110-120]
general/overlay/init[175-180]

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

## Issue description
When the carried-over settings cannot be restored after rootfs_data has been erased, init says nothing, so a camera silently coming up on defaults cannot be diagnosed.
## Fix Focus Areas
- general/overlay/init[113-119]
## Recommended Fix
Add else branches for the jffs2 mount failure and for the gunzip/tar failure that echo a message and write `<3>init: ...` to /dev/kmsg, as the existing overlay branches do.

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


10. CI Telegram upload stops for these boards ✓ Resolved
Description
REPACK_NOR_SPLIT puts a second openipc*nor* archive into output/images, so in build.yml
NORFW=$(find output/images -name openipc*nor*) expands to two paths. [ -e ${NORFW} ] then fails
with too many arguments, NORFW is never exported, and the env.NORFW step quietly skips the NOR
image upload for all four gk7205v200/v300 boards.
Code

Makefile[R365-366]

+	cd $(TARGET)/images && tar -czf openipc.$(BR2_OPENIPC_SOC_MODEL)-nor-$(BR2_OPENIPC_VARIANT)-split.tgz \
+		firmware.bin.$(BR2_OPENIPC_SOC_MODEL).md5sum firmware.bin.$(BR2_OPENIPC_SOC_MODEL)
Evidence
The build step expects find to return exactly one file. With the new -split.tgz next to the plain
package, the unquoted test gets two operands and fails, and the Telegram step only runs when
env.NORFW is set.

.github/workflows/build.yml[479-482]
.github/workflows/build.yml[620-640]
Makefile[361-368]

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 new -split.tgz makes `find output/images -name openipc*nor*` return two files, so the NORFW test fails and the NOR artifact upload step is skipped.
## Fix Focus Areas
- .github/workflows/build.yml[479-482]
## Recommended Fix
Use `NORFW=$(find output/images -name 'openipc*nor*' ! -name '*-split.tgz' | head -1)` and test it with `[ -n "$NORFW" ] && [ -e "$NORFW" ]`. If the split archive should be uploaded as well, handle it separately.

ⓘ 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 general/overlay/usr/sbin/sysupgrade
Comment thread general/overlay/usr/sbin/sysupgrade
Comment thread general/overlay/usr/sbin/sysupgrade Outdated
Comment thread general/overlay/init Outdated
Comment thread general/overlay/init Outdated
Comment thread general/overlay/usr/sbin/sysupgrade
Comment thread general/overlay/usr/sbin/sysupgrade Outdated
Comment thread general/overlay/init Outdated
From review of the split-layout upgrade:

sysupgrade
- The FIT's SoC, bytes past the squashfs, and settings too big for what
  the image leaves are now refused before the RAM pivot, where a refusal
  still costs no reboot. The writer keeps its own checks.
- A camera on the split layout takes only a split firmware.bin: any
  other combined image used to fall through to a whole-partition write
  over "firmware".
- --channel/--build resolve the plain package from the manifest; a
  camera whose bootloader boots the layout now fetches the -split one
  beside it, as the default URL already did. The manifest itself keeps
  listing only the plain package, which older cameras install from.

/init
- The carry-over runs only after flash_aliased says the chip is what the
  kernel thinks, and is skipped on an aliased one.
- Nothing is erased until the archive is read whole and lists clean. A
  short read or no RAM keeps the blob for the next boot and boots on a
  RAM overlay; a damaged archive is reported and left to the usual
  mount. Every failure goes to the console and /dev/kmsg.

CI: the -split package made `find openipc*nor*` return two paths, so
the NOR upload step skipped; the plain package is picked by name.

Verified on GK7205V200 and GK7205V300 with the images built from this
tree, using the sysupgrade inside them: fixed slots to split and split
to split carry settings ("Settings restored."), -n comes up on
defaults ("Clearing settings after an upgrade...").
@widgetii
widgetii merged commit 6fd638e into master Oct 17, 2026
135 of 136 checks passed
@widgetii
widgetii deleted the nor/fit-split branch October 17, 2026 12:57
widgetii added a commit that referenced this pull request Oct 17, 2026
Their kernels already carry mtdsplit and the split options (the
gk7205v200 family's config fragments, #2617), but only the gk7205v200
and gk7205v300 defconfigs ran post-image.sh, so these two produced no
firmware.bin and no -split package. They now do, beside the unchanged
plain package. OpenIPC/u-boot#19 enables the layout in their
bootloaders; until a camera runs one, sysupgrade keeps it on the plain
package.

Local builds: gk7202v300_lite firmware.bin 7040KB/7616KB, gk7605v100_lite
7040KB/7616KB; each FIT is described "OpenIPC <soc>".

Build-tested only: no gk7202v300 or gk7605v100 camera was run.
widgetii added a commit to OpenIPC/wiki that referenced this pull request Oct 17, 2026
…0 family (#605)

A new page for the split NOR layout on GK7205V200, GK7205V300, GK7202V300
and GK7605V100 (OpenIPC/linux#96, OpenIPC/u-boot#18 and #19,
OpenIPC/firmware#2617 and #2621):
- what the layout is, and how mtdsplit divides it at boot;
- what it needs: the u-boot-<soc>-nor.bin bootloader and the -split
  package;
- how to tell which layout a camera runs;
- moving a camera over: the bootloader, then sysupgrade -k -r;
- how sysupgrade carries the settings, -n, and what it refuses;
- writing the image from U-Boot, and going back to fixed slots.

The console lines quoted are from the lab GK7205V200 and GK7205V300.
Linked from the README, install-goke and sysupgrade.
widgetii added a commit to OpenIPC/defib that referenced this pull request Oct 17, 2026
…family (#154)

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
read`s 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.
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant