diff --git a/MAINTAINERS b/MAINTAINERS index 06c4ea2ecd..b9c505d5fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1331,6 +1331,13 @@ F: arch/sandbox/ F: doc/arch/sandbox.rst F: include/dt-bindings/*/sandbox*.h +SEAMA +M: Linus Walleij +S: Maintained +F: cmd/seama.c +F: doc/usage/cmd/seama.rst +F: test/cmd/seama.c + SEMIHOSTING R: Sean Anderson S: Orphaned diff --git a/README b/README index edce7890c0..9cc0c981c4 100644 --- a/README +++ b/README @@ -1810,6 +1810,7 @@ sspi - SPI utility commands base - print or set address offset printenv- print environment variables pwm - control pwm channels +seama - load SEAMA NAND image setenv - set environment variables saveenv - save environment variables to persistent storage protect - enable or disable FLASH write protection diff --git a/cmd/Kconfig b/cmd/Kconfig index dc0446e02e..b50e14f70a 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -337,6 +337,12 @@ config BOOTM_RTEMS help Support booting RTEMS images via the bootm command. +config CMD_SEAMA + bool "Support read SEAMA NAND images" + depends on MTD_RAW_NAND + help + Support reading NAND Seattle Image (SEAMA) images. + config CMD_VBE bool "vbe - Verified Boot for Embedded" depends on BOOTMETH_VBE diff --git a/cmd/Makefile b/cmd/Makefile index 7b6ff73186..b03d68d5f9 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -156,6 +156,7 @@ obj-$(CONFIG_SANDBOX) += sb.o obj-$(CONFIG_CMD_SF) += sf.o obj-$(CONFIG_CMD_SCSI) += scsi.o disk.o obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o +obj-$(CONFIG_CMD_SEAMA) += seama.o obj-$(CONFIG_CMD_SETEXPR) += setexpr.o obj-$(CONFIG_CMD_SETEXPR_FMT) += printf.o obj-$(CONFIG_CMD_SPI) += spi.o diff --git a/cmd/seama.c b/cmd/seama.c new file mode 100644 index 0000000000..3aafb43c48 --- /dev/null +++ b/cmd/seama.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2023 Linus Walleij + * Support for the "SEAttle iMAge" SEAMA NAND image format + */ + +#include +#include +#include + +/* + * All SEAMA data is stored in the flash in "network endianness" + * i.e. big endian, which means that it needs to be byte-swapped + * on all little endian platforms. + * + * structure for a SEAMA entity in NAND flash: + * + * 32 bit SEAMA magic 0x5EA3A417 + * 16 bit reserved + * 16 bit metadata size (following the header) + * 32 bit image size + * 16 bytes MD5 digest of the image + * meta data + * ... image data ... + * + * Then if a new SEAMA magic follows, that is the next image. + */ + +#define SEAMA_MAGIC 0x5EA3A417 +#define SEAMA_HDR_NO_META_SZ 28 +#define SEAMA_MAX_META_SZ (1024 - SEAMA_HDR_NO_META_SZ) + +struct seama_header { + u32 magic; + u32 meta_size; + u32 image_size; + u8 md5[16]; + u8 metadata[SEAMA_MAX_META_SZ]; +}; + +static struct seama_header shdr; + +static int env_set_val(const char *varname, ulong val) +{ + int ret; + + ret = env_set_hex(varname, val); + if (ret) + printf("Failed to %s env var\n", varname); + + return ret; +} + +static int do_seama_load_image(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct mtd_info *mtd; + uintptr_t load_addr; + unsigned long image_index; + u32 len; + size_t readsz; + int ret; + u32 *start; + u32 *offset; + u32 *end; + u32 tmp; + + if (argc < 2 || argc > 3) + return CMD_RET_USAGE; + + load_addr = hextoul(argv[1], NULL); + if (!load_addr) { + printf("Invalid load address\n"); + return CMD_RET_USAGE; + } + + /* Can be 0 for first image */ + image_index = hextoul(argv[2], NULL); + + /* We only support one NAND, the first one */ + nand_curr_device = 0; + mtd = get_nand_dev_by_index(0); + if (!mtd) { + printf("NAND Device 0 not available\n"); + return CMD_RET_FAILURE; + } + +#ifdef CONFIG_SYS_NAND_SELECT_DEVICE + board_nand_select_device(mtd_to_nand(mtd), 0); +#endif + + printf("Loading SEAMA image %lu from %s\n", image_index, mtd->name); + + readsz = sizeof(shdr); + offset = 0; + ret = nand_read_skip_bad(mtd, 0, &readsz, NULL, mtd->size, + (u_char *)&shdr); + if (ret) { + printf("Read error reading SEAMA header\n"); + return CMD_RET_FAILURE; + } + + if (shdr.magic != SEAMA_MAGIC) { + printf("Invalid SEAMA image magic: 0x%08x\n", shdr.magic); + return CMD_RET_FAILURE; + } + + /* Only the lower 16 bits are valid */ + shdr.meta_size &= 0xFFFF; + + if (env_set_val("seama_image_size", 0)) + return CMD_RET_FAILURE; + + printf("SEMA IMAGE:\n"); + printf(" metadata size %d\n", shdr.meta_size); + printf(" image size %d\n", shdr.image_size); + printf(" checksum %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + shdr.md5[0], shdr.md5[1], shdr.md5[2], shdr.md5[3], + shdr.md5[4], shdr.md5[5], shdr.md5[6], shdr.md5[7], + shdr.md5[8], shdr.md5[9], shdr.md5[10], shdr.md5[11], + shdr.md5[12], shdr.md5[13], shdr.md5[14], shdr.md5[15]); + + /* TODO: handle metadata if needed */ + + len = shdr.image_size; + if (env_set_val("seama_image_size", len)) + return CMD_RET_FAILURE; + + /* We need to include the header (read full pages) */ + readsz = shdr.image_size + SEAMA_HDR_NO_META_SZ + shdr.meta_size; + ret = nand_read_skip_bad(mtd, 0, &readsz, NULL, mtd->size, + (u_char *)load_addr); + if (ret) { + printf("Read error reading SEAMA main image\n"); + return CMD_RET_FAILURE; + } + + /* We use a temporary variable tmp to avoid to hairy casts */ + start = (u32 *)load_addr; + tmp = (u32)start; + tmp += SEAMA_HDR_NO_META_SZ + shdr.meta_size; + offset = (u32 *)tmp; + tmp += shdr.image_size; + end = (u32 *)tmp; + + printf("Decoding SEAMA image 0x%08x..0x%08x to 0x%08x\n", + (u32)offset, (u32)end, (u32)start); + for (; start < end; start++, offset++) + *start = be32_to_cpu(*offset); + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD + (seama, 3, 1, do_seama_load_image, + "Load the SEAMA image and sets envs", + "seama \n" +); diff --git a/doc/usage/cmd/seama.rst b/doc/usage/cmd/seama.rst new file mode 100644 index 0000000000..356c00a723 --- /dev/null +++ b/doc/usage/cmd/seama.rst @@ -0,0 +1,60 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +seama command +============= + +Synopsis +-------- + +:: + + seama + +Description +----------- + +The seama command is used to load and decode SEAttle iMAges from NAND +flash to memory. + +This type of flash image is found in some D-Link routers such as +DIR-645, DIR-842, DIR-859, DIR-860L, DIR-885L, DIR890L and DCH-M225, +as well as in WD and NEC routers on the ath79 (MIPS), Broadcom +BCM53xx, and RAMIPS platforms. + +This U-Boot command will read and decode a SEAMA image from raw NAND +flash on any platform. As it is always using big endian format for +the data decoding is always necessary on platforms such as ARM. + +dst_addr + destination address of the byte stream to be loaded + +index + the image index (0, 1, 2..) can be omitted + +Example +------- + +:: + + => seama 0x01000000 + Loading SEAMA image 0 from nand0 + SEMA IMAGE: + metadata size 36 + image size 8781764 + checksum 054859cfb1487b59befda98824e09dd6 + Decoding SEAMA image 0x01000040..0x01860004 to 0x01000000 + + +Configuration +------------- + +The command is available if CONFIG_CMD_SEAMA=y. + +Return value +------------ + +The return value $? is set 0 (true) if the loading is succefull, and +is set to 1 (false) in case of error. + +The environment variable $seama_image_size is set to the size of the +loaded SEAMA image. diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 3804046835..13e6939b38 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -75,6 +75,7 @@ Shell commands cmd/sbi cmd/sf cmd/scp03 + cmd/seama cmd/setexpr cmd/size cmd/sleep diff --git a/include/test/suites.h b/include/test/suites.h index 9ce49cbb03..7c4960c004 100644 --- a/include/test/suites.h +++ b/include/test/suites.h @@ -49,6 +49,7 @@ int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_overlay(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_print(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_ut_seama(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_str(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 09e410ec30..2ffde8703a 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_CMD_LOADM) += loadm.o obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o obj-$(CONFIG_CMD_PINMUX) += pinmux.o obj-$(CONFIG_CMD_PWM) += pwm.o +obj-$(CONFIG_CMD_SEAMA) += seama.o ifdef CONFIG_SANDBOX obj-$(CONFIG_CMD_SETEXPR) += setexpr.o endif diff --git a/test/cmd/seama.c b/test/cmd/seama.c new file mode 100644 index 0000000000..b1b56930c6 --- /dev/null +++ b/test/cmd/seama.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Executes tests for SEAMA (SEAttle iMAge) command + * + * Copyright (C) 2021 Linus Walleij + */ + +#include +#include +#include +#include +#include +#include + +#define SEAMA_TEST(_name, _flags) UNIT_TEST(_name, _flags, seama_test) + +static int seama_test_noargs(struct unit_test_state *uts) +{ + /* Test that 'seama' with no arguments fails gracefully */ + console_record_reset(); + run_command("seama", 0); + ut_assert_nextlinen("seama - Load the SEAMA image and sets envs"); + ut_assert_skipline(); + ut_assert_skipline(); + ut_assert_skipline(); + ut_assert_skipline(); + ut_assert_console_end(); + return 0; +} +SEAMA_TEST(seama_test_noargs, UT_TESTF_CONSOLE_REC); + +static int seama_test_addr(struct unit_test_state *uts) +{ + /* Test that loads SEAMA image 0 to address 0x01000000 */ + console_record_reset(); + run_command("seama 0x01000000", 0); + ut_assert_nextlinen("Loading SEAMA image 0 from nand0"); + ut_assert_nextlinen("SEMA IMAGE:"); + ut_assert_nextlinen(" metadata size "); + ut_assert_nextlinen(" image size "); + ut_assert_nextlinen(" checksum "); + ut_assert_nextlinen("Decoding SEAMA image 0x01000040.."); + ut_assert_console_end(); + return 0; +} +SEAMA_TEST(seama_test_addr, UT_TESTF_CONSOLE_REC); + +static int seama_test_index(struct unit_test_state *uts) +{ + /* Test that loads SEAMA image 0 exlicitly specified */ + console_record_reset(); + run_command("seama 0x01000000 0", 0); + ut_assert_nextlinen("Loading SEAMA image 0 from nand0"); + ut_assert_nextlinen("SEMA IMAGE:"); + ut_assert_nextlinen(" metadata size "); + ut_assert_nextlinen(" image size "); + ut_assert_nextlinen(" checksum "); + ut_assert_nextlinen("Decoding SEAMA image 0x01000040.."); + ut_assert_console_end(); + return 0; +} +SEAMA_TEST(seama_test_index, UT_TESTF_CONSOLE_REC); + +int do_ut_seama(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct unit_test *tests = UNIT_TEST_SUITE_START(seama_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(seama_test); + + return cmd_ut_category("seama", "seama_test_", tests, n_ents, argc, + argv); +} diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 1713d0d1c8..409c22bfd2 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -110,6 +110,9 @@ static struct cmd_tbl cmd_ut_sub[] = { #ifdef CONFIG_CMD_LOADM U_BOOT_CMD_MKENT(loadm, CONFIG_SYS_MAXARGS, 1, do_ut_loadm, "", ""), #endif +#ifdef CONFIG_CMD_SEAMA + U_BOOT_CMD_MKENT(seama, CONFIG_SYS_MAXARGS, 1, do_ut_seama, "", ""), +#endif }; static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc, @@ -212,6 +215,9 @@ static char ut_help_text[] = #ifdef CONFIG_SANDBOX "\nstr - basic test of string functions" #endif +#ifdef CONFIG_CMD_SEAMA + "\nseama - seama command parameters loading and decoding" +#endif #ifdef CONFIG_UT_TIME "\ntime - very basic test of time functions" #endif