Skip to content

ci: stop assembling the two NOR images their u-boot has no room for - #2461

Merged
openipc-ai merged 2 commits into
masterfrom
ci-drop-unassemblable-hisi-images
Sep 20, 2026
Merged

openipc-ai merged 2 commits into
masterfrom
ci-drop-unassemblable-hisi-images

Conversation

@openipc-ai

@openipc-ai openipc-ai commented Sep 20, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

The image workflow (run 35462750911) refused six images and went red:

hi3516cv6xx_ultimate: the FIT is 2752 KiB, the kernel partition is 2048 KiB   (x4 DDR binnings)
hi3519dv500_ultimate: the rootfs is 8820 KiB, the rootfs partition is 8192 KiB (x2)

That is the bounds check #2448 added, running for the first time — every
image run between it merging and this one was skipped. #2448 predicted it
in its own description. It is not a regression: it is the table disagreement
the published images already carried, now reported instead of shipped.

Two things the log does not say.

It assembled from a stale nightly. nightly-20260918-49908b5, because the
build had failed and the manifest never advanced. That is why cv6xx reports a
FIT overflow — that blob predates #2447's kernel trim.

Re-running on a fresh nightly does not clear it. Measured against the
current nightly with create_hisi's own arithmetic (FIT size = the big-endian
word at byte 4 rounded to 64 KiB; rootfs = bytes_used at superblock byte 40
rounded to 4 KiB):

hi3516cv6xx_lite      FIT 2048/2048 ok   rootfs 5088/5120 ok
hi3516cv6xx_ultimate  FIT 2048/2048 ok   rootfs 7096/5120  OVER by 1976 KiB
hi3519dv500_ultimate  FIT 5632/6144 ok   rootfs 8820/8192  OVER by  628 KiB

The error message changes; the failure does not.

The cause is that there is one boot binary per DDR binning, not one per part
size, and its compiled-in mtdparts is the same on an 8 MiB part and a 16 MiB
one. Decompressing the gzip member inside the shipped u-boots (offset 40128 for
cv610, 84768 for hi3519dv500) and running strings on the result:

cv610/cv608  256k(boot),64k(env),2048k(kernel),5120k(rootfs),7168k@0x50000(firmware),-(rootfs_data)
hi3519dv500  512k(boot),256k(env),6144k(kernel),8192k(rootfs),14336k@0xC0000(firmware),-(rootfs_data)

The cv6xx ultimate blob is 9152 KiB and the dv500 one is 14464 KiB — each
larger than the whole firmware partition, never mind the rootfs slot inside it.
BR2_OPENIPC_FLASH_SIZE="16" buys them nothing, because the rest of the chip
is rootfs_data. No trim closes a 1976 KiB gap, so until a u-boot ships whose
table matches a 16 MiB part there is nothing here to assemble.

So this emits cv6xx lite only and drops the dv500 loop, which has no lite
variant to fall back on. Both comments carry the partition numbers, so
restoring a loop is a two-line change once such a u-boot exists. Tracked
in #2460, which carries the tables, the measurements and what a fix needs.

#2447 fits both cv6xx lite slots exactly, and that image assembles and boots
today.

Stopping assembly is only half of it. image is a fixed tag and Upload
only adds or replaces the files a run produced, so dropping a target from the
loops leaves whatever it published last on the release for good. Six such
assets were still downloadable, all dated 2026-09-18 — the four cv610/cv608
ultimate images and both dv500 ones — and they are not merely stale: every one
predates #2448, so they carry the very layout it replaced, a FIT past the end
of the 2048 KiB kernel slot and a rootfs landing over rootfs_data. Withdrawing
the targets while leaving those files up would have left exactly the images
this PR exists to stop shipping. A step before Upload now deletes them by
name, tolerating an asset that is already absent so it is idempotent and never
reddens a run; a name comes off the list when its loop comes back. The .tgz for both variants still publishes from the build job, so
sysupgrade is unaffected: it splits the blob at the FIT boundary and writes
each half to its own partition, and check_combined_fits refuses an oversized
half rather than mis-landing it.

Hardware tested on

None, and none is needed for this one — it is CI machinery that only
selects what to assemble. It ships nothing to a camera; the opposite, it stops
publishing two .bin files that could not boot on the u-boot they are paired
with. Nothing that does reach a camera changes: the same build job publishes
the same .tgz for every variant it did before.

Evidence

Before — the six refusals, from run 35462750911:

