Skip to content

sigmastar: OpenIPC's common layer and openipc-hisilicon's NAND layout - #109

Merged
dimerr merged 7 commits into
openipc-sigmastarfrom
sigmastar/openipc-layout
Nov 7, 2026
Merged

dimerr merged 7 commits into
openipc-sigmastarfrom
sigmastar/openipc-layout

Conversation

@dimerr

@dimerr dimerr commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

This brings openipc-sigmastar in line with the other vendor branches. It follows #107.

Common layer. common/openipc.c, common/Kconfig and the default environment are now openipc-ingenic's, which follow openipc-hisilicon's. That brings:

  • the split NOR layout (CONFIG_OPENIPC_NOR_SPLIT);
  • FAT recovery from a partition or a whole disk;
  • the boot-limit failsafe and the saved environment's migrations;
  • on NOR, fwfile=firmware.bin.<soc>, and an mtdslite that resets kernaddr.

OPENIPC_SPI_NAND now includes our CONFIG_NAND_MS_SPINAND. The UBI marker is read from the first good eraseblock.

NOR. The partitions are unchanged: 256k(boot),64k(env). The images now end where their data does; they are no longer padded with 0xFF to 256 KiB.

SPI NAND, openipc-hisilicon's layout.

  • Partitions: 768k(boot),256k(env),-(ubi). The environment is at 0xC0000: 128 KiB in the 256 KiB partition, so one bad block there doesn't stop saveenv. openipc-hisilicon uses 256 KiB, so the firmware's fw_env.config for these cameras needs the 128 KiB size.
  • Firmware: one UBI device. Its UBIFS rootfs volume holds the kernel as /boot/fitImage or /boot/uImage, and rootfs_data takes the rest.
  • Boot: root=ubi0:rootfs rootfstype=ubifs ubi.mtd=2,2048.
  • Recovery (ur, or rootfs.ubifs.<soc>.img on an SD card) installs rootfs.ubifs.<soc>.
  • nand_config is openipc-hisilicon's. The per-die NAND fragments and the separate kernel volume are gone.

Each die's vendor boot stages in the 768 KiB boot partition, one copy each:

Die Layout
infinity6, 6b0, 6e, infinity2m SNI and PNI in block 0, IPL in 1, IPL_CUST in 2, U-Boot in 3-5. SNI byte 0x2E tells infinity6's IPL_CUST where to start looking for U-Boot.
infinity6c The CIS in blocks 0 and 1 (its IPL reads a copy past block 0), IPL in 2, IPL_CUST in 3, U-Boot in 4-5.
Ifliegen CIS, IPL, IPL_CUST and TF-A in blocks 0-3, U-Boot in 4-5.
Iford Its IPL finds each stage by name at any 2 KiB page, which is what lets the 338 KB OP-TEE fit; U-Boot ends near 0xB8000.

