[PATCH 0/3] Test and docs for fdt command

This was required by Marek to provide a starting point for documentation and a test for a new subcommand.
Simon Glass (3): addrmap: Support on sandbox fdt: Start a test for the fdt command doc: Make a start on docs for fdt command
board/sandbox/sandbox.c | 9 +++ common/cli.c | 15 ++++ configs/sandbox_defconfig | 1 + doc/usage/cmd/fdt.rst | 69 ++++++++++++++++++ doc/usage/index.rst | 1 + include/addr_map.h | 2 + include/command.h | 10 +++ include/test/suites.h | 1 + lib/addr_map.c | 5 +- test/cmd/Makefile | 1 + test/cmd/addrmap.c | 5 +- test/cmd/fdt.c | 142 ++++++++++++++++++++++++++++++++++++++ test/cmd_ut.c | 6 ++ 13 files changed, 262 insertions(+), 5 deletions(-) create mode 100644 doc/usage/cmd/fdt.rst create mode 100644 test/cmd/fdt.c

Update this feature so that it works on sandbox, using a basic identity mapping. This allows us to run the 'ut addrmap' test.
Also fix up the test to use the correct macros to access the linker list, so that the 'ut addrmap' command actually works.
Signed-off-by: Simon Glass sjg@chromium.org ---
board/sandbox/sandbox.c | 9 +++++++++ configs/sandbox_defconfig | 1 + include/addr_map.h | 2 ++ lib/addr_map.c | 5 +++-- test/cmd/addrmap.c | 5 ++--- 5 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c index e054f300c4a..ca9a2ca5b17 100644 --- a/board/sandbox/sandbox.c +++ b/board/sandbox/sandbox.c @@ -4,6 +4,7 @@ */
#include <common.h> +#include <addr_map.h> #include <cpu_func.h> #include <cros_ec.h> #include <dm.h> @@ -155,3 +156,11 @@ int board_late_init(void) return 0; } #endif + +int init_addr_map(void) +{ + if (IS_ENABLED(CONFIG_ADDR_MAP)) + addrmap_set_entry(0, 0, CONFIG_SYS_SDRAM_SIZE, 0); + + return 0; +} diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 572cf8edd8b..55c014e1c45 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -313,6 +313,7 @@ CONFIG_WDT_GPIO=y CONFIG_WDT_SANDBOX=y CONFIG_FS_CBFS=y CONFIG_FS_CRAMFS=y +CONFIG_ADDR_MAP=y CONFIG_CMD_DHRYSTONE=y CONFIG_ECDSA=y CONFIG_ECDSA_VERIFY=y diff --git a/include/addr_map.h b/include/addr_map.h index 55d3a6a165a..db3712b5d30 100644 --- a/include/addr_map.h +++ b/include/addr_map.h @@ -14,7 +14,9 @@ struct addrmap { unsigned long vaddr; };
+#ifdef CONFIG_ADDR_MAP extern struct addrmap address_map[CONFIG_SYS_NUM_ADDR_MAP]; +#endif
phys_addr_t addrmap_virt_to_phys(void *vaddr); void *addrmap_phys_to_virt(phys_addr_t paddr); diff --git a/lib/addr_map.c b/lib/addr_map.c index fb2ef400078..9b3e0a544e4 100644 --- a/lib/addr_map.c +++ b/lib/addr_map.c @@ -5,6 +5,7 @@
#include <common.h> #include <addr_map.h> +#include <mapmem.h>
struct addrmap address_map[CONFIG_SYS_NUM_ADDR_MAP];
@@ -18,7 +19,7 @@ phys_addr_t addrmap_virt_to_phys(void * vaddr) if (address_map[i].size == 0) continue;
- addr = (u64)((u32)vaddr); + addr = map_to_sysmem(vaddr); base = (u64)(address_map[i].vaddr); upper = (u64)(address_map[i].size) + base - 1;
@@ -48,7 +49,7 @@ void *addrmap_phys_to_virt(phys_addr_t paddr)
offset = address_map[i].paddr - address_map[i].vaddr;
- return (void *)(unsigned long)(paddr - offset); + return map_sysmem(paddr - offset, 0); } }
diff --git a/test/cmd/addrmap.c b/test/cmd/addrmap.c index fb744485bbf..1eb5955db17 100644 --- a/test/cmd/addrmap.c +++ b/test/cmd/addrmap.c @@ -29,9 +29,8 @@ ADDRMAP_TEST(addrmap_test_basic, UT_TESTF_CONSOLE_REC);
int do_ut_addrmap(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, - addrmap_test); - const int n_ents = ll_entry_count(struct unit_test, addrmap_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(addrmap_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(addrmap_test);
return cmd_ut_category("cmd_addrmap", "cmd_addrmap_", tests, n_ents, argc, argv);

Update this feature so that it works on sandbox, using a basic identity mapping. This allows us to run the 'ut addrmap' test.
Also fix up the test to use the correct macros to access the linker list, so that the 'ut addrmap' command actually works.
Signed-off-by: Simon Glass sjg@chromium.org ---
board/sandbox/sandbox.c | 9 +++++++++ configs/sandbox_defconfig | 1 + include/addr_map.h | 2 ++ lib/addr_map.c | 5 +++-- test/cmd/addrmap.c | 5 ++--- 5 files changed, 17 insertions(+), 5 deletions(-)
Applied to u-boot-dm, thanks!

Add a basic test of the 'fdt addr' command, to kick things off.
This includes a new convenience function to run a command from a printf() string.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/cli.c | 15 +++++ include/command.h | 10 +++ include/test/suites.h | 1 + test/cmd/Makefile | 1 + test/cmd/fdt.c | 142 ++++++++++++++++++++++++++++++++++++++++++ test/cmd_ut.c | 6 ++ 6 files changed, 175 insertions(+) create mode 100644 test/cmd/fdt.c
diff --git a/common/cli.c b/common/cli.c index a7e3d84b68f..a47d6a3f2b4 100644 --- a/common/cli.c +++ b/common/cli.c @@ -126,6 +126,21 @@ int run_command_list(const char *cmd, int len, int flag) return rcode; }
+int run_commandf(const char *fmt, ...) +{ + va_list args; + char cmd[128]; + int i, ret; + + va_start(args, fmt); + i = vsnprintf(cmd, sizeof(cmd), fmt, args); + va_end(args); + + ret = run_command(cmd, 0); + + return ret; +} + /****************************************************************************/
#if defined(CONFIG_CMD_RUN) diff --git a/include/command.h b/include/command.h index 0cf12fde396..44c91f655d4 100644 --- a/include/command.h +++ b/include/command.h @@ -257,6 +257,16 @@ int board_run_command(const char *cmdline); int run_command(const char *cmd, int flag); int run_command_repeatable(const char *cmd, int flag);
+/** + * run_commandf() - Run a command created by a format string + * + * The command cannot be larger than 127 characters + * + * @fmt: printf() format string + * @...: Arguments to use (flag is always 0) + */ +int run_commandf(const char *fmt, ...); + /** * Run a list of commands separated by ; or even \0 * diff --git a/include/test/suites.h b/include/test/suites.h index ddb8827fdb1..44025ccecd6 100644 --- a/include/test/suites.h +++ b/include/test/suites.h @@ -38,6 +38,7 @@ int do_ut_compression(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_dm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_env(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_ut_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_lib(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_loadm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_log(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]); diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 4b2d7df0d2e..c331757425e 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_CONSOLE_RECORD) += test_echo.o endif obj-y += mem.o obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o +obj-$(CONFIG_CMD_FDT) += fdt.o obj-$(CONFIG_CMD_LOADM) += loadm.o obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o obj-$(CONFIG_CMD_PINMUX) += pinmux.o diff --git a/test/cmd/fdt.c b/test/cmd/fdt.c new file mode 100644 index 00000000000..100a7ef5ebf --- /dev/null +++ b/test/cmd/fdt.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for fdt command + * + * Copyright 2022 Google LLCmap_to_sysmem(fdt)); + */ + +#include <common.h> +#include <console.h> +#include <fdt_support.h> +#include <mapmem.h> +#include <asm/global_data.h> +#include <linux/libfdt.h> +#include <test/suites.h> +#include <test/ut.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Declare a new fdt test */ +#define FDT_TEST(_name, _flags) UNIT_TEST(_name, _flags, fdt_test) + +/** + * make_test_fdt() - Create an FDT with just a root node + * + * The size is set to the minimum needed + * + * @uts: Test state + * @fdt: Place to write FDT + * @size: Maximum size of space for fdt + */ +static int make_test_fdt(struct unit_test_state *uts, void *fdt, int size) +{ + ut_assertok(fdt_create(fdt, size)); + ut_assertok(fdt_finish_reservemap(fdt)); + ut_assert(fdt_begin_node(fdt, "") >= 0); + ut_assertok(fdt_end_node(fdt)); + ut_assertok(fdt_finish(fdt)); + + return 0; +} + +/* Test 'fdt addr' getting/setting address */ +static int fdt_test_addr(struct unit_test_state *uts) +{ + const void *fdt_blob, *new_fdt; + char fdt[256]; + ulong addr; + int ret; + + ut_assertok(console_record_reset_enable()); + ut_assertok(run_command("fdt addr -c", 0)); + ut_assert_nextline("Control fdt: %08lx", + (ulong)map_to_sysmem(gd->fdt_blob)); + ut_assertok(ut_check_console_end(uts)); + + /* The working fdt is not set, so this should fail */ + set_working_fdt_addr(0); + ut_asserteq(CMD_RET_FAILURE, run_command("fdt addr", 0)); + ut_assert_nextline("libfdt fdt_check_header(): FDT_ERR_BADMAGIC"); + ut_assertok(ut_check_console_end(uts)); + + /* Set up a working FDT and try again */ + ut_assertok(make_test_fdt(uts, fdt, sizeof(fdt))); + addr = map_to_sysmem(fdt); + set_working_fdt_addr(addr); + ut_assertok(run_command("fdt addr", 0)); + ut_assert_nextline("Working fdt: %08lx", (ulong)map_to_sysmem(fdt)); + ut_assertok(ut_check_console_end(uts)); + + /* Set the working FDT */ + set_working_fdt_addr(0); + ut_assertok(run_commandf("fdt addr %08x", addr)); + ut_asserteq(addr, map_to_sysmem(working_fdt)); + ut_assertok(ut_check_console_end(uts)); + set_working_fdt_addr(0); + + /* Set the working FDT */ + fdt_blob = gd->fdt_blob; + gd->fdt_blob = NULL; + ret = run_commandf("fdt addr -c %08x", addr); + new_fdt = gd->fdt_blob; + gd->fdt_blob = fdt_blob; + ut_assertok(ret); + ut_asserteq(addr, map_to_sysmem(new_fdt)); + ut_assertok(ut_check_console_end(uts)); + + /* Test setting an invalid FDT */ + fdt[0] = 123; + ut_asserteq(1, run_commandf("fdt addr %08x", addr)); + ut_assert_nextline("libfdt fdt_check_header(): FDT_ERR_BADMAGIC"); + ut_assertok(ut_check_console_end(uts)); + + /* Test detecting an invalid FDT */ + fdt[0] = 123; + set_working_fdt_addr(addr); + ut_asserteq(1, run_commandf("fdt addr")); + ut_assert_nextline("libfdt fdt_check_header(): FDT_ERR_BADMAGIC"); + ut_assertok(ut_check_console_end(uts)); + + return 0; +} +FDT_TEST(fdt_test_addr, UT_TESTF_CONSOLE_REC); + +/* Test 'fdt addr' resizing an fdt */ +static int fdt_test_resize(struct unit_test_state *uts) +{ + char fdt[256]; + const int newsize = sizeof(fdt) / 2; + ulong addr; + + ut_assertok(make_test_fdt(uts, fdt, sizeof(fdt))); + addr = map_to_sysmem(fdt); + set_working_fdt_addr(addr); + + /* Test setting and resizing the working FDT to a larger size */ + ut_assertok(console_record_reset_enable()); + ut_assertok(run_commandf("fdt addr %08x %x", addr, newsize)); + ut_assertok(ut_check_console_end(uts)); + + /* Try shrinking it */ + ut_assertok(run_commandf("fdt addr %08x %x", addr, sizeof(fdt) / 4)); + ut_assert_nextline("New length %d < existing length %d, ignoring", + (int)sizeof(fdt) / 4, newsize); + ut_assertok(ut_check_console_end(uts)); + + /* ...quietly */ + ut_assertok(run_commandf("fdt addr -q %08x %x", addr, sizeof(fdt) / 4)); + ut_assertok(ut_check_console_end(uts)); + + /* We cannot easily provoke errors in fdt_open_into(), so ignore that */ + + return 0; +} +FDT_TEST(fdt_test_resize, UT_TESTF_CONSOLE_REC); + +int do_ut_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct unit_test *tests = UNIT_TEST_SUITE_START(fdt_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(fdt_test); + + return cmd_ut_category("fdt", "fdt_test_", tests, n_ents, argc, argv); +} diff --git a/test/cmd_ut.c b/test/cmd_ut.c index d70b72678ae..3789c6b784c 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -39,6 +39,9 @@ static struct cmd_tbl cmd_ut_sub[] = { #if defined(CONFIG_UT_ENV) U_BOOT_CMD_MKENT(env, CONFIG_SYS_MAXARGS, 1, do_ut_env, "", ""), #endif +#ifdef CONFIG_CMD_FDT + U_BOOT_CMD_MKENT(fdt, CONFIG_SYS_MAXARGS, 1, do_ut_fdt, "", ""), +#endif #ifdef CONFIG_UT_OPTEE U_BOOT_CMD_MKENT(optee, CONFIG_SYS_MAXARGS, 1, do_ut_optee, "", ""), #endif @@ -131,6 +134,9 @@ static char ut_help_text[] = #ifdef CONFIG_UT_ENV "ut env [test-name]\n" #endif +#ifdef CONFIG_CMD_FDT + "ut fdt [test-name] - test of the fdt command\n" +#endif #ifdef CONFIG_UT_LIB "ut lib [test-name] - test library functions\n" #endif

Add a basic test of the 'fdt addr' command, to kick things off.
This includes a new convenience function to run a command from a printf() string.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/cli.c | 15 +++++ include/command.h | 10 +++ include/test/suites.h | 1 + test/cmd/Makefile | 1 + test/cmd/fdt.c | 142 ++++++++++++++++++++++++++++++++++++++++++ test/cmd_ut.c | 6 ++ 6 files changed, 175 insertions(+) create mode 100644 test/cmd/fdt.c
Applied to u-boot-dm, thanks!

Add some information about the 'fdt addr' subcommand, to get things started.
Signed-off-by: Simon Glass sjg@chromium.org ---
doc/usage/cmd/fdt.rst | 69 +++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 70 insertions(+) create mode 100644 doc/usage/cmd/fdt.rst
diff --git a/doc/usage/cmd/fdt.rst b/doc/usage/cmd/fdt.rst new file mode 100644 index 00000000000..07fed732e45 --- /dev/null +++ b/doc/usage/cmd/fdt.rst @@ -0,0 +1,69 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +fdt command +=========== + +Synopis +------- + +:: + + fdt addr [-cq] [addr [len]] + +Description +----------- + +The fdt command provides access to flat device tree blobs in memory. It has +many subcommands, some of which are not documented here. + +Flags: + +-c + Select the control FDT (otherwise the working FDT is used). +-q + Don't display errors + +The control FDT is the one used by U-Boot itself to control various features, +including driver model. This should only be changed if you really know what you +are doing, since once U-Boot starts it maintains pointers into the FDT from the +various driver model data structures. + +The working FDT is the one passed to the Operating System when booting. This +can be freely modified, so far as U-Boot is concerned, since it does not affect +U-Boot's operation. + +fdt addr +~~~~~~~~ + +With no arguments, this shows the address of the current working or control +FDT. + +If the `addr` argument is provided, then this sets the address of the working or +control FDT to the provided address. + +If the `len` argument is provided, then the device tree is expanded to that +size. This can be used to make space for more nodes and properties. It is +assumed that there is enough space in memory for this expansion. + +Example +------- + +Get the control address and copy that FDT to free memory:: + + => fdt addr -c + Control fdt: 0aff9fd0 + => cp.b 0aff9fd0 10000 10000 + => md 10000 4 + 00010000: edfe0dd0 5b3d0000 78000000 7c270000 ......=[...x..'| + +The second word shows the size of the FDT. Now set the working FDT to that +address and expand it to 0xf000 in size:: + + => fdt addr 10000 f000 + => md 10000 4 + 00010000: edfe0dd0 00f00000 78000000 7c270000 ...........x..'| + +Return value +------------ + +The return value $? indicates whether the command succeeded. diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 8b98629d6bf..16a3db5c000 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -43,6 +43,7 @@ Shell commands cmd/false cmd/fatinfo cmd/fatload + cmd/fdt cmd/for cmd/load cmd/loadm

Add some information about the 'fdt addr' subcommand, to get things started.
Signed-off-by: Simon Glass sjg@chromium.org ---
doc/usage/cmd/fdt.rst | 69 +++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 70 insertions(+) create mode 100644 doc/usage/cmd/fdt.rst
Applied to u-boot-dm, thanks!
participants (1)
-
Simon Glass