From 9e23fadf7617aa624ceaabc580f42ae2b83cd70f Mon Sep 17 00:00:00 2001 From: Dmitry Ilyin <6576495+widgetii@users.noreply.github.com> Date: Sun, 4 Oct 2026 19:18:04 +0300 Subject: [PATCH] Erase a NAND camera's UBI partition by name, so chips bigger than 128 MiB install too The UBI-only NAND install erased a fixed 0x7f00000 from 0x100000, which is the end of a 128 MiB chip. The partition is -(ubi) and runs to the end of whatever chip there is, so on a bigger one stale blocks were left behind, which UBI counts as corrupted PEBs when it attaches. - The Linux step now erases with `nand erase.part ubi`, which the u-boot-xmedia NAND build carries (OpenIPC/u-boot-xmedia#12) and the U-Boot step installs first. - The full-flash image, written from whatever U-Boot the camera has, erases with `nand erase.chip`. - Both keep write.trimffs. Also gofmt on catalogue.go, which #392 left unformatted. --- service/internal/catalogue/catalogue.go | 10 ++--- service/internal/wizard/camera.go | 10 ++--- service/internal/wizard/lines.go | 39 +++++++++++++++---- .../internal/wizard/testdata/documents.json | 14 +++---- service/internal/wizard/wizard_test.go | 8 ++-- 5 files changed, 53 insertions(+), 28 deletions(-) diff --git a/service/internal/catalogue/catalogue.go b/service/internal/catalogue/catalogue.go index b64df776..999aa20a 100644 --- a/service/internal/catalogue/catalogue.go +++ b/service/internal/catalogue/catalogue.go @@ -27,14 +27,14 @@ type SoC struct { // device rather than a raw partition at 0x100000. Empty everywhere else, // which keeps the split layout (boot, env, kernel, ubi) and its `run // uknand; run urnand` for every SoC that still boots that way. - UBootNANDFilename string `yaml:"uboot_nand_filename"` + UBootNANDFilename string `yaml:"uboot_nand_filename"` // NANDBoard is the build name upstream publishes this SoC's NAND // firmware under, when that is not the NOR one: GK7205V510 has a NOR // build of its own, but its NAND firmware is the GK7205V500 build. - NANDBoard string `yaml:"nand_board"` - LinuxFilename string `yaml:"linux_filename"` - LoadAddress string `yaml:"load_address"` - Vendor *Vendor `yaml:"-"` + NANDBoard string `yaml:"nand_board"` + LinuxFilename string `yaml:"linux_filename"` + LoadAddress string `yaml:"load_address"` + Vendor *Vendor `yaml:"-"` } type Vendor struct { diff --git a/service/internal/wizard/camera.go b/service/internal/wizard/camera.go index e68cd89a..e4a1d174 100644 --- a/service/internal/wizard/camera.go +++ b/service/internal/wizard/camera.go @@ -45,13 +45,11 @@ const ( // mtdparts=:768k(boot),256k(env),-(ubi). The kernel is a FIT // volume inside the one UBI device, so there is no raw kernel partition, no // uknand/urnand pair and no `run setnand` -- the bootloader's own mtdparts is -// already the layout, and rootfs.ubi. (volumes kernel, rootfs and -// rootfs_data) is the only file an install writes. The UBI region runs to the -// end of the 128 MiB chip the rest of the NAND page assumes. +// already the layout, and rootfs.ubi. (volumes rootfs, with the kernel +// in its /boot, and rootfs_data) is the only file an install writes. The UBI region runs to the +// end of the chip, whatever its size: it is erased by name (ubiFlash). const ( - ubiBootSize = "0xc0000" - ubiOffset = "0x100000" - ubiRegionSize = "0x7f00000" + ubiBootSize = "0xc0000" ) type norTable struct{ kernelOffset, kernelMax, rootfsOffset, rootfsMax, overlayOffset int64 } diff --git a/service/internal/wizard/lines.go b/service/internal/wizard/lines.go index 09946779..467fee96 100644 --- a/service/internal/wizard/lines.go +++ b/service/internal/wizard/lines.go @@ -85,6 +85,24 @@ func (c *camera) guardedWrite(transfer, offset, eraseSize, write, writeSize stri " " + write + " " + c.soc.LoadAddress + " " + offset + " " + writeSize } +// ubiFlash is guardedWrite for the UBI-only layout, where nothing on the +// flash has a size the wizard can know: the chip may be 128 MiB or bigger. +// The UBI partition is erased by name (`nand erase.part ubi`, which the +// u-boot-xmedia NAND build carries and the U-Boot step installs first), so +// to the end of the chip whatever its size; blocks left with stale data past +// the image would be corrupted PEBs to UBI. A full image, written from +// whatever U-Boot the camera has, erases the whole chip instead. +func (c *camera) ubiFlash(transfer string, whole bool) string { + // The partition by name for the write too, so it lands where the erase + // was: both resolve from the bootloader's mtdparts. + erase, offset := "nand erase.part ubi", "ubi" + if whole { + erase, offset = "nand erase.chip", "0x0" + } + return transfer + " && " + erase + " && nand " + c.writeCmd() + " " + c.soc.LoadAddress + " " + + offset + " ${filesize}" +} + func (c *camera) writeSizeFor(fixed string) string { if c.flashType == "nand" { return fixed @@ -129,6 +147,17 @@ func (c *camera) flashingEverything() []string { // The full image holds the UBI image, so on the UBI-only layout it goes // on with write.trimffs like rootfs.ubi does on its own. w := c.writeCmd() + if c.ubi() { + if c.sdWifi() { + text = append(text, c.ubiFlash("fatload mmc 0:1 "+la+" "+fw, true)) + } else { + text = append(text, + c.ubiFlash("tftpboot "+la+" "+fw, true), + "# if there is no tftpboot but tftp then run this instead", + c.ubiFlash("tftp "+la+" "+fw, true)) + } + return append(text, "reset") + } if c.sdWifi() { text = append(text, c.guardedWrite("fatload mmc 0:1 "+la+" "+fw, "0x0", c.flashSizeHex(), w, "${filesize}")) } else { @@ -179,17 +208,13 @@ func (c *camera) flashingLinux() []string { // staging blank: the write is ${filesize} long, and blanking the // region would be 127 MiB of RAM the camera may not have. ubi := "rootfs.ubi." + c.board - // The UBI partition runs to the end of the chip (-(ubi)); the erase - // below covers a 128 MiB one, the size the wizard installs for. - text = append(text, "# erases a 128 MiB chip: on a 256 MiB one use 0xff00000 instead of 0x7f00000") if c.sdWifi() { - text = append(text, c.guardedWrite("fatload mmc 0:1 "+la+" "+ubi, - ubiOffset, ubiRegionSize, c.writeCmd(), "${filesize}"), "") + text = append(text, c.ubiFlash("fatload mmc 0:1 "+la+" "+ubi, false), "") } else { text = append(text, - c.guardedWrite("tftpboot "+la+" "+ubi, ubiOffset, ubiRegionSize, c.writeCmd(), "${filesize}"), + c.ubiFlash("tftpboot "+la+" "+ubi, false), "# if there is no tftpboot but tftp then run this instead", - c.guardedWrite("tftp "+la+" "+ubi, ubiOffset, ubiRegionSize, c.writeCmd(), "${filesize}")) + c.ubiFlash("tftp "+la+" "+ubi, false)) } return append(text, "reset") } diff --git a/service/internal/wizard/testdata/documents.json b/service/internal/wizard/testdata/documents.json index c5d34499..941d3156 100644 --- a/service/internal/wizard/testdata/documents.json +++ b/service/internal/wizard/testdata/documents.json @@ -31,9 +31,9 @@ "gk7205v200": "943c32e1c38a82a246c0154c57c5f775375e82b85dae6dd42419564eb5f3e1dd", "gk7205v210": "aeff55cc268f50246c91a2f2ace7d0d74e3d9d228c2ea6b0bca647b63b0ab211", "gk7205v300": "b7aab36c9cfa89b7cb1eaa37b4fab765712176af3f29328500a45dd92e3dde1a", - "gk7205v500": "4e4973d6bb2b5282cdb521bf734dd5a070345516b76876519a04ef988594c026", - "gk7205v510": "63c47f96eb0bd8a2a3fbfffcd2c46bfa36a1fed98682623f97c891fe07a0f3e3", - "gk7205v530": "cbb8d2771a0b24441b7f4143aab448ac2798265024accccee2b1ed3bb1513bdf", + "gk7205v500": "c171f65a4969eb5b2f6ab166fee9d0f7ee298bde9be62ef7aa2ab911510eaab5", + "gk7205v510": "06c5384f22fbb78658586ead784d90e31bf493089744e63ad0285574d7fc9940", + "gk7205v530": "8b5acae406bce13ac9a76604735036074a0785d2698187e82e6b535bb81cd619", "gk7605v100": "d20d539bce8fc4f9eb80cfc4d02d816a8c1f2aca7bc66e61d6cf7dfd4983839c", "gm8135": "c367db7ad5b32a232b0ef6e9f301ff91763a38b2c6dc8ee8df3d574aaa92d547", "gm8136": "8f491dca72bc63a626a015bdbdd4b58a74f2d0280ad676a0f82f994bce964fef", @@ -45,16 +45,16 @@ "hi3516cv300": "cc7e4e4a7d03f8683df827855157ad345268c982fe8bde2b3438851b965540df", "hi3516cv500": "2b8926b2eff46757ecc7bb69c3150643dbd7ce7522ff7f57b8019584ab8d4a1b", "hi3516dv100": "013051a4938344031a5fb25ffad178d18332b9012488c023cb2a1f9ec23e240c", - "hi3516dv200": "d481e0adc36650363ef3350b056252ade986e4a87d7b536c461ded7badf7b019", + "hi3516dv200": "3ce54093ed77459e8632e1acbc269a5cc14704d680cc263484e6242f731efbc2", "hi3516dv300": "e64903d05af789169ddafd9d2d11db2abc9e97e1879edbf0957e4059c90bc69f", "hi3516ev100": "bc30ca2a98b204e48cca23a066be0894a79cb18133db40cc7f47212eac949da9", - "hi3516ev200": "b0e1b515ac53390b20f17238d3b4f9cb09621b10c3e2572779c3e1f2b3e60b1f", - "hi3516ev300": "a32163f61c32b36028757e4bd1a443cda6c1e74385ac79b8002a161ea7b02935", + "hi3516ev200": "243225a023f6a5245601d2a08f852a89a96e5dcb2b5f758c8db9487dd1f906ed", + "hi3516ev300": "a02ccc1d83f76727ba80ed3b17f5b0854ff14e431e8cda1587f29beefd544a11", "hi3518cv100": "b08c8580dd3e18f20a5967005733425911b53430b05017874798b11fa2909868", "hi3518ev100": "4533443ab52a57946bab06de2678a5e0b0a285b05a531023d24ef568b4cbe4de", "hi3518ev200": "6f3aabd0af3d4f4f530c9eb525156334c7d4254765b8dba19d89e66df9b7fb04", "hi3518ev201": "73ed154710b0cab632f8edfd5089f6632bea1f63045e8ef17b60754f64abddf4", - "hi3518ev300": "4d16f1710098b62d3828615b13ff8146db34d37fd4d95835b7b35bca1a99b1f9", + "hi3518ev300": "a0071d3562a3c5af2f2c893092e57af6b84330b7a8b4432f019e8259ede9ad6d", "hi3519v101": "23466502aa228417ef33ff45ce97230d337c94a6a3460619796a7aa19182584d", "hi3520dv100": "4ea373391fe243d60d590b011969a53c4918051d0c0a94ed6241aa2c73849f0b", "hi3520dv200": "782f9cb791ab9084424ccae5d195d38b65209d551b726db11c40996f66eead24", diff --git a/service/internal/wizard/wizard_test.go b/service/internal/wizard/wizard_test.go index 7e77eba5..b0186c57 100644 --- a/service/internal/wizard/wizard_test.go +++ b/service/internal/wizard/wizard_test.go @@ -257,12 +257,14 @@ func TestUBINandLines(t *testing.T) { t.Errorf("U-Boot block:\n%s", uboot) } linux := block(c, "flashing_linux") - if !strings.Contains(linux, "rootfs.ubi.hi3516ev300 && nand erase 0x100000 0x7f00000 && "+ - "nand write.trimffs 0x42000000 0x100000 ${filesize}") { + // Erased by name, to the end of the chip whatever its size. + if !strings.Contains(linux, "rootfs.ubi.hi3516ev300 && nand erase.part ubi && "+ + "nand write.trimffs 0x42000000 ubi ${filesize}") || strings.Contains(linux, "0x7f00000") { t.Errorf("Linux block:\n%s", linux) } full := block(c, "flashing_everything") - if !strings.Contains(full, "nand write.trimffs 0x42000000 0x0 ${filesize}") || strings.Contains(full, "nand write 0x") { + if !strings.Contains(full, "&& nand erase.chip && nand write.trimffs 0x42000000 0x0 ${filesize}") || + strings.Contains(full, "nand write 0x") || strings.Contains(full, "nand erase 0x0") { t.Errorf("full image block:\n%s", full) } for name := range c["blocks"].(map[string]any) {