##[error]hi3516cv6xx_ultimate: the FIT is 2752 KiB, the kernel partition is 2048 KiB
##[error]hi3516cv6xx_ultimate: the FIT is 2752 KiB, the kernel partition is 2048 KiB
##[error]hi3516cv6xx_ultimate: the FIT is 2752 KiB, the kernel partition is 2048 KiB
##[error]hi3516cv6xx_ultimate: the FIT is 2752 KiB, the kernel partition is 2048 KiB
##[error]hi3519dv500_ultimate: the rootfs is 8820 KiB, the rootfs partition is 8192 KiB
##[error]hi3519dv500_ultimate: the rootfs is 8820 KiB, the rootfs partition is 8192 KiB
##[error]one or more HiSilicon NOR images were refused (see above); the rest were assembled and will still be uploaded

The partition tables, read back out of the shipped boot binaries rather than
assumed:

$ tail -c +40129 boot-hi3516cv610-20s-nor.bin | gzip -dc | strings -n 20 | grep mtdparts=
mtdparts=${mtdids}:256k(boot),64k(env),2048k(kernel),5120k(rootfs),7168k@0x50000(firmware),-(rootfs_data)

$ tail -c +84769 boot-hi3519dv500-dmeb-nor.bin | gzip -dc | strings -n 20 | grep mtdparts=
mtdparts=512k(boot),256k(env),6144k(kernel),8192k(rootfs),14336k@0xC0000(firmware),-(rootfs_data)

After — create_hisi's measurement run against the current nightly blobs:

hi3516cv6xx_lite      (blob  7168 KiB, part  8192 KiB)  FIT 2048/2048 ok  rootfs 5088/5120 ok
hi3516cv6xx_ultimate  (blob  9152 KiB, part 16384 KiB)  FIT 2048/2048 ok  rootfs 7096/5120 OVER 1976
hi3519dv500_ultimate  (blob 14464 KiB, part 16384 KiB)  FIT 5632/6144 ok  rootfs 8820/8192 OVER  628

so after this change the job assembles the four cv6xx lite images and nothing
that it would have to refuse.

$ python3 .github/scripts/lint-workflow-shell.py
checked 60 run block(s)
all run blocks parse clean
$ python3 .github/scripts/lint-workflow-shell.py --self-test
self-test passed

Scope

  • No kernel patches under general/package/all-patches/linux/ (those go to OpenIPC/linux)
  • No files specific to a single retail camera model (those go to OpenIPC/builder)
  • No probing or bring-up tooling (that goes to OpenIPC/ipctool)
  • Nothing under general/overlay/ or in a shared load_<vendor> script hardcodes a value specific to my board
  • Package sources come from an OpenIPC repository, and any version bump keeps at least the specificity of the pin it replaces (a new package should pin a full 40-character SHA)
  • No LD_PRELOAD, and no binaries that cannot be rebuilt from source
  • New code is selected by a defconfig, so CI actually builds it

The bounds checks #2448 added ran for the first time on 2026-09-19 and
refused six images: hi3516cv6xx ultimate on all four DDR binnings, and
hi3519dv500 ultimate on both. That is not a regression #2448 introduced --
it is the table disagreement the published images already carried, now
reported instead of shipped -- but it leaves the job red on every run, and
re-running against a fresh nightly does not clear it.

That run assembled from nightly-20260918-49908b5, because the build had
failed and the manifest never advanced, so cv6xx reported a FIT overflow
from a blob predating #2447's kernel trim. Measured against the current
nightly with create_hisi's own arithmetic, the error changes but does not
go away:

  hi3516cv6xx_lite      FIT 2048/2048 ok   rootfs 5088/5120 ok
  hi3516cv6xx_ultimate  FIT 2048/2048 ok   rootfs 7096/5120  over by 1976 KiB
  hi3519dv500_ultimate  FIT 5632/6144 ok   rootfs 8820/8192  over by  628 KiB

The cause is that there is one boot binary per DDR binning, not one per
part size, and its compiled-in mtdparts is the same on an 8 MiB part and a
16 MiB one. Decompressing the gzip member inside the shipped u-boots
(offset 40128 for cv610, 84768 for hi3519dv500) gives:

  cv610/cv608  256k(boot),64k(env),2048k(kernel),5120k(rootfs),7168k@0x50000(firmware)
  hi3519dv500  512k(boot),256k(env),6144k(kernel),8192k(rootfs),14336k@0xC0000(firmware)

The cv6xx ultimate blob is 9152 KiB and the dv500 one 14464 KiB -- each
larger than the whole firmware partition, never mind the rootfs slot inside
it. FLASH_SIZE="16" buys them nothing, because the rest of the chip is
rootfs_data. No trim closes a 1976 KiB gap, so until a u-boot ships whose
table matches a 16 MiB part there is nothing to assemble.

So emit cv6xx lite only, and drop the dv500 loop, which has no lite variant
to fall back on. Both comments carry the partition numbers so restoring a
loop is a two-line change. #2447 fits both cv6xx lite slots exactly (2048 in
2048, 5088 in 5120) and that image assembles and boots today.