Ahead of the other vendor branches (from Qodo's review here; they follow later):

  • ubwrite writes only an image that fits the boot partition. It checks the size before erasing, so a failed run ub no longer leaves a board with no IPL, and it writes into the partition by name, so a bad block can't push U-Boot into env.
  • NOR SD/USB recovery writes only .img files whose name carries this SoC as a word: a card with several cameras' images flashes only this one's. NAND recovery checks that the image fits the free RAM.
  • A saved altbootcmd in the retired form is migrated before recovery runs, so a script.txt can't run the old one.
  • What remains: a bad block in boot blocks 1-5 still moves the stages off the blocks the PNI names. One copy of each stage is all 768 KiB holds.

Breaking for NAND cameras: this is not OpenIPC/u-boot-sigmastar's NAND layout, which puts UBI at 0x240000 with a kernel volume and a squashfs rootfs. A camera moving to this U-Boot needs its NAND firmware packaged as rootfs.ubifs.<soc>, with the kernel in /boot, as HiSilicon's is. That package doesn't exist yet on the OpenIPC/firmware side.

Tested, in QEMU only:

  • All 52 images, NOR and NAND, pass CI's smoke test locally: two boots, with the environment kept, each on its own machine.
  • Full NAND flow from a blank flash: the scan finds no UBI, recovery installs rootfs.ubifs over TFTP, and the kernel boots with root=ubi0:rootfs; again after saveenv and reset:
    • ssc325de, ssc337de, ssc338q: to login:, with their published firmware's kernel and rootfs repacked as UBIFS (kernel in /boot);
    • ssc029a, ssc034a: to the root mount, with SDK kernels; ssd202d: to a shell, with the infinity2m SDK kernel;
    • ssc377: to login: with an SDK kernel. That kernel has no overlayfs, so the rootfs ends up remounted read-write and is left dirty. The next scan then can't mount it and recovery reinstalls, as HiSilicon's U-Boot would.
  • ssc337de also installs from an SD card and boots to login:.

Merge this before the CI PR, which needs these 768 KiB NAND images.

common/openipc.c, common/Kconfig and common/Makefile are openipc-ingenic's,
which keep openipc-hisilicon's in step and take the SPI NAND path by
OPENIPC_SPI_NAND: the split NOR layout (CONFIG_OPENIPC_NOR_SPLIT), the
recovery from a FAT partition or a whole-disk FAT, the NAND scan of the
UBIFS rootfs and its /boot kernel, the boot-limit failsafe and the saved
environment's migrations. OPENIPC_SPI_NAND takes CONFIG_NAND_MS_SPINAND
too, and the UBI marker is read from the first good eraseblock, which a
corrected read (-EUCLEAN) still gives. CONFIG_OPENIPC_NAND_KERNEL_VOLUME,
the kernel in a UBI volume of its own, goes.
768k(boot),256k(env),-(ubi): the environment at 0xC0000 (256 KiB, range
256 KiB), one UBI device from 0x100000 whose UBIFS rootfs volume holds
the kernel as /boot/fitImage or /boot/uImage, rootfs_data on the rest,
root=ubi0:rootfs rootfstype=ubifs ubi.mtd=2,2048; ur installs
rootfs.ubifs.<soc> sized to the image, keeping rootfs_data. nand_config
is openipc-hisilicon's, with UBIFS and FIT; the per-die NAND fragments
go. The NOR environment takes the split layout's fwupd/fwwrite,
fwfile=firmware.bin.<soc>, and mtdslite resetting kernaddr, as the
others.

Not OpenIPC/u-boot-sigmastar's NAND layout (UBI at 0x240000, a kernel
volume and a squashfs rootfs): a camera moving over takes the firmware's
rootfs.ubifs too, as HiSilicon's do.

qemu: ssc325de, ssc337de, ssc338q from blank through TFTP and SD
recovery to login, again after saveenv and reset; ssc377 with mstar-06's
Maruko kernel.
One copy of each stage, a block each where the IPL wants blocks:
- infinity6, 6b0, 6e, infinity2m: SNI and PNI in block 0 (BL0PBA 1,
  BL1PBA 0, SNI byte 0x2E 2, where infinity6's IPL_CUST starts its search
  for U-Boot), IPL in 1, IPL_CUST in 2, U-Boot in 3-5.
- infinity6c: the CIS in blocks 0 and 1 (its IPL reads a copy past block
  0), IPL in 2, IPL_CUST in 3, U-Boot in 4-5.
- Ifliegen: the CIS, IPL, IPL_CUST, TF-A's SP_MIN in blocks 0-3, U-Boot
  in 4-5.
- Iford: its IPL takes every stage by name at any 2 KiB page, which lets
  the 338 KB OP-TEE in: IPL from 0x20000, IPL_CUST, OP-TEE and U-Boot
  each from the next page, ending near 0xB8000.

NOR and NAND images end where their data does, as OpenIPC's others: no
0xFF padding to the partition.

qemu: every image, NOR and NAND, two boots to the autoboot prompt with
the environment kept, on its own machine.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Align SigmaStar boot and recovery with the OpenIPC NAND layout

✨ Enhancement ⚙️ Configuration changes 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Align SigmaStar boot and recovery with the shared OpenIPC layer, including split NOR support.
• Standardize SPI NAND on a 768 KiB boot partition and UBIFS rootfs containing the kernel.
• Repack boot stages per die; existing NAND firmware needs migration, with validation limited to
 QEMU.
Diagram

graph TD
  B["Build configuration"] --> P["Image packer"] --> F["NAND layout"] --> S{"Rootfs valid?"} -->|yes| K["Boot kernel"]
  S -->|no| R["Recovery image"] --> U["UBIFS installer"] --> F
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Retain the legacy NAND format alongside the new layout
  • ➕ Existing NAND firmware could continue booting during migration.
  • ➖ Two partition maps and rootfs formats would complicate scanning, recovery, and support.
2. Stage NAND deployment until matching firmware is published
  • ➕ Avoids deploying a bootloader that cannot boot currently packaged NAND firmware.
  • ➖ Delays adoption of the shared layout and the CI work that depends on its images.

Recommendation: The shared HiSilicon-style layout is a coherent long-term choice and removes per-die firmware-layout divergence. Keep the breaking incompatibility prominent, coordinate release of rootfs.ubifs packages before NAND deployment, and treat QEMU validation as insufficient evidence of silicon compatibility.

Files changed (8) +879 / -479

