From 93e2673982e6005a298ca2bd3450ac130105981e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:11 -0600 Subject: test: doc: Add documentation for ut command Before adding more options, document this command. Signed-off-by: Simon Glass --- doc/usage/cmd/ut.rst | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 103 insertions(+) create mode 100644 doc/usage/cmd/ut.rst (limited to 'doc/usage') diff --git a/doc/usage/cmd/ut.rst b/doc/usage/cmd/ut.rst new file mode 100644 index 00000000000..9f602ea7917 --- /dev/null +++ b/doc/usage/cmd/ut.rst @@ -0,0 +1,102 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +ut command +========== + +Synopis +------- + +:: + + ut [-r] [-f] [ []] + + Number of times to run each test + -f Force 'manual' tests to run as well + Test suite to run, or `all` + Name of single test to run + +Description +----------- + +The ut command runs unit tests written in C. + +Typically the command is run on :ref:`arch/sandbox/sandbox:sandbox` since it +includes a near-complete set of emulators, no code-size limits, many CONFIG +options enabled and runs easily in CI without needing QEMU. It is also possible +to run some tests on real boards. + +For a list of available test suites, type `ut` by itself. + +Each test is normally run once, although those marked with `UT_TESTF_DM` are +run with livetree and flattree where possible. To run a test more than once, +use the `-r` flag. + +Manual tests are normally skipped by this command. Use `-f` to run them. See +See :ref:`develop/tests_writing:mixing python and c` for more information on +manual test. + +Generally all tests in the suite are run. To run just a single test from the +suite, provide the argument. + +See :ref:`develop/tests_writing:writing c tests` for more information on how to +write unit tests. + +Example +------- + +List available unit-test suites:: + + => ut + ut - unit tests + + Usage: + ut [-r] [-f] [] - run unit tests + -r Number of times to run each test + -f Force 'manual' tests to run as well + Test suite to run, or all + + Suites: + all - execute all enabled tests + addrmap - very basic test of addrmap command + bloblist - bloblist implementation + bootstd - standard boot implementation + compression - compressors and bootm decompression + dm - driver model + env - environment + fdt - fdt command + loadm - loadm command parameters and loading memory blob + lib - library functions + log - logging functions + mem - memory-related commands + overlay - device tree overlays + print - printing things to the console + setexpr - setexpr command + str - basic test of string functions + time - very basic test of time functions + unicode - Unicode functions + +Run one of the suites:: + + => ut bloblist + Running 14 bloblist tests + Test: bloblist_test_align: bloblist.c + Test: bloblist_test_bad_blob: bloblist.c + Test: bloblist_test_blob: bloblist.c + Test: bloblist_test_blob_ensure: bloblist.c + Test: bloblist_test_blob_maxsize: bloblist.c + Test: bloblist_test_checksum: bloblist.c + Test: bloblist_test_cmd_info: bloblist.c + Test: bloblist_test_cmd_list: bloblist.c + Test: bloblist_test_grow: bloblist.c + Test: bloblist_test_init: bloblist.c + Test: bloblist_test_reloc: bloblist.c + Test: bloblist_test_resize_fail: bloblist.c + Test: bloblist_test_resize_last: bloblist.c + Test: bloblist_test_shrink: bloblist.c + Failures: 0 + +Run just a single test in a suite:: + + => ut bloblist bloblist_test_grow + Test: bloblist_test_grow: bloblist.c + Failures: 0 diff --git a/doc/usage/index.rst b/doc/usage/index.rst index df50746c349..f3c8fba2ce2 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -74,6 +74,7 @@ Shell commands cmd/tftpput cmd/true cmd/ums + cmd/ut cmd/wdt cmd/xxd -- cgit v1.3.1 From 6580b618306a24b6ae2974318922c40588ab0284 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:12 -0600 Subject: test: Allow showing basic information about tests Add a 'ut info' command to show the number of suites and tests. This is useful to get a feel for the scale of the tests. Signed-off-by: Simon Glass --- doc/usage/cmd/ut.rst | 6 ++++++ test/cmd_ut.c | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'doc/usage') diff --git a/doc/usage/cmd/ut.rst b/doc/usage/cmd/ut.rst index 9f602ea7917..11c64a17793 100644 --- a/doc/usage/cmd/ut.rst +++ b/doc/usage/cmd/ut.rst @@ -100,3 +100,9 @@ Run just a single test in a suite:: => ut bloblist bloblist_test_grow Test: bloblist_test_grow: bloblist.c Failures: 0 + +Show information about tests:: + + => ut info + Test suites: 21 + Total tests: 642 diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 8333eaccff2..76e37f35c84 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -14,6 +14,9 @@ static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); + int cmd_ut_category(const char *name, const char *prefix, struct unit_test *tests, int n_ents, int argc, char *const argv[]) @@ -45,6 +48,7 @@ int cmd_ut_category(const char *name, const char *prefix, static struct cmd_tbl cmd_ut_sub[] = { U_BOOT_CMD_MKENT(all, CONFIG_SYS_MAXARGS, 1, do_ut_all, "", ""), + U_BOOT_CMD_MKENT(info, 1, 1, do_ut_info, "", ""), #ifdef CONFIG_BOOTSTD U_BOOT_CMD_MKENT(bootstd, CONFIG_SYS_MAXARGS, 1, do_ut_bootstd, "", ""), @@ -119,6 +123,15 @@ static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc, return any_fail; } +static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + printf("Test suites: %d\n", (int)ARRAY_SIZE(cmd_ut_sub)); + printf("Total tests: %d\n", (int)UNIT_TEST_ALL_COUNT()); + + return 0; +} + static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct cmd_tbl *cp; @@ -145,8 +158,9 @@ static char ut_help_text[] = " -f Force 'manual' tests to run as well\n" " Test suite to run, or all\n" "\n" - "Suites:" + "\nOptions for :" "\nall - execute all enabled tests" + "\ninfo - show info about tests" #ifdef CONFIG_CMD_ADDRMAP "\naddrmap - very basic test of addrmap command" #endif -- cgit v1.3.1 From d1b46595700b063faaec3e33f5754642e68b3d8f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:13 -0600 Subject: test: Add a way to detect a test that breaks another When running unit tests, some may have side effects which cause a subsequent test to break. This can sometimes be seen when using 'ut dm' or similar. Add a new argument which allows a particular (failing) test to be run immediately after a certain number of tests have run. This allows the test causing the failure to be determined. Update the documentation also. Signed-off-by: Simon Glass --- arch/sandbox/cpu/spl.c | 2 +- doc/develop/tests_sandbox.rst | 69 +++++++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/ut.rst | 11 ++++++- include/test/ut.h | 7 ++++- test/cmd_ut.c | 9 ++++-- test/test-main.c | 39 ++++++++++++++++++++---- 6 files changed, 127 insertions(+), 10 deletions(-) (limited to 'doc/usage') diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index 0faf34cc00a..09e3d10d6a5 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -132,7 +132,7 @@ void spl_board_init(void) int ret; ret = ut_run_list("spl", NULL, tests, count, - state->select_unittests, 1, false); + state->select_unittests, 1, false, NULL); /* continue execution into U-Boot */ } } diff --git a/doc/develop/tests_sandbox.rst b/doc/develop/tests_sandbox.rst index 8e42a32afb9..bfd3bdb9270 100644 --- a/doc/develop/tests_sandbox.rst +++ b/doc/develop/tests_sandbox.rst @@ -143,6 +143,75 @@ For example:: Test dm_test_rtc_reset failed 3 times +Isolating a test that breaks another +------------------------------------ + +When running unit tests, some may have side effects which cause a subsequent +test to break. This can sometimes be seen when using 'ut dm' or similar. + +You can use the `-I` argument to the `ut` command to isolate this problem. +First use `ut info` to see how many tests there are, then use a binary search to +home in on the problem. Note that you might need to restart U-Boot after each +iteration, so the `-c` argument to U-Boot is useful. + +For example, let's stay that dm_test_host() is failing:: + + => ut dm + ... + Test: dm_test_get_stats: core.c + Test: dm_test_get_stats: core.c (flat tree) + Test: dm_test_host: host.c + test/dm/host.c:71, dm_test_host(): 0 == ut_check_delta(mem_start): Expected 0x0 (0), got 0xffffcbb0 (-13392) + Test: dm_test_host: host.c (flat tree) + Test failed 1 times + Test: dm_test_host_dup: host.c + Test: dm_test_host_dup: host.c (flat tree) + ... + +You can then tell U-Boot to run the failing test at different points in the +sequence: + + => ut info + Test suites: 21 + Total tests: 645 + +:: + + $ ./u-boot -T -c "ut dm -I300:dm_test_host" + ... + Test: dm_test_pinctrl_single: pinmux.c (flat tree) + Test: dm_test_host: host.c + test/dm/host.c:71, dm_test_host(): 0 == ut_check_delta(mem_start): Expected 0x0 (0), got 0xfffffdb0 (-592) + Test: dm_test_host: host.c (flat tree) + Test dm_test_host failed 1 times (position 300) + Failures: 4 + +So it happened before position 300. Trying 150 shows it failing, so we try 75:: + + $ ./u-boot -T -c "ut dm -I75:dm_test_host" + ... + Test: dm_test_autoprobe: core.c + Test: dm_test_autoprobe: core.c (flat tree) + Test: dm_test_host: host.c + Test: dm_test_host: host.c (flat tree) + Failures: 0 + +That succeeds, so we try 120, etc. until eventually we can figure out that the +problem first happens at position 82. + + $ ./u-boot -T -c "ut dm -I82:dm_test_host" + ... + Test: dm_test_blk_flags: blk.c + Test: dm_test_blk_flags: blk.c (flat tree) + Test: dm_test_host: host.c + test/dm/host.c:71, dm_test_host(): 0 == ut_check_delta(mem_start): Expected 0x0 (0), got 0xffffc960 (-13984) + Test: dm_test_host: host.c (flat tree) + Test dm_test_host failed 1 times (position 82) + Failures: 1 + +From this we can deduce that `dm_test_blk_flags()` causes the problem with +`dm_test_host()`. + Running sandbox_spl tests directly ---------------------------------- diff --git a/doc/usage/cmd/ut.rst b/doc/usage/cmd/ut.rst index 11c64a17793..a3039634f2e 100644 --- a/doc/usage/cmd/ut.rst +++ b/doc/usage/cmd/ut.rst @@ -8,10 +8,12 @@ Synopis :: - ut [-r] [-f] [ []] + ut [-r] [-f] [-I:] [ []] Number of times to run each test -f Force 'manual' tests to run as well + Run after other tests have run + Name of the 'one' test to run Test suite to run, or `all` Name of single test to run @@ -35,6 +37,13 @@ Manual tests are normally skipped by this command. Use `-f` to run them. See See :ref:`develop/tests_writing:mixing python and c` for more information on manual test. +When running unit tests, some may have side effects which cause a subsequent +test to break. This can sometimes be seen when using 'ut dm' or similar. To +fix this, select the 'one' test which breaks. Then tell the 'ut' command to +run this one test after a certain number of other tests have run. Using a +binary search method with `-I` you can quickly figure one which test is causing +the problem. + Generally all tests in the suite are run. To run just a single test from the suite, provide the argument. diff --git a/include/test/ut.h b/include/test/ut.h index e0e618b58c2..4d00b4eeca1 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -410,10 +410,15 @@ void test_set_state(struct unit_test_state *uts); * then all tests are run * @runs_per_test: Number of times to run each test (typically 1) * @force_run: Run tests that are marked as manual-only (UT_TESTF_MANUAL) + * @test_insert: String describing a test to run after n other tests run, in the + * format n:name where n is the number of tests to run before this one and + * name is the name of the test to run. This is used to find which test causes + * another test to fail. If the one test fails, testing stops immediately. + * Pass NULL to disable this * Return: 0 if all tests passed, -1 if any failed */ int ut_run_list(const char *name, const char *prefix, struct unit_test *tests, int count, const char *select_name, int runs_per_test, - bool force_run); + bool force_run, const char *test_insert); #endif diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 76e37f35c84..2736582f11c 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -21,6 +21,7 @@ int cmd_ut_category(const char *name, const char *prefix, struct unit_test *tests, int n_ents, int argc, char *const argv[]) { + const char *test_insert = NULL; int runs_per_text = 1; bool force_run = false; int ret; @@ -35,13 +36,17 @@ int cmd_ut_category(const char *name, const char *prefix, case 'f': force_run = true; break; + case 'I': + test_insert = str + 2; + break; } argv++; - argc++; + argc--; } ret = ut_run_list(name, prefix, tests, n_ents, - argc > 1 ? argv[1] : NULL, runs_per_text, force_run); + argc > 1 ? argv[1] : NULL, runs_per_text, force_run, + test_insert); return ret ? CMD_RET_FAILURE : 0; } diff --git a/test/test-main.c b/test/test-main.c index ab3b00a3b3f..5931e94a915 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -498,12 +498,29 @@ static int ut_run_test_live_flat(struct unit_test_state *uts, */ static int ut_run_tests(struct unit_test_state *uts, const char *prefix, struct unit_test *tests, int count, - const char *select_name) + const char *select_name, const char *test_insert) { - struct unit_test *test; + struct unit_test *test, *one; int found = 0; + int pos = 0; + int upto; - for (test = tests; test < tests + count; test++) { + one = NULL; + if (test_insert) { + char *p; + + pos = dectoul(test_insert, NULL); + p = strchr(test_insert, ':'); + if (p) + p++; + + for (test = tests; test < tests + count; test++) { + if (!strcmp(p, test->name)) + one = test; + } + } + + for (upto = 0, test = tests; test < tests + count; test++, upto++) { const char *test_name = test->name; int ret, i, old_fail_count; @@ -534,6 +551,17 @@ static int ut_run_tests(struct unit_test_state *uts, const char *prefix, } } old_fail_count = uts->fail_count; + + if (one && upto == pos) { + ret = ut_run_test_live_flat(uts, one); + if (uts->fail_count != old_fail_count) { + printf("Test %s failed %d times (position %d)\n", + one->name, + uts->fail_count - old_fail_count, pos); + } + return -EBADF; + } + for (i = 0; i < uts->runs_per_test; i++) ret = ut_run_test_live_flat(uts, test); if (uts->fail_count != old_fail_count) { @@ -554,7 +582,7 @@ static int ut_run_tests(struct unit_test_state *uts, const char *prefix, int ut_run_list(const char *category, const char *prefix, struct unit_test *tests, int count, const char *select_name, - int runs_per_test, bool force_run) + int runs_per_test, bool force_run, const char *test_insert) { struct unit_test_state uts = { .fail_count = 0 }; bool has_dm_tests = false; @@ -589,7 +617,8 @@ int ut_run_list(const char *category, const char *prefix, memcpy(uts.fdt_copy, gd->fdt_blob, uts.fdt_size); } uts.force_run = force_run; - ret = ut_run_tests(&uts, prefix, tests, count, select_name); + ret = ut_run_tests(&uts, prefix, tests, count, select_name, + test_insert); /* Best efforts only...ignore errors */ if (has_dm_tests) -- cgit v1.3.1 From 2851cc94f3010d686fca3817f66ec8e9f4b2235b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:18 -0600 Subject: dm: Add documentation for host command and implementation Document the 'host' command and also the internals of how it is implemented. Signed-off-by: Simon Glass --- doc/arch/index.rst | 2 +- doc/arch/sandbox.rst | 623 --------------------------------------- doc/arch/sandbox/block_impl.rst | 39 +++ doc/arch/sandbox/index.rst | 12 + doc/arch/sandbox/sandbox.rst | 626 ++++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/host.rst | 116 ++++++++ doc/usage/index.rst | 1 + 7 files changed, 795 insertions(+), 624 deletions(-) delete mode 100644 doc/arch/sandbox.rst create mode 100644 doc/arch/sandbox/block_impl.rst create mode 100644 doc/arch/sandbox/index.rst create mode 100644 doc/arch/sandbox/sandbox.rst create mode 100644 doc/usage/cmd/host.rst (limited to 'doc/usage') diff --git a/doc/arch/index.rst b/doc/arch/index.rst index 792d9182c31..b3e85f9bf34 100644 --- a/doc/arch/index.rst +++ b/doc/arch/index.rst @@ -11,7 +11,7 @@ Architecture-specific doc m68k mips nios2 - sandbox + sandbox/index sh x86 xtensa diff --git a/doc/arch/sandbox.rst b/doc/arch/sandbox.rst deleted file mode 100644 index ed66f70f619..00000000000 --- a/doc/arch/sandbox.rst +++ /dev/null @@ -1,623 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0+ */ -.. Copyright (c) 2014 The Chromium OS Authors. -.. sectionauthor:: Simon Glass - -Sandbox -======= - -Native Execution of U-Boot --------------------------- - -The 'sandbox' architecture is designed to allow U-Boot to run under Linux on -almost any hardware. To achieve this it builds U-Boot (so far as possible) -as a normal C application with a main() and normal C libraries. - -All of U-Boot's architecture-specific code therefore cannot be built as part -of the sandbox U-Boot. The purpose of running U-Boot under Linux is to test -all the generic code, not specific to any one architecture. The idea is to -create unit tests which we can run to test this upper level code. - -Sandbox allows development of many types of new features in a traditional way, -rather than needing to test each iteration on real hardware. Many U-Boot -features were developed on sandbox, including the core driver model, most -uclasses, verified boot, bloblist, logging and dozens of others. Sandbox has -enabled many large-scale code refactors as well. - -CONFIG_SANDBOX is defined when building a native board. - -The board name is 'sandbox' but the vendor name is unset, so there is a -single board in board/sandbox. - -CONFIG_SANDBOX_BIG_ENDIAN should be defined when running on big-endian -machines. - -There are two versions of the sandbox: One using 32-bit-wide integers, and one -using 64-bit-wide integers. The 32-bit version can be build and run on either -32 or 64-bit hosts by either selecting or deselecting CONFIG_SANDBOX_32BIT; by -default, the sandbox it built for a 32-bit host. The sandbox using 64-bit-wide -integers can only be built on 64-bit hosts. - -Note that standalone/API support is not available at present. - - -Prerequisites -------------- - -Install the dependencies noted in :doc:`../build/gcc`. - - -Basic Operation ---------------- - -To run sandbox U-Boot use something like:: - - make sandbox_defconfig all - ./u-boot - -Note: If you get errors about 'sdl-config: Command not found' you may need to -install libsdl2.0-dev or similar to get SDL support. Alternatively you can -build sandbox without SDL (i.e. no display/keyboard support) by removing -the CONFIG_SANDBOX_SDL line in include/configs/sandbox.h or using:: - - make sandbox_defconfig all NO_SDL=1 - ./u-boot - -U-Boot will start on your computer, showing a sandbox emulation of the serial -console:: - - U-Boot 2014.04 (Mar 20 2014 - 19:06:00) - - DRAM: 128 MiB - Using default environment - - In: serial - Out: lcd - Err: lcd - => - -You can issue commands as your would normally. If the command you want is -not supported you can add it to include/configs/sandbox.h. - -To exit, type 'poweroff' or press Ctrl-C. - - -Console / LCD support ---------------------- - -Assuming that CONFIG_SANDBOX_SDL is defined when building, you can run the -sandbox with LCD and keyboard emulation, using something like:: - - ./u-boot -d u-boot.dtb -l - -This will start U-Boot with a window showing the contents of the LCD. If -that window has the focus then you will be able to type commands as you -would on the console. You can adjust the display settings in the device -tree file - see arch/sandbox/dts/sandbox.dts. - - -Command-line Options --------------------- - -Various options are available, mostly for test purposes. Use -h to see -available options. Some of these are described below: - --t, --terminal - The terminal is normally in what is called 'raw-with-sigs' mode. This means - that you can use arrow keys for command editing and history, but if you - press Ctrl-C, U-Boot will exit instead of handling this as a keypress. - Other options are 'raw' (so Ctrl-C is handled within U-Boot) and 'cooked' - (where the terminal is in cooked mode and cursor keys will not work, Ctrl-C - will exit). - --l - Show the LCD emulation window. - --d - A device tree binary file can be provided with -d. If you edit the source - (it is stored at arch/sandbox/dts/sandbox.dts) you must rebuild U-Boot to - recreate the binary file. - --D - To use the default device tree, use -D. - --T - To use the test device tree, use -T. - --c [;] - To execute commands directly, use the -c option. You can specify a single - command, or multiple commands separated by a semicolon, as is normal in - U-Boot. Be careful with quoting as the shell will normally process and - swallow quotes. When -c is used, U-Boot exits after the command is complete, - but you can force it to go to interactive mode instead with -i. - --i - Go to interactive mode after executing the commands specified by -c. - -Environment Variables ---------------------- - -UBOOT_SB_TIME_OFFSET - This environment variable stores the offset of the emulated real time clock - to the host's real time clock in seconds. The offset defaults to zero. - -Memory Emulation ----------------- - -Memory emulation is supported, with the size set by CONFIG_SANDBOX_RAM_SIZE_MB. -The -m option can be used to read memory from a file on start-up and write -it when shutting down. This allows preserving of memory contents across -test runs. You can tell U-Boot to remove the memory file after it is read -(on start-up) with the --rm_memory option. - -To access U-Boot's emulated memory within the code, use map_sysmem(). This -function is used throughout U-Boot to ensure that emulated memory is used -rather than the U-Boot application memory. This provides memory starting -at 0 and extending to the size of the emulation. - - -Storing State -------------- - -With sandbox you can write drivers which emulate the operation of drivers on -real devices. Some of these drivers may want to record state which is -preserved across U-Boot runs. This is particularly useful for testing. For -example, the contents of a SPI flash chip should not disappear just because -U-Boot exits. - -State is stored in a device tree file in a simple format which is driver- -specific. You then use the -s option to specify the state file. Use -r to -make U-Boot read the state on start-up (otherwise it starts empty) and -w -to write it on exit (otherwise the stored state is left unchanged and any -changes U-Boot made will be lost). You can also use -n to tell U-Boot to -ignore any problems with missing state. This is useful when first running -since the state file will be empty. - -The device tree file has one node for each driver - the driver can store -whatever properties it likes in there. See 'Writing Sandbox Drivers' below -for more details on how to get drivers to read and write their state. - - -Running and Booting -------------------- - -Since there is no machine architecture, sandbox U-Boot cannot actually boot -a kernel, but it does support the bootm command. Filesystems, memory -commands, hashing, FIT images, verified boot and many other features are -supported. - -When 'bootm' runs a kernel, sandbox will exit, as U-Boot does on a real -machine. Of course in this case, no kernel is run. - -It is also possible to tell U-Boot that it has jumped from a temporary -previous U-Boot binary, with the -j option. That binary is automatically -removed by the U-Boot that gets the -j option. This allows you to write -tests which emulate the action of chain-loading U-Boot, typically used in -a situation where a second 'updatable' U-Boot is stored on your board. It -is very risky to overwrite or upgrade the only U-Boot on a board, since a -power or other failure will brick the board and require return to the -manufacturer in the case of a consumer device. - - -Supported Drivers ------------------ - -U-Boot sandbox supports these emulations: - -- Block devices -- Chrome OS EC -- GPIO -- Host filesystem (access files on the host from within U-Boot) -- I2C -- Keyboard (Chrome OS) -- LCD -- Network -- Serial (for console only) -- Sound (incomplete - see sandbox_sdl_sound_init() for details) -- SPI -- SPI flash -- TPM (Trusted Platform Module) - -A wide range of commands are implemented. Filesystems which use a block -device are supported. - -Also sandbox supports driver model (CONFIG_DM) and associated commands. - - -Sandbox Variants ----------------- - -There are unfortunately quite a few variants at present: - -sandbox: - should be used for most tests -sandbox64: - special build that forces a 64-bit host -sandbox_flattree: - builds with dev_read\_...() functions defined as inline. - We need this build so that we can test those inline functions, and we - cannot build with both the inline functions and the non-inline functions - since they are named the same. -sandbox_spl: - builds sandbox with SPL support, so you can run spl/u-boot-spl - and it will start up and then load ./u-boot. It is also possible to - run ./u-boot directly. - -Of these sandbox_spl can probably be removed since it is a superset of sandbox. - -Most of the config options should be identical between these variants. - - -Linux RAW Networking Bridge ---------------------------- - -The sandbox_eth_raw driver bridges traffic between the bottom of the network -stack and the RAW sockets API in Linux. This allows much of the U-Boot network -functionality to be tested in sandbox against real network traffic. - -For Ethernet network adapters, the bridge utilizes the RAW AF_PACKET API. This -is needed to get access to the lowest level of the network stack in Linux. This -means that all of the Ethernet frame is included. This allows the U-Boot network -stack to be fully used. In other words, nothing about the Linux network stack is -involved in forming the packets that end up on the wire. To receive the -responses to packets sent from U-Boot the network interface has to be set to -promiscuous mode so that the network card won't filter out packets not destined -for its configured (on Linux) MAC address. - -The RAW sockets Ethernet API requires elevated privileges in Linux. You can -either run as root, or you can add the capability needed like so:: - - sudo /sbin/setcap "CAP_NET_RAW+ep" /path/to/u-boot - -The default device tree for sandbox includes an entry for eth0 on the sandbox -host machine whose alias is "eth1". The following are a few examples of network -operations being tested on the eth0 interface. - -.. code-block:: none - - sudo /path/to/u-boot -D - - DHCP - .... - - setenv autoload no - setenv ethrotate no - setenv ethact eth1 - dhcp - - PING - .... - - setenv autoload no - setenv ethrotate no - setenv ethact eth1 - dhcp - ping $gatewayip - - TFTP - .... - - setenv autoload no - setenv ethrotate no - setenv ethact eth1 - dhcp - setenv serverip WWW.XXX.YYY.ZZZ - tftpboot u-boot.bin - -The bridge also supports (to a lesser extent) the localhost interface, 'lo'. - -The 'lo' interface cannot use the RAW AF_PACKET API because the lo interface -doesn't support Ethernet-level traffic. It is a higher-level interface that is -expected only to be used at the AF_INET level of the API. As such, the most raw -we can get on that interface is the RAW AF_INET API on UDP. This allows us to -set the IP_HDRINCL option to include everything except the Ethernet header in -the packets we send and receive. - -Because only UDP is supported, ICMP traffic will not work, so expect that ping -commands will time out. - -The default device tree for sandbox includes an entry for lo on the sandbox -host machine whose alias is "eth5". The following is an example of a network -operation being tested on the lo interface. - -.. code-block:: none - - TFTP - .... - - setenv ethrotate no - setenv ethact eth5 - tftpboot u-boot.bin - - -SPI Emulation -------------- - -Sandbox supports SPI and SPI flash emulation. - -The device can be enabled via a device tree, for example:: - - spi@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0 1>; - compatible = "sandbox,spi"; - cs-gpios = <0>, <&gpio_a 0>; - spi.bin@0 { - reg = <0>; - compatible = "spansion,m25p16", "jedec,spi-nor"; - spi-max-frequency = <40000000>; - sandbox,filename = "spi.bin"; - }; - }; - -The file must be created in advance:: - - $ dd if=/dev/zero of=spi.bin bs=1M count=2 - $ u-boot -T - -Here, you can use "-T" or "-D" option to specify test.dtb or u-boot.dtb, -respectively, or "-d " for your own dtb. - -With this setup you can issue SPI flash commands as normal:: - - =>sf probe - SF: Detected M25P16 with page size 64 KiB, total 2 MiB - =>sf read 0 0 10000 - SF: 65536 bytes @ 0x0 Read: OK - -Since this is a full SPI emulation (rather than just flash), you can -also use low-level SPI commands:: - - =>sspi 0:0 32 9f - FF202015 - -This is issuing a READ_ID command and getting back 20 (ST Micro) part -0x2015 (the M25P16). - - -Block Device Emulation ----------------------- - -U-Boot can use raw disk images for block device emulation. To e.g. list -the contents of the root directory on the second partion of the image -"disk.raw", you can use the following commands:: - - =>host bind 0 ./disk.raw - =>ls host 0:2 - -The device can be marked removeable with 'host bind -r'. - -A disk image can be created using the following commands:: - - $> truncate -s 1200M ./disk.raw - $> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk ./disk.raw - $> lodev=`sudo losetup -P -f --show ./disk.raw` - $> sudo mkfs.vfat -n EFI -v ${lodev}p1 - $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2 - -or utilize the device described in test/py/make_test_disk.py:: - - #!/usr/bin/python - import make_test_disk - make_test_disk.makeDisk() - -Writing Sandbox Drivers ------------------------ - -Generally you should put your driver in a file containing the word 'sandbox' -and put it in the same directory as other drivers of its type. You can then -implement the same hooks as the other drivers. - -To access U-Boot's emulated memory, use map_sysmem() as mentioned above. - -If your driver needs to store configuration or state (such as SPI flash -contents or emulated chip registers), you can use the device tree as -described above. Define handlers for this with the SANDBOX_STATE_IO macro. -See arch/sandbox/include/asm/state.h for documentation. In short you provide -a node name, compatible string and functions to read and write the state. -Since writing the state can expand the device tree, you may need to use -state_setprop() which does this automatically and avoids running out of -space. See existing code for examples. - - -VPL (Verifying Program Loader) ------------------------------- - -Sandbox provides an example build of vpl called `sandbox_vpl`. This can be run -using:: - - /path/to/sandbox_vpl/tpl/u-boot-tpl -D - -It starts up TPL (first-stage init), then VPL, then runs SPL and finally U-Boot -proper, following the normal flow for a verified boot. At present, no -verification is actually implemented. - - -Debugging the init sequence ---------------------------- - -If you get a failure in the initcall sequence, like this:: - - initcall sequence 0000560775957c80 failed at call 0000000000048134 (err=-96) - -Then you use can use grep to see which init call failed, e.g.:: - - $ grep 0000000000048134 u-boot.map - stdio_add_devices - -Of course another option is to run it with a debugger such as gdb:: - - $ gdb u-boot - ... - (gdb) br initcall.h:41 - Breakpoint 1 at 0x4db9d: initcall.h:41. (2 locations) - -Note that two locations are reported, since this function is used in both -board_init_f() and board_init_r(). - -.. code-block:: none - - (gdb) r - Starting program: /tmp/b/sandbox/u-boot - [Thread debugging using libthread_db enabled] - Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". - - U-Boot 2018.09-00264-ge0c2ba9814-dirty (Sep 22 2018 - 12:21:46 -0600) - - DRAM: 128 MiB - MMC: - - Breakpoint 1, initcall_run_list (init_sequence=0x5555559619e0 ) - at /scratch/sglass/cosarm/src/third_party/u-boot/files/include/initcall.h:41 - 41 printf("initcall sequence %p failed at call %p (err=%d)\n", - (gdb) print *init_fnc_ptr - $1 = (const init_fnc_t) 0x55555559c114 - (gdb) - - -This approach can be used on normal boards as well as sandbox. - -For debugging with GDB or LLDB, it is preferable to reduce the compiler -optimization level (CONFIG_CC_OPTIMIZE_FOR_DEBUG=y) and to disable Link Time -Optimization (CONFIG_LTO=n). - -SDL_CONFIG ----------- - -If sdl-config is on a different path from the default, set the SDL_CONFIG -environment variable to the correct pathname before building U-Boot. - - -Using valgrind / memcheck -------------------------- - -It is possible to run U-Boot under valgrind to check memory allocations:: - - valgrind ./u-boot - -However, this does not give very useful results. The sandbox allocates a memory -pool via mmap(). U-Boot's internal malloc() and free() work on this memory pool. -Custom allocators and deallocators are invisible to valgrind by default. To -expose U-Boot's malloc() and free() to valgrind, enable ``CONFIG_VALGRIND``. -Enabling this option will inject placeholder assembler code which valgrind -interprets. This is used to annotate sections of memory as safe or unsafe, and -to inform valgrind about malloc()s and free()s. There are currently no standard -placeholder assembly sequences for RISC-V, so this option cannot be enabled on -that architecture. - -Malloc's bookkeeping information is marked as unsafe by default. However, this -will generate many false positives when malloc itself accesses this information. -These warnings can be suppressed with:: - - valgrind --suppressions=scripts/u-boot.supp ./u-boot - -Additionally, you may experience false positives if U-Boot is using a smaller -pointer size than your host architecture. This is because the pointers used by -U-Boot will only contain 32 bits of addressing information. When interpreted as -64-bit pointers, valgrind will think that they are not initialized properly. To -fix this, enable ``CONFIG_SANDBOX64`` (such as via ``sandbox64_defconfig``) -when running on a 64-bit host. - -Additional options -^^^^^^^^^^^^^^^^^^ - -The following valgrind options are useful in addition to the above examples: - -``--trace-childen=yes`` - tells valgrind to keep tracking subprocesses, such - as when U-Boot jumps from TPL to SPL, or from SPL to U-Boot proper. - -``--track-origins=yes`` - will (for a small overhead) tell valgrind to keep - track of who allocated some troublesome memory. - -``--error-limit`` - will enable printing more than 1000 errors in a single session. - -``--vgdb=yes --vgdb-error=0`` - will let you use GDB to attach like:: - - gdb -ex "target remote | vgdb" u-boot - - This is very helpful for inspecting the program state when there is - an error. - -The following U-Boot option are also helpful: - -``-Tc 'ut all'`` - lets U-Boot run unit tests automatically. Note - that not all unit tests will succeed in the default configuration. - -``-t cooked`` - will keep the console in a sane state if you - terminate it early (instead of having to run tset). - -Future work -^^^^^^^^^^^ - -The biggest limitation to the current approach is that supressions don't -"un-taint" uninitialized memory accesses. Currently, dlmalloc's bookkeeping -information is marked as a "red zone." This means that all reads to that zone -are marked as illegal by valgrind. This is fine for regular code, but dlmalloc -really does need to access this area, so we suppress its violations. However, if -dlmalloc then passes a result calculated from a "tainted" access, that result is -still tainted. So the first accessor will raise a warning. This means that every -construct like - -.. code-block:: - - foo = malloc(sizeof(*foo)); - if (!foo) - return -ENOMEM; - -will raise a warning when we check the result of malloc. Whoops. - -There are at least four possible ways to address this: - -* Don't mark dlmalloc bookkeeping information as a red zone. This is the - simplest solution, but reduces the power of valgrind immensely, since we can - no longer determine that (e.g.) access past the end of an array is undefined. -* Implement red zones properly. This would involve growing every allocation by a - fixed amount (16 bytes or so) and then using that extra space for a real red - zone that neither regular code nor dlmalloc needs to access. Unfortunately, - this would probably some fairly intensive surgery to dlmalloc to add/remove - the offset appropriately. -* Mark bookkeeping information as valid before we use it in dlmalloc, and then - mark it invalid before returning. This would be the most correct, but it would - be very tricky to implement since there are so many code paths to mark. I - think it would be the most effort out of the three options here. -* Use the host malloc and free instead of U-Boot's custom allocator. This will - eliminate the need to annotate dlmalloc. However, using a different allocator - for sandbox will mean that bugs in dlmalloc will only be tested when running - on read (or emulated) hardware. - -Until one of the above options are implemented, it will remain difficult -to sift through the massive amount of spurious warnings. - -Testing -------- - -U-Boot sandbox can be used to run various tests, mostly in the test/ -directory. - -See :doc:`../develop/tests_sandbox` for more information and -:doc:`../develop/testing` for information about testing generally. - - -Memory Map ----------- - -Sandbox has its own emulated memory starting at 0. Here are some of the things -that are mapped into that memory: - -======= ======================== =============================== -Addr Config Usage -======= ======================== =============================== - 0 CONFIG_SYS_FDT_LOAD_ADDR Device tree - c000 CONFIG_BLOBLIST_ADDR Blob list - 10000 CONFIG_MALLOC_F_ADDR Early memory allocation - f0000 CONFIG_PRE_CON_BUF_ADDR Pre-console buffer - 100000 CONFIG_TRACE_EARLY_ADDR Early trace buffer (if enabled). Also used - as the SPL load buffer in spl_test_load(). - 200000 CONFIG_TEXT_BASE Load buffer for U-Boot (sandbox_spl only) -======= ======================== =============================== diff --git a/doc/arch/sandbox/block_impl.rst b/doc/arch/sandbox/block_impl.rst new file mode 100644 index 00000000000..344c74f718b --- /dev/null +++ b/doc/arch/sandbox/block_impl.rst @@ -0,0 +1,39 @@ +.. SPDX-License-Identifier: GPL-2.0+ */ +.. Copyright (c) 2014 The Chromium OS Authors. +.. sectionauthor:: Simon Glass + +Sandbox block devices (implementation) +====================================== + +(See :ref:`sandbox_blk` for operation) + +Sandbox block devices are implemented using the `UCLASS_HOST` uclass. Only one +driver is provided (`host_sb_drv`) so all devices in the uclass use the same +driver. + +The uclass has a simple API allowing files to be attached and detached. +Attaching a file results in it appearing as a block device in sandbox. This +allows filesystems and whole disk images to be accessed from U-Boot. This is +particularly useful for tests. + +Devices are created using `host_create_device()`. This sets up a new +`UCLASS_HOST`. + +The device can then be attached to a file with `host_attach_file()`. This +creates the child block device (and bootdev device). + +The host device's block device must be probed before use, as normal. + +To destroy a device, call host_destroy_device(). This removes the device (and +its children of course), then closes any attached file, then unbinds the device. + +There is no arbitrary limit to the number of host devices that can be created. + + +Uclass API +---------- + +This is incomplete as it isn't clear how to make Sphinx do the right thing for +struct host_ops. See `include/sandbox_host.h` for full details. + +.. kernel-doc:: include/sandbox_host.h diff --git a/doc/arch/sandbox/index.rst b/doc/arch/sandbox/index.rst new file mode 100644 index 00000000000..1f1f5de4b03 --- /dev/null +++ b/doc/arch/sandbox/index.rst @@ -0,0 +1,12 @@ +.. SPDX-License-Identifier: GPL-2.0+ */ +.. Copyright 2022 Google LLC +.. sectionauthor:: Simon Glass + +Sandbox +======= + +.. toctree:: + :maxdepth: 2 + + sandbox + block_impl diff --git a/doc/arch/sandbox/sandbox.rst b/doc/arch/sandbox/sandbox.rst new file mode 100644 index 00000000000..34c4e06d9b8 --- /dev/null +++ b/doc/arch/sandbox/sandbox.rst @@ -0,0 +1,626 @@ +.. SPDX-License-Identifier: GPL-2.0+ */ +.. Copyright (c) 2014 The Chromium OS Authors. +.. sectionauthor:: Simon Glass + +Sandbox +======= + +Native Execution of U-Boot +-------------------------- + +The 'sandbox' architecture is designed to allow U-Boot to run under Linux on +almost any hardware. To achieve this it builds U-Boot (so far as possible) +as a normal C application with a main() and normal C libraries. + +All of U-Boot's architecture-specific code therefore cannot be built as part +of the sandbox U-Boot. The purpose of running U-Boot under Linux is to test +all the generic code, not specific to any one architecture. The idea is to +create unit tests which we can run to test this upper level code. + +Sandbox allows development of many types of new features in a traditional way, +rather than needing to test each iteration on real hardware. Many U-Boot +features were developed on sandbox, including the core driver model, most +uclasses, verified boot, bloblist, logging and dozens of others. Sandbox has +enabled many large-scale code refactors as well. + +CONFIG_SANDBOX is defined when building a native board. + +The board name is 'sandbox' but the vendor name is unset, so there is a +single board in board/sandbox. + +CONFIG_SANDBOX_BIG_ENDIAN should be defined when running on big-endian +machines. + +There are two versions of the sandbox: One using 32-bit-wide integers, and one +using 64-bit-wide integers. The 32-bit version can be build and run on either +32 or 64-bit hosts by either selecting or deselecting CONFIG_SANDBOX_32BIT; by +default, the sandbox it built for a 32-bit host. The sandbox using 64-bit-wide +integers can only be built on 64-bit hosts. + +Note that standalone/API support is not available at present. + + +Prerequisites +------------- + +Install the dependencies noted in :doc:`../../build/gcc`. + + +Basic Operation +--------------- + +To run sandbox U-Boot use something like:: + + make sandbox_defconfig all + ./u-boot + +Note: If you get errors about 'sdl-config: Command not found' you may need to +install libsdl2.0-dev or similar to get SDL support. Alternatively you can +build sandbox without SDL (i.e. no display/keyboard support) by removing +the CONFIG_SANDBOX_SDL line in include/configs/sandbox.h or using:: + + make sandbox_defconfig all NO_SDL=1 + ./u-boot + +U-Boot will start on your computer, showing a sandbox emulation of the serial +console:: + + U-Boot 2014.04 (Mar 20 2014 - 19:06:00) + + DRAM: 128 MiB + Using default environment + + In: serial + Out: lcd + Err: lcd + => + +You can issue commands as your would normally. If the command you want is +not supported you can add it to include/configs/sandbox.h. + +To exit, type 'poweroff' or press Ctrl-C. + + +Console / LCD support +--------------------- + +Assuming that CONFIG_SANDBOX_SDL is defined when building, you can run the +sandbox with LCD and keyboard emulation, using something like:: + + ./u-boot -d u-boot.dtb -l + +This will start U-Boot with a window showing the contents of the LCD. If +that window has the focus then you will be able to type commands as you +would on the console. You can adjust the display settings in the device +tree file - see arch/sandbox/dts/sandbox.dts. + + +Command-line Options +-------------------- + +Various options are available, mostly for test purposes. Use -h to see +available options. Some of these are described below: + +-t, --terminal + The terminal is normally in what is called 'raw-with-sigs' mode. This means + that you can use arrow keys for command editing and history, but if you + press Ctrl-C, U-Boot will exit instead of handling this as a keypress. + Other options are 'raw' (so Ctrl-C is handled within U-Boot) and 'cooked' + (where the terminal is in cooked mode and cursor keys will not work, Ctrl-C + will exit). + +-l + Show the LCD emulation window. + +-d + A device tree binary file can be provided with -d. If you edit the source + (it is stored at arch/sandbox/dts/sandbox.dts) you must rebuild U-Boot to + recreate the binary file. + +-D + To use the default device tree, use -D. + +-T + To use the test device tree, use -T. + +-c [;] + To execute commands directly, use the -c option. You can specify a single + command, or multiple commands separated by a semicolon, as is normal in + U-Boot. Be careful with quoting as the shell will normally process and + swallow quotes. When -c is used, U-Boot exits after the command is complete, + but you can force it to go to interactive mode instead with -i. + +-i + Go to interactive mode after executing the commands specified by -c. + +Environment Variables +--------------------- + +UBOOT_SB_TIME_OFFSET + This environment variable stores the offset of the emulated real time clock + to the host's real time clock in seconds. The offset defaults to zero. + +Memory Emulation +---------------- + +Memory emulation is supported, with the size set by CONFIG_SANDBOX_RAM_SIZE_MB. +The -m option can be used to read memory from a file on start-up and write +it when shutting down. This allows preserving of memory contents across +test runs. You can tell U-Boot to remove the memory file after it is read +(on start-up) with the --rm_memory option. + +To access U-Boot's emulated memory within the code, use map_sysmem(). This +function is used throughout U-Boot to ensure that emulated memory is used +rather than the U-Boot application memory. This provides memory starting +at 0 and extending to the size of the emulation. + + +Storing State +------------- + +With sandbox you can write drivers which emulate the operation of drivers on +real devices. Some of these drivers may want to record state which is +preserved across U-Boot runs. This is particularly useful for testing. For +example, the contents of a SPI flash chip should not disappear just because +U-Boot exits. + +State is stored in a device tree file in a simple format which is driver- +specific. You then use the -s option to specify the state file. Use -r to +make U-Boot read the state on start-up (otherwise it starts empty) and -w +to write it on exit (otherwise the stored state is left unchanged and any +changes U-Boot made will be lost). You can also use -n to tell U-Boot to +ignore any problems with missing state. This is useful when first running +since the state file will be empty. + +The device tree file has one node for each driver - the driver can store +whatever properties it likes in there. See 'Writing Sandbox Drivers' below +for more details on how to get drivers to read and write their state. + + +Running and Booting +------------------- + +Since there is no machine architecture, sandbox U-Boot cannot actually boot +a kernel, but it does support the bootm command. Filesystems, memory +commands, hashing, FIT images, verified boot and many other features are +supported. + +When 'bootm' runs a kernel, sandbox will exit, as U-Boot does on a real +machine. Of course in this case, no kernel is run. + +It is also possible to tell U-Boot that it has jumped from a temporary +previous U-Boot binary, with the -j option. That binary is automatically +removed by the U-Boot that gets the -j option. This allows you to write +tests which emulate the action of chain-loading U-Boot, typically used in +a situation where a second 'updatable' U-Boot is stored on your board. It +is very risky to overwrite or upgrade the only U-Boot on a board, since a +power or other failure will brick the board and require return to the +manufacturer in the case of a consumer device. + + +Supported Drivers +----------------- + +U-Boot sandbox supports these emulations: + +- Block devices +- Chrome OS EC +- GPIO +- Host filesystem (access files on the host from within U-Boot) +- I2C +- Keyboard (Chrome OS) +- LCD +- Network +- Serial (for console only) +- Sound (incomplete - see sandbox_sdl_sound_init() for details) +- SPI +- SPI flash +- TPM (Trusted Platform Module) + +A wide range of commands are implemented. Filesystems which use a block +device are supported. + +Also sandbox supports driver model (CONFIG_DM) and associated commands. + + +Sandbox Variants +---------------- + +There are unfortunately quite a few variants at present: + +sandbox: + should be used for most tests +sandbox64: + special build that forces a 64-bit host +sandbox_flattree: + builds with dev_read\_...() functions defined as inline. + We need this build so that we can test those inline functions, and we + cannot build with both the inline functions and the non-inline functions + since they are named the same. +sandbox_spl: + builds sandbox with SPL support, so you can run spl/u-boot-spl + and it will start up and then load ./u-boot. It is also possible to + run ./u-boot directly. + +Of these sandbox_spl can probably be removed since it is a superset of sandbox. + +Most of the config options should be identical between these variants. + + +Linux RAW Networking Bridge +--------------------------- + +The sandbox_eth_raw driver bridges traffic between the bottom of the network +stack and the RAW sockets API in Linux. This allows much of the U-Boot network +functionality to be tested in sandbox against real network traffic. + +For Ethernet network adapters, the bridge utilizes the RAW AF_PACKET API. This +is needed to get access to the lowest level of the network stack in Linux. This +means that all of the Ethernet frame is included. This allows the U-Boot network +stack to be fully used. In other words, nothing about the Linux network stack is +involved in forming the packets that end up on the wire. To receive the +responses to packets sent from U-Boot the network interface has to be set to +promiscuous mode so that the network card won't filter out packets not destined +for its configured (on Linux) MAC address. + +The RAW sockets Ethernet API requires elevated privileges in Linux. You can +either run as root, or you can add the capability needed like so:: + + sudo /sbin/setcap "CAP_NET_RAW+ep" /path/to/u-boot + +The default device tree for sandbox includes an entry for eth0 on the sandbox +host machine whose alias is "eth1". The following are a few examples of network +operations being tested on the eth0 interface. + +.. code-block:: none + + sudo /path/to/u-boot -D + + DHCP + .... + + setenv autoload no + setenv ethrotate no + setenv ethact eth1 + dhcp + + PING + .... + + setenv autoload no + setenv ethrotate no + setenv ethact eth1 + dhcp + ping $gatewayip + + TFTP + .... + + setenv autoload no + setenv ethrotate no + setenv ethact eth1 + dhcp + setenv serverip WWW.XXX.YYY.ZZZ + tftpboot u-boot.bin + +The bridge also supports (to a lesser extent) the localhost interface, 'lo'. + +The 'lo' interface cannot use the RAW AF_PACKET API because the lo interface +doesn't support Ethernet-level traffic. It is a higher-level interface that is +expected only to be used at the AF_INET level of the API. As such, the most raw +we can get on that interface is the RAW AF_INET API on UDP. This allows us to +set the IP_HDRINCL option to include everything except the Ethernet header in +the packets we send and receive. + +Because only UDP is supported, ICMP traffic will not work, so expect that ping +commands will time out. + +The default device tree for sandbox includes an entry for lo on the sandbox +host machine whose alias is "eth5". The following is an example of a network +operation being tested on the lo interface. + +.. code-block:: none + + TFTP + .... + + setenv ethrotate no + setenv ethact eth5 + tftpboot u-boot.bin + + +SPI Emulation +------------- + +Sandbox supports SPI and SPI flash emulation. + +The device can be enabled via a device tree, for example:: + + spi@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0 1>; + compatible = "sandbox,spi"; + cs-gpios = <0>, <&gpio_a 0>; + spi.bin@0 { + reg = <0>; + compatible = "spansion,m25p16", "jedec,spi-nor"; + spi-max-frequency = <40000000>; + sandbox,filename = "spi.bin"; + }; + }; + +The file must be created in advance:: + + $ dd if=/dev/zero of=spi.bin bs=1M count=2 + $ u-boot -T + +Here, you can use "-T" or "-D" option to specify test.dtb or u-boot.dtb, +respectively, or "-d " for your own dtb. + +With this setup you can issue SPI flash commands as normal:: + + =>sf probe + SF: Detected M25P16 with page size 64 KiB, total 2 MiB + =>sf read 0 0 10000 + SF: 65536 bytes @ 0x0 Read: OK + +Since this is a full SPI emulation (rather than just flash), you can +also use low-level SPI commands:: + + =>sspi 0:0 32 9f + FF202015 + +This is issuing a READ_ID command and getting back 20 (ST Micro) part +0x2015 (the M25P16). + +.. _sandbox_blk: + +Block Device Emulation +---------------------- + +U-Boot can use raw disk images for block device emulation. To e.g. list +the contents of the root directory on the second partion of the image +"disk.raw", you can use the following commands:: + + =>host bind 0 ./disk.raw + =>ls host 0:2 + +The device can be marked removeable with 'host bind -r'. + +A disk image can be created using the following commands:: + + $> truncate -s 1200M ./disk.raw + $> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk ./disk.raw + $> lodev=`sudo losetup -P -f --show ./disk.raw` + $> sudo mkfs.vfat -n EFI -v ${lodev}p1 + $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2 + +or utilize the device described in test/py/make_test_disk.py:: + + #!/usr/bin/python + import make_test_disk + make_test_disk.makeDisk() + +For more technical details, see :doc:`block_impl`. + +Writing Sandbox Drivers +----------------------- + +Generally you should put your driver in a file containing the word 'sandbox' +and put it in the same directory as other drivers of its type. You can then +implement the same hooks as the other drivers. + +To access U-Boot's emulated memory, use map_sysmem() as mentioned above. + +If your driver needs to store configuration or state (such as SPI flash +contents or emulated chip registers), you can use the device tree as +described above. Define handlers for this with the SANDBOX_STATE_IO macro. +See arch/sandbox/include/asm/state.h for documentation. In short you provide +a node name, compatible string and functions to read and write the state. +Since writing the state can expand the device tree, you may need to use +state_setprop() which does this automatically and avoids running out of +space. See existing code for examples. + + +VPL (Verifying Program Loader) +------------------------------ + +Sandbox provides an example build of vpl called `sandbox_vpl`. This can be run +using:: + + /path/to/sandbox_vpl/tpl/u-boot-tpl -D + +It starts up TPL (first-stage init), then VPL, then runs SPL and finally U-Boot +proper, following the normal flow for a verified boot. At present, no +verification is actually implemented. + + +Debugging the init sequence +--------------------------- + +If you get a failure in the initcall sequence, like this:: + + initcall sequence 0000560775957c80 failed at call 0000000000048134 (err=-96) + +Then you use can use grep to see which init call failed, e.g.:: + + $ grep 0000000000048134 u-boot.map + stdio_add_devices + +Of course another option is to run it with a debugger such as gdb:: + + $ gdb u-boot + ... + (gdb) br initcall.h:41 + Breakpoint 1 at 0x4db9d: initcall.h:41. (2 locations) + +Note that two locations are reported, since this function is used in both +board_init_f() and board_init_r(). + +.. code-block:: none + + (gdb) r + Starting program: /tmp/b/sandbox/u-boot + [Thread debugging using libthread_db enabled] + Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". + + U-Boot 2018.09-00264-ge0c2ba9814-dirty (Sep 22 2018 - 12:21:46 -0600) + + DRAM: 128 MiB + MMC: + + Breakpoint 1, initcall_run_list (init_sequence=0x5555559619e0 ) + at /scratch/sglass/cosarm/src/third_party/u-boot/files/include/initcall.h:41 + 41 printf("initcall sequence %p failed at call %p (err=%d)\n", + (gdb) print *init_fnc_ptr + $1 = (const init_fnc_t) 0x55555559c114 + (gdb) + + +This approach can be used on normal boards as well as sandbox. + +For debugging with GDB or LLDB, it is preferable to reduce the compiler +optimization level (CONFIG_CC_OPTIMIZE_FOR_DEBUG=y) and to disable Link Time +Optimization (CONFIG_LTO=n). + +SDL_CONFIG +---------- + +If sdl-config is on a different path from the default, set the SDL_CONFIG +environment variable to the correct pathname before building U-Boot. + + +Using valgrind / memcheck +------------------------- + +It is possible to run U-Boot under valgrind to check memory allocations:: + + valgrind ./u-boot + +However, this does not give very useful results. The sandbox allocates a memory +pool via mmap(). U-Boot's internal malloc() and free() work on this memory pool. +Custom allocators and deallocators are invisible to valgrind by default. To +expose U-Boot's malloc() and free() to valgrind, enable ``CONFIG_VALGRIND``. +Enabling this option will inject placeholder assembler code which valgrind +interprets. This is used to annotate sections of memory as safe or unsafe, and +to inform valgrind about malloc()s and free()s. There are currently no standard +placeholder assembly sequences for RISC-V, so this option cannot be enabled on +that architecture. + +Malloc's bookkeeping information is marked as unsafe by default. However, this +will generate many false positives when malloc itself accesses this information. +These warnings can be suppressed with:: + + valgrind --suppressions=scripts/u-boot.supp ./u-boot + +Additionally, you may experience false positives if U-Boot is using a smaller +pointer size than your host architecture. This is because the pointers used by +U-Boot will only contain 32 bits of addressing information. When interpreted as +64-bit pointers, valgrind will think that they are not initialized properly. To +fix this, enable ``CONFIG_SANDBOX64`` (such as via ``sandbox64_defconfig``) +when running on a 64-bit host. + +Additional options +^^^^^^^^^^^^^^^^^^ + +The following valgrind options are useful in addition to the above examples: + +``--trace-childen=yes`` + tells valgrind to keep tracking subprocesses, such + as when U-Boot jumps from TPL to SPL, or from SPL to U-Boot proper. + +``--track-origins=yes`` + will (for a small overhead) tell valgrind to keep + track of who allocated some troublesome memory. + +``--error-limit`` + will enable printing more than 1000 errors in a single session. + +``--vgdb=yes --vgdb-error=0`` + will let you use GDB to attach like:: + + gdb -ex "target remote | vgdb" u-boot + + This is very helpful for inspecting the program state when there is + an error. + +The following U-Boot option are also helpful: + +``-Tc 'ut all'`` + lets U-Boot run unit tests automatically. Note + that not all unit tests will succeed in the default configuration. + +``-t cooked`` + will keep the console in a sane state if you + terminate it early (instead of having to run tset). + +Future work +^^^^^^^^^^^ + +The biggest limitation to the current approach is that supressions don't +"un-taint" uninitialized memory accesses. Currently, dlmalloc's bookkeeping +information is marked as a "red zone." This means that all reads to that zone +are marked as illegal by valgrind. This is fine for regular code, but dlmalloc +really does need to access this area, so we suppress its violations. However, if +dlmalloc then passes a result calculated from a "tainted" access, that result is +still tainted. So the first accessor will raise a warning. This means that every +construct like + +.. code-block:: + + foo = malloc(sizeof(*foo)); + if (!foo) + return -ENOMEM; + +will raise a warning when we check the result of malloc. Whoops. + +There are at least four possible ways to address this: + +* Don't mark dlmalloc bookkeeping information as a red zone. This is the + simplest solution, but reduces the power of valgrind immensely, since we can + no longer determine that (e.g.) access past the end of an array is undefined. +* Implement red zones properly. This would involve growing every allocation by a + fixed amount (16 bytes or so) and then using that extra space for a real red + zone that neither regular code nor dlmalloc needs to access. Unfortunately, + this would probably some fairly intensive surgery to dlmalloc to add/remove + the offset appropriately. +* Mark bookkeeping information as valid before we use it in dlmalloc, and then + mark it invalid before returning. This would be the most correct, but it would + be very tricky to implement since there are so many code paths to mark. I + think it would be the most effort out of the three options here. +* Use the host malloc and free instead of U-Boot's custom allocator. This will + eliminate the need to annotate dlmalloc. However, using a different allocator + for sandbox will mean that bugs in dlmalloc will only be tested when running + on read (or emulated) hardware. + +Until one of the above options are implemented, it will remain difficult +to sift through the massive amount of spurious warnings. + +Testing +------- + +U-Boot sandbox can be used to run various tests, mostly in the test/ +directory. + +See :doc:`../../develop/tests_sandbox` for more information and +:doc:`../../develop/testing` for information about testing generally. + + +Memory Map +---------- + +Sandbox has its own emulated memory starting at 0. Here are some of the things +that are mapped into that memory: + +======= ======================== =============================== +Addr Config Usage +======= ======================== =============================== + 0 CONFIG_SYS_FDT_LOAD_ADDR Device tree + c000 CONFIG_BLOBLIST_ADDR Blob list + 10000 CONFIG_MALLOC_F_ADDR Early memory allocation + f0000 CONFIG_PRE_CON_BUF_ADDR Pre-console buffer + 100000 CONFIG_TRACE_EARLY_ADDR Early trace buffer (if enabled). Also used + as the SPL load buffer in spl_test_load(). + 200000 CONFIG_TEXT_BASE Load buffer for U-Boot (sandbox_spl only) +======= ======================== =============================== diff --git a/doc/usage/cmd/host.rst b/doc/usage/cmd/host.rst new file mode 100644 index 00000000000..e14508986ca --- /dev/null +++ b/doc/usage/cmd/host.rst @@ -0,0 +1,116 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +host command +============ + +Synopis +------- + +:: + + host bind [-r]