diff --git a/board/xmedia/xm72050200/board.c b/board/xmedia/xm72050200/board.c index 1788b96b37b1..232abb248a3f 100755 --- a/board/xmedia/xm72050200/board.c +++ b/board/xmedia/xm72050200/board.c @@ -279,11 +279,13 @@ void clear_update_flag(int update_flag) int misc_init_r(void) { + /* Before openipc_helper(): a FIT on the split NOR layout carries + * hashes, and firmware_scan() drops this for it. */ + env_set("verify", "n"); openipc_helper(); #ifdef CONFIG_RANDOM_ETHADDR random_init_r(); #endif - env_set("verify", "n"); #ifdef CFG_MMU_HANDLEOK dcache_stop(); diff --git a/board/xmedia/xm72050300/board.c b/board/xmedia/xm72050300/board.c index bc4fe6f4bde6..1d38813606a1 100755 --- a/board/xmedia/xm72050300/board.c +++ b/board/xmedia/xm72050300/board.c @@ -278,11 +278,13 @@ void clear_update_flag(int update_flag) int misc_init_r(void) { + /* Before openipc_helper(): a FIT on the split NOR layout carries + * hashes, and firmware_scan() drops this for it. */ + env_set("verify", "n"); openipc_helper(); #ifdef CONFIG_RANDOM_ETHADDR random_init_r(); #endif - env_set("verify", "n"); #ifdef CFG_MMU_HANDLEOK dcache_stop(); diff --git a/common/Kconfig b/common/Kconfig index 6e69bb5b0489..3bbaaf8080c8 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1060,3 +1060,13 @@ config PRODUCT_SOCMODEL Optional board/binning model exposed as 'socmodel=' in the default environment (e.g. hi3516cv610 DDR binnings). +config OPENIPC_NOR_FIT_SPLIT + bool "OpenIPC: boot the split NOR layout (FIT + squashfs in one partition)" + depends on FIT + help + A FIT found at the NOR kernel offset is taken for the split layout: + the FIT and the squashfs back to back in one "firmware" partition, + which a kernel with mtdsplit divides at boot. Linux is passed that + one partition. Only for boards whose kernel carries mtdsplit; a FIT + kernel without it (hi3516cv610) keeps its fixed slots. + diff --git a/common/openipc.c b/common/openipc.c index 49cf81270dad..aa75fe13e754 100644 --- a/common/openipc.c +++ b/common/openipc.c @@ -40,7 +40,7 @@ #define SQSH_MAGIC_BE 0x73717368 #define SQSH_MAGIC_LE 0x68737173 -static int check_squashfs(void *buf) { +static int __maybe_unused check_squashfs(void *buf) { uint32_t magic = get_unaligned_be32(buf); if (magic == SQSH_MAGIC_BE || magic == SQSH_MAGIC_LE) return 1; @@ -76,7 +76,7 @@ static int ubi_marker_present(void) { } #endif -static int check_kernel(void *buf) { +static int __maybe_unused check_kernel(void *buf) { struct image_header *hdr = (struct image_header *)buf; if (image_check_magic(hdr)) { return 1; @@ -495,6 +495,43 @@ int firmware_recovery(void) { } #endif +#if !defined(CONFIG_FMC_SPI_NAND) && defined(CONFIG_OPENIPC_NOR_FIT_SPLIT) +/* + * The kernel learns the NOR layout from bootargs. A saved environment carries + * its own bootargs with "root=/dev/mtdblock3" spelled out, which is right for + * fixed slots but names the FIT under the split layout, where the partitions + * are u-boot, env, firmware, then the kernel's split of firmware into kernel + * (3), rootfs (4) and rootfs_data (5). Rewrite that one token for the layout + * found, in RAM only, and add openipc_nor_fit=1: the word sysupgrade reads from + * /proc/cmdline to know this bootloader boots the split layout. + */ +static void nor_bootargs_adjust(int fit) +{ + const char *cur = env_get("bootargs"); + const char *want = fit ? "root=/dev/mtdblock4" : "root=/dev/mtdblock3"; + const char *other = fit ? "root=/dev/mtdblock3" : "root=/dev/mtdblock4"; + char buf[1024]; + const char *p; + + if (!cur || strlen(cur) + 32 >= sizeof(buf)) + return; + p = strstr(cur, other); + if (p) { + size_t head = p - cur; + + memcpy(buf, cur, head); + strcpy(buf + head, want); + strcat(buf, p + strlen(other)); + } else { + strcpy(buf, cur); + } + if (!strstr(buf, "openipc_nor_fit=1")) + strcat(buf, " openipc_nor_fit=1"); + if (strcmp(buf, cur)) + env_set("bootargs", buf); +} +#endif + int firmware_scan(void) { #ifdef CONFIG_FMC_SPI_NAND u8 buf[64]; @@ -568,7 +605,79 @@ int firmware_scan(void) { rootfs_size = 0xa00000; #endif + /* + * A FIT at the kernel offset is the split layout: FIT and squashfs back to + * back in one "firmware" partition that the kernel divides at boot + * (mtdsplit). Linux gets that one partition, the read is the FIT's own + * size, and nothing is clamped to a slot. + */ +#ifdef CONFIG_OPENIPC_NOR_FIT_SPLIT + if (kernel_off && rootfs_off) { + u8 hdr[64]; + + if (!spi_flash_read(flash, kernel_off, sizeof(hdr), hdr) && + fdt_magic(hdr) == FDT_MAGIC && fdt_check_header(hdr) == 0) { + char str[32], mtds[128], mtdparts[160]; + const char *mtdids = env_get("mtdids"); + ulong fit_size = ALIGN(fdt_totalsize(hdr), 0x10000); + ulong kern_slot, root_slot; + + /* + * kernsize is what loadkernel reads, and also what uk erases; rootaddr + * and rootsize are where ur writes. Those commands install a uImage + * and a squashfs, i.e. fixed slots, so they get the fixed slots: the + * kernel slot whole (the split squashfs starts inside it, and a head + * left there would be found by the next scan before the new rootfs), + * the rootfs slot after it. The FIT is read whole either way. + */ + if (fit_size <= 0x200000) { + kern_slot = 0x200000; + root_slot = 0x500000; + } else if (fit_size <= 0x300000 && flash->size > 0x800000) { + kern_slot = 0x300000; + root_slot = 0xa00000; + } else { + /* No fixed-slot layout holds this kernel. */ + kern_slot = fit_size; + root_slot = flash->size - kernel_off - fit_size; + } + spi_flash_free(flash); + sprintf(str, "0x%08lx", kernel_off); + env_set("kernaddr", str); + sprintf(str, "0x%lx", kern_slot); + env_set("kernsize", str); + sprintf(str, "0x%08lx", kernel_off + kern_slot); + env_set("rootaddr", str); + sprintf(str, "0x%lx", root_slot); + env_set("rootsize", str); +#ifdef SFC + if (!mtdids || !*mtdids) + mtdids = SFC; +#endif + sprintf(mtds, "%dk(u-boot),%dk(env),-(firmware)", + CONFIG_ENV_OFFSET / 1024, CONFIG_ENV_SIZE / 1024); + env_set("mtds", mtds); + sprintf(mtdparts, "%s:%s", mtdids ? mtdids : "", mtds); + env_set("mtdparts", mtdparts); + /* The DTB stays in the kernel's lowmem (mem=${osmem}); a saved + * environment from a uImage-only bootloader has no bootm_size. */ + if (!env_get("bootm_size")) + env_set("bootm_size", "0x2000000"); + /* The FIT carries crc32 and sha1 for the kernel and the DTB; a + * verify=n saved by an older bootloader must not skip them. RAM + * only, like the rest of the scan. */ + env_set("verify", NULL); + nor_bootargs_adjust(1); + env_set("bootfail", NULL); + return 0; + } + } +#endif + spi_flash_free(flash); +#ifdef CONFIG_OPENIPC_NOR_FIT_SPLIT + nor_bootargs_adjust(0); +#endif if (kernel_off) { char str[32]; diff --git a/openipc/xm72050200_config b/openipc/xm72050200_config index ae226538b520..23b060aaf0cb 100644 --- a/openipc/xm72050200_config +++ b/openipc/xm72050200_config @@ -2,3 +2,7 @@ CONFIG_SYS_LOAD_ADDR=0x42000000 CONFIG_MMC=y CONFIG_CMD_MMC=y CONFIG_MMC_SDHCI=y +# Split NOR layout: a hashed FIT kernel (board nor-fit.its in OpenIPC/firmware) +CONFIG_FIT=y +CONFIG_SHA1=y +CONFIG_OPENIPC_NOR_FIT_SPLIT=y diff --git a/openipc/xm72050300_config b/openipc/xm72050300_config index ec7c022070b8..28d78126a0f4 100644 --- a/openipc/xm72050300_config +++ b/openipc/xm72050300_config @@ -8,3 +8,7 @@ CONFIG_SYS_LOAD_ADDR=0x42000000 CONFIG_MMC=y CONFIG_CMD_MMC=y CONFIG_MMC_SDHCI=y +# Split NOR layout: a hashed FIT kernel (board nor-fit.its in OpenIPC/firmware) +CONFIG_FIT=y +CONFIG_SHA1=y +CONFIG_OPENIPC_NOR_FIT_SPLIT=y