Enhancement (2) +678 / -304
openipc.cUnify firmware scanning, recovery, and environment migration +515/-151

Unify firmware scanning, recovery, and environment migration

• Adds SigmaStar SPI NAND to the shared NAND path and scans its UBIFS rootfs for a kernel instead of expecting a separate volume. Extends NOR split-layout detection and CRC checks, supports FAT recovery media and validated NOR images, and keeps scan-derived environment changes in RAM.

common/openipc.c

sigmastar-image.pyPack die-specific boot chains into the 768 KiB partition +163/-153

Pack die-specific boot chains into the 768 KiB partition

• Rewrites NAND SNI and PNI records and places one copy of each boot stage in layouts suited to the individual dies, including Iford's page-aligned OP-TEE chain. Writes NOR and NAND images only through their last data byte instead of padding them to the partition size.

openipc/sigmastar-image.py

Documentation (1) +77 / -70
CLAUDE.mdDocument the unified NAND layout and boot-stage placement +77/-70

Document the unified NAND layout and boot-stage placement

• Replaces descriptions of vendor-specific NAND partitions with the 768 KiB boot, 256 KiB environment, and UBIFS layout. Documents die-specific stage placement, firmware incompatibility, and QEMU validation.

CLAUDE.md

Other (5) +124 / -105
build.shBuild NAND variants with one shared configuration +4/-6

Build NAND variants with one shared configuration

• Removes per-die NAND configuration fragments from the build commands and drops the infinity2m PNI-layout option. NAND targets now use the common nand_config fragment.

build.sh

KconfigReplace the kernel-volume option with NOR split detection +10/-8

Replace the kernel-volume option with NOR split detection

• Removes the option for a separate NAND kernel volume. Adds CONFIG_OPENIPC_NOR_SPLIT for boards whose kernels recognize a combined NOR firmware partition.

common/Kconfig

MakefileRespect SPL and TPL selection for the OpenIPC object +1/-1

Respect SPL and TPL selection for the OpenIPC object

• Changes the OpenIPC object selection to use the SPL/TPL-aware configuration symbol.

common/Makefile

openipc-common.hDefine shared NAND boot and NOR update environments +88/-78

Define shared NAND boot and NOR update environments

• Replaces die-specific NAND partition and squashfs boot settings with a UBIFS rootfs containing the kernel. Adds split-NOR firmware update commands, a firmware.bin.<soc> filename, and fixed-slot fallback behavior.

include/configs/openipc-common.h

nand_configSet the HiSilicon-style SPI NAND partition map +21/-12

Set the HiSilicon-style SPI NAND partition map

• Moves the environment to 0xC0000 and defines 768k(boot),256k(env),-(ubi). Enables UBIFS and FIT support and removes the separate-kernel-volume setting.

openipc/nand_config

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

qodo-free-for-open-source-projects Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Action required

1. One bad env block makes settings unsavable ✓ Resolved
Description
openipc/nand_config sets CONFIG_ENV_SIZE=0x40000 equal to CONFIG_ENV_RANGE=0x40000 (two 128
KiB blocks), so env/nand.c has no spare block to skip to. A single bad block in the env partition
(factory-marked or worn) makes saveenv fail and every boot fall back to the default environment,
which loses network settings and the boot-limit state.


Remediation recommended

2. Split NOR firmware boots with old arguments 🐞 Bug ≡ Correctness
Description
OPENIPC_NOR_SPLIT has no default or selection in the SigmaStar build fragments, so NOR builds omit
the new split-layout detection and boot-argument cleanup. When a split firmware image is installed,
the scan continues to pass fixed-slot root= and mtdparts= arguments instead of letting its
kernel use the split layout.
Code

common/Kconfig[R1031-1033]

+config OPENIPC_NOR_SPLIT
+	bool "OpenIPC: recognise the split NOR layout (uImage + squashfs in one partition)"
+	help
Evidence
The option is introduced without a default, while the shared NOR fragment and build path do not
select it. Both split detection and removal of fixed-slot boot arguments are conditional on that
option.

common/Kconfig[1031-1039]
openipc/openipc_config[1-8]
build.sh[45-64]
common/openipc.c[887-888]
include/configs/openipc-common.h[132-151]

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 NOR path is gated by a configuration option that no SigmaStar build enables.
## Fix Focus Areas
- common/Kconfig[1031-1039]
- openipc/openipc_config[1-8]
- build.sh[45-64]
## Recommended Fix
Enable the option in the fragments for targets whose kernels support the split layout, while leaving unsupported targets on fixed slots. Verify a generated NOR configuration contains the option.

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