The .tgz for both variants still publishes from the build job, so
sysupgrade is unaffected -- it splits the blob at the FIT boundary and
writes each half to its own partition, and refuses an oversized half rather
than mis-landing it.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Stop assembling unsupported HiSilicon NOR images

🐞 Bug fix ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

AI Description

• Restricts Hi3516CV6xx NOR assembly to the bootloader-compatible lite variant.
• Stops assembling Hi3519DV500 images that exceed U-Boot partition limits.
• Documents partition constraints and conditions for restoring excluded images.
Diagram

graph TD
  A["Image Workflow"] --> B{"Target Variant"} -->|"cv6xx lite"| C["Bounds Check"] --> D["NOR Output"]
  B -->|"cv6xx ultimate"| E["Skip Assembly"]
  B -->|"dv500 ultimate"| E
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Dynamically skip failed bounds checks
  • ➕ Automatically adapts if future firmware becomes small enough to fit.
  • ➕ Retains all variant loops without maintaining a static allowlist.
  • ➖ Can silently omit expected release artifacts unless separately reported.
  • ➖ Size reductions do not resolve the underlying mismatch between flash size and U-Boot partitions.
2. Publish 16 MiB-specific U-Boot artifacts
  • ➕ Restores combined ultimate images with partition tables matching their physical flash.
  • ➕ Fixes the underlying boot layout rather than changing CI selection.
  • ➖ Requires bootloader changes, hardware validation, and new upstream artifacts.
  • ➖ Cannot immediately restore DV500 if no suitable layout is available.

Recommendation: Use the PR's explicit exclusions now because the current bootloaders cannot address the space occupied by either ultimate image, and failing every workflow run provides no usable artifact. The durable follow-up is publishing dedicated 16 MiB U-Boot builds, after which the documented loops and layout entries can be restored.

Files changed (1) +19 / -11

Bug fix (1) +19 / -11
image.ymlExclude unassemblable HiSilicon ultimate NOR images +19/-11

Exclude unassemblable HiSilicon ultimate NOR images

• Removes the Hi3519DV500 layout and assembly loop, and limits Hi3516CV6xx assembly to lite images. Adds measured U-Boot partition constraints and restoration guidance for both excluded ultimate variants.

.github/workflows/image.yml

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

qodo-free-for-open-source-projects Bot commented Sep 20, 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. Unsafe images remain downloadable ✓ Resolved 🐞 Bug ≡ Correctness
Description
The reduced variant loop and removed Hi3519 assembly loop stop creating those files, while the
Upload step sends only target/*.bin to the existing fixed image release without deleting assets
omitted from the new run. Once an earlier run has published these ultimate images, subsequent runs
leave those stale files on the release where users can continue downloading the images this change
intends to withdraw.
Code

.github/workflows/image.yml[274]

+            for variant in lite; do
Evidence
The current branch produces only Hi3516CV6xx lite images and explicitly assembles no Hi3519DV500
image, but the upload still targets the persistent image tag with only the files currently present
in target/; no workflow step removes assets that prior runs attached under the discontinued names.

.github/workflows/image.yml[274-289]
.github/workflows/image.yml[301-309]

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 workflow stops generating the unsupported ultimate images but does not remove copies already attached to the persistent `image` release, so those unsafe files remain downloadable.
## Fix Focus Areas
- .github/workflows/image.yml[274-289]
- .github/workflows/image.yml[301-309]
## Recommended Fix
Before uploading the newly assembled files, explicitly delete the four withdrawn Hi3516CV6xx ultimate assets and the two withdrawn Hi3519DV500 assets from the `image` release, tolerating assets that are already absent. Keep this cleanup active on later runs so stale copies cannot reappear unnoticed.

ⓘ 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 turn on the rule miner and Qodo learns your standards from review history

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread .github/workflows/image.yml
image is a fixed tag and Upload only adds or replaces the files a run
produced, so dropping a target from the assembly loops leaves whatever it
published last sitting on the release for good. Six such assets were still
downloadable, all dated 2026-09-18: the four hi3516cv610/cv608 ultimate
images and both hi3519dv500 ones.

They are not merely stale. They were assembled before #2448 taught
create_hisi to split the blob at the FIT boundary and measure each half
against the partition it goes into, so they carry the layout that PR
replaced -- a FIT running past the end of the kernel slot and a rootfs
written over rootfs_data. Withdrawing the images from the loops without
withdrawing them from the release would have left exactly the files this
change exists to stop shipping.

Delete them by name before Upload, tolerating an asset that is already
absent so the step is idempotent and never fails a run. Drop a name from
the list when its loop comes back (#2460).
@openipc-ai
openipc-ai merged commit f07c206 into master Sep 20, 2026
22 checks passed
@openipc-ai
openipc-ai deleted the ci-drop-unassemblable-hisi-images branch September 20, 2026 06:17
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