3. Existing cameras miss split updates 🐞 Bug ≡ Correctness
Description
OPENIPC_FWUPD_LEGACY_CMD matches run mtdslite; run ur; run uk, but the pre-PR NOR default was
run ur; run uk. A camera retaining that saved default never satisfies the equality check in
firmware_scan(), so its update command continues to fetch only the fixed-slot pair rather than the
new whole-firmware file.
Code

include/configs/openipc-common.h[152]

+#define OPENIPC_FWUPD_LEGACY_CMD "run mtdslite; run ur; run uk"
Evidence
The removed NOR definition in the supplied diff is fwupd=run ur; run uk, whereas the new legacy
constant has an additional run mtdslite. Migration requires an exact strcmp, so it cannot match
the previously shipped default.

include/configs/openipc-common.h[149-165]
common/openipc.c[849-858]

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 saved-environment migration compares against a command introduced by this PR, not the NOR command existing cameras actually saved.
## Fix Focus Areas
- include/configs/openipc-common.h[149-152]
- common/openipc.c[849-858]
## Recommended Fix
Recognize the old `run ur; run uk` value and replace that exact unedited value with the split update command. Preserve the existing behavior of leaving customized commands alone.

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


4. Recovery scripts use stale update commands ✓ Resolved
Description
openipc_helper() runs removable-media recovery before firmware_scan() replaces legacy fwupd
and fwwrite values. If a saved environment has an old update command, a script.txt that invokes
it uses that command during recovery even after the legacy-value comparison is corrected; the
migration only takes effect afterward.

View review recommended (3)
5. A bad block in the boot area bricks NAND cameras ✓ Resolved
Description
The new 768 KiB boot image puts exactly one copy of each stage at a fixed block (IPL in 1, IPL_CUST
in 2, U-Boot in 3-5, PNI records with 0 backups), and ubwrite writes it with nand write, which
skips bad blocks and so shifts every later stage. With one bad block anywhere in blocks 1-5 the IPL
cannot find a stage at its PNI block, and U-Boot can spill into the env blocks at 0xC0000, which
were never erased. The old layout had a second boot copy as a fallback.

6. SD recovery flashes other SoCs' images ✓ Resolved
Description
recovery_images() passes every root-level regular .img file to recovery_write_img(), which
flashes the image at its uImage load address without checking CONFIG_PRODUCT_SOC or restricting
the destination to firmware partitions. When removable FAT media is present at boot, a card holding
images for multiple cameras can flash a foreign SoC’s kernel or rootfs, while an otherwise valid
image addressed to offset zero can replace U-Boot; later writes to the same destination win.

7. Large NAND recovery image can overwrite U-Boot ✓ Resolved
Description
The NAND recovery_write reads the whole rootfs.ubifs..img to CONFIG_SYS_LOAD_ADDR using only
its file size. Unlike the NOR image path and recovery_run_script, which this PR guards with
recovery_ram_room(), nothing checks that the file fits. A UBIFS image larger than the RAM between
0x21000000 and the relocated U-Boot/stack (about 46 MiB on 64 MiB parts) overwrites the running
bootloader during recovery.

Grey Divider

Tip of the day
💡 Did you know, you can hide the parts of a finding you never read, like the evidence or the agent prompt

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

- NOR SD/USB recovery writes only the *.img files whose name carries
  CONFIG_PRODUCT_SOC as a word between '.' or '-': a card holding several
  cameras' images flashes this one's alone (uImage.ssc337.img is not
  ssc337de's).
- NAND recovery reads rootfs.ubifs.<soc>.img only if it fits the RAM below
  the relocated U-Boot, as the NOR image and script.txt paths do.
- A saved altbootcmd of the retired form is migrated before recovery, so
  a script.txt that runs it gets the current one.

openipc-sigmastar only for now; the other vendor branches follow.
Reported by Qodo on #109.
- The environment is 128 KiB in the 256 KiB env partition: with
  CONFIG_ENV_SIZE equal to its range, one bad block there left saveenv
  nowhere to go and every boot on the default environment.
- ubwrite writes only an image that fits the 768 KiB boot partition,
  checked before it erases (a failed write after the erase left no
  IPL), and into the partition by name, so bad blocks cannot push it
  into env.

The firmware's fw_env.config for these cameras takes the 128 KiB size.
qemu ssc337de: an oversize ub refused with the boot intact; the env block
at 0xC0000 marked bad, saveenv to 0xE0000, loaded after reset.
Reported by Qodo on #109.
@dimerr
dimerr merged commit 42574c4 into openipc-sigmastar Nov 7, 2026
60 checks passed
@dimerr
dimerr deleted the sigmastar/openipc-layout branch November 7, 2026 17:52
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