1.. SPDX-License-Identifier: GPL-2.0+ */
2.. Copyright (c) 2014 The Chromium OS Authors.
3.. sectionauthor:: Simon Glass <sjg@chromium.org>
4
5Sandbox
6=======
7
8Native Execution of U-Boot
9--------------------------
10
11The 'sandbox' architecture is designed to allow U-Boot to run under Linux on
12almost any hardware. To achieve this it builds U-Boot (so far as possible)
13as a normal C application with a main() and normal C libraries.
14
15All of U-Boot's architecture-specific code therefore cannot be built as part
16of the sandbox U-Boot. The purpose of running U-Boot under Linux is to test
17all the generic code, not specific to any one architecture. The idea is to
18create unit tests which we can run to test this upper level code.
19
20Sandbox allows development of many types of new features in a traditional way,
21rather than needing to test each iteration on real hardware. Many U-Boot
22features were developed on sandbox, including the core driver model, most
23uclasses, verified boot, bloblist, logging and dozens of others. Sandbox has
24enabled many large-scale code refactors as well.
25
26CONFIG_SANDBOX is defined when building a native board.
27
28The board name is 'sandbox' but the vendor name is unset, so there is a
29single board in board/sandbox.
30
31CONFIG_SANDBOX_BIG_ENDIAN should be defined when running on big-endian
32machines.
33
34There are two versions of the sandbox: One using 32-bit-wide integers, and one
35using 64-bit-wide integers. The 32-bit version can be build and run on either
3632 or 64-bit hosts by either selecting or deselecting CONFIG_SANDBOX_32BIT; by
37default, the sandbox it built for a 32-bit host. The sandbox using 64-bit-wide
38integers can only be built on 64-bit hosts.
39
40Note that standalone/API support is not available at present.
41
42
43Prerequisites
44-------------
45
46Install the dependencies noted in :doc:`../../build/gcc`.
47
48
49Basic Operation
50---------------
51
52To run sandbox U-Boot use something like::
53
54   make sandbox_defconfig all
55   ./u-boot
56
57Note: If you get errors about 'sdl-config: Command not found' you may need to
58install libsdl2.0-dev or similar to get SDL support. Alternatively you can
59build sandbox without SDL (i.e. no display/keyboard support) by disabling
60CONFIG_SANDBOX_SDL in the .config file.
61
62U-Boot will start on your computer, showing a sandbox emulation of the serial
63console::
64
65   U-Boot 2014.04 (Mar 20 2014 - 19:06:00)
66
67   DRAM:  128 MiB
68   Using default environment
69
70   In:    serial
71   Out:   lcd
72   Err:   lcd
73   =>
74
75You can issue commands as your would normally. If the command you want is
76not supported you can add it to include/configs/sandbox.h.
77
78To exit, type 'poweroff' or press Ctrl-C.
79
80
81Console / LCD support
82---------------------
83
84Assuming that CONFIG_SANDBOX_SDL is enabled when building, you can run the
85sandbox with LCD and keyboard emulation, using something like::
86
87   ./u-boot -d u-boot.dtb -l
88
89This will start U-Boot with a window showing the contents of the LCD. If
90that window has the focus then you will be able to type commands as you
91would on the console. You can adjust the display settings in the device
92tree file - see arch/sandbox/dts/sandbox.dts.
93
94
95Command-line Options
96--------------------
97
98Various options are available, mostly for test purposes. Use -h to see
99available options. Some of these are described below:
100
101-t, --terminal <arg>
102  The terminal is normally in what is called 'raw-with-sigs' mode. This means
103  that you can use arrow keys for command editing and history, but if you
104  press Ctrl-C, U-Boot will exit instead of handling this as a keypress.
105  Other options are 'raw' (so Ctrl-C is handled within U-Boot) and 'cooked'
106  (where the terminal is in cooked mode and cursor keys will not work, Ctrl-C
107  will exit).
108
109-l
110  Show the LCD emulation window.
111
112-d <device_tree>
113  A device tree binary file can be provided with -d. If you edit the source
114  (it is stored at arch/sandbox/dts/sandbox.dts) you must rebuild U-Boot to
115  recreate the binary file.
116
117-D
118  To use the default device tree, use -D.
119
120-T
121  To use the test device tree, use -T.
122
123-c [<cmd>;]<cmd>
124  To execute commands directly, use the -c option. You can specify a single
125  command, or multiple commands separated by a semicolon, as is normal in
126  U-Boot. Be careful with quoting as the shell will normally process and
127  swallow quotes. When -c is used, U-Boot exits after the command is complete,
128  but you can force it to go to interactive mode instead with -i.
129
130-i
131  Go to interactive mode after executing the commands specified by -c.
132
133Environment Variables
134---------------------
135
136UBOOT_SB_TIME_OFFSET
137    This environment variable stores the offset of the emulated real time clock
138    to the host's real time clock in seconds. The offset defaults to zero.
139
140Memory Emulation
141----------------
142
143Memory emulation is supported, with the size set by CONFIG_SANDBOX_RAM_SIZE_MB.
144The -m option can be used to read memory from a file on start-up and write
145it when shutting down. This allows preserving of memory contents across
146test runs. You can tell U-Boot to remove the memory file after it is read
147(on start-up) with the --rm_memory option.
148
149To access U-Boot's emulated memory within the code, use map_sysmem(). This
150function is used throughout U-Boot to ensure that emulated memory is used
151rather than the U-Boot application memory. This provides memory starting
152at 0 and extending to the size of the emulation.
153
154
155Storing State
156-------------
157
158With sandbox you can write drivers which emulate the operation of drivers on
159real devices. Some of these drivers may want to record state which is
160preserved across U-Boot runs. This is particularly useful for testing. For
161example, the contents of a SPI flash chip should not disappear just because
162U-Boot exits.
163
164State is stored in a device tree file in a simple format which is driver-
165specific. You then use the -s option to specify the state file. Use -r to
166make U-Boot read the state on start-up (otherwise it starts empty) and -w
167to write it on exit (otherwise the stored state is left unchanged and any
168changes U-Boot made will be lost). You can also use -n to tell U-Boot to
169ignore any problems with missing state. This is useful when first running
170since the state file will be empty.
171
172The device tree file has one node for each driver - the driver can store
173whatever properties it likes in there. See 'Writing Sandbox Drivers' below
174for more details on how to get drivers to read and write their state.
175
176
177Running and Booting
178-------------------
179
180Since there is no machine architecture, sandbox U-Boot cannot actually boot
181a kernel, but it does support the bootm command. Filesystems, memory
182commands, hashing, FIT images, verified boot and many other features are
183supported.
184
185When 'bootm' runs a kernel, sandbox will exit, as U-Boot does on a real
186machine. Of course in this case, no kernel is run.
187
188It is also possible to tell U-Boot that it has jumped from a temporary
189previous U-Boot binary, with the -j option. That binary is automatically
190removed by the U-Boot that gets the -j option. This allows you to write
191tests which emulate the action of chain-loading U-Boot, typically used in
192a situation where a second 'updatable' U-Boot is stored on your board. It
193is very risky to overwrite or upgrade the only U-Boot on a board, since a
194power or other failure will brick the board and require return to the
195manufacturer in the case of a consumer device.
196
197
198Supported Drivers
199-----------------
200
201U-Boot sandbox supports these emulations:
202
203- Arm FF-A
204- Block devices
205- Chrome OS EC
206- GPIO
207- Host filesystem (access files on the host from within U-Boot)
208- I2C
209- Keyboard (Chrome OS)
210- LCD
211- Network
212- Serial (for console only)
213- Sound (incomplete - see sandbox_sdl_sound_init() for details)
214- SPI
215- SPI flash
216- TPM (Trusted Platform Module)
217
218A wide range of commands are implemented. Filesystems which use a block
219device are supported.
220
221Also sandbox supports driver model (CONFIG_DM) and associated commands.
222
223
224Sandbox Variants
225----------------
226
227There are unfortunately quite a few variants at present:
228
229sandbox:
230  should be used for most tests
231sandbox64:
232  special build that forces a 64-bit host
233sandbox_flattree:
234  builds with dev_read\_...() functions defined as inline.
235  We need this build so that we can test those inline functions, and we
236  cannot build with both the inline functions and the non-inline functions
237  since they are named the same.
238sandbox_spl:
239  builds sandbox with SPL support, so you can run spl/u-boot-spl
240  and it will start up and then load ./u-boot. It is also possible to
241  run ./u-boot directly.
242
243Of these sandbox_spl can probably be removed since it is a superset of sandbox.
244
245Most of the config options should be identical between these variants.
246
247
248Linux RAW Networking Bridge
249---------------------------
250
251The sandbox_eth_raw driver bridges traffic between the bottom of the network
252stack and the RAW sockets API in Linux. This allows much of the U-Boot network
253functionality to be tested in sandbox against real network traffic.
254
255For Ethernet network adapters, the bridge utilizes the RAW AF_PACKET API.  This
256is needed to get access to the lowest level of the network stack in Linux. This
257means that all of the Ethernet frame is included. This allows the U-Boot network
258stack to be fully used. In other words, nothing about the Linux network stack is
259involved in forming the packets that end up on the wire. To receive the
260responses to packets sent from U-Boot the network interface has to be set to
261promiscuous mode so that the network card won't filter out packets not destined
262for its configured (on Linux) MAC address.
263
264The RAW sockets Ethernet API requires elevated privileges in Linux. You can
265either run as root, or you can add the capability needed like so::
266
267   sudo /sbin/setcap "CAP_NET_RAW+ep" /path/to/u-boot
268
269The default device tree for sandbox includes an entry for eth0 on the sandbox
270host machine whose alias is "eth1". The following are a few examples of network
271operations being tested on the eth0 interface.
272
273.. code-block:: none
274
275   sudo /path/to/u-boot -D
276
277   DHCP
278   ....
279
280   setenv autoload no
281   setenv ethrotate no
282   setenv ethact eth1
283   dhcp
284
285   PING
286   ....
287
288   setenv autoload no
289   setenv ethrotate no
290   setenv ethact eth1
291   dhcp
292   ping $gatewayip
293
294   TFTP
295   ....
296
297   setenv autoload no
298   setenv ethrotate no
299   setenv ethact eth1
300   dhcp
301   setenv serverip WWW.XXX.YYY.ZZZ
302   tftpboot u-boot.bin
303
304The bridge also supports (to a lesser extent) the localhost interface, 'lo'.
305
306The 'lo' interface cannot use the RAW AF_PACKET API because the lo interface
307doesn't support Ethernet-level traffic. It is a higher-level interface that is
308expected only to be used at the AF_INET level of the API. As such, the most raw
309we can get on that interface is the RAW AF_INET API on UDP. This allows us to
310set the IP_HDRINCL option to include everything except the Ethernet header in
311the packets we send and receive.
312
313Because only UDP is supported, ICMP traffic will not work, so expect that ping
314commands will time out.
315
316The default device tree for sandbox includes an entry for lo on the sandbox
317host machine whose alias is "eth5". The following is an example of a network
318operation being tested on the lo interface.
319
320.. code-block:: none
321
322   TFTP
323   ....
324
325   setenv ethrotate no
326   setenv ethact eth5
327   tftpboot u-boot.bin
328
329
330SPI Emulation
331-------------
332
333Sandbox supports SPI and SPI flash emulation.
334
335The device can be enabled via a device tree, for example::
336
337    spi@0 {
338            #address-cells = <1>;
339            #size-cells = <0>;
340            reg = <0 1>;
341            compatible = "sandbox,spi";
342            cs-gpios = <0>, <&gpio_a 0>;
343            spi.bin@0 {
344                    reg = <0>;
345                    compatible = "spansion,m25p16", "jedec,spi-nor";
346                    spi-max-frequency = <40000000>;
347                    sandbox,filename = "spi.bin";
348            };
349    };
350
351The file must be created in advance::
352
353   $ dd if=/dev/zero of=spi.bin bs=1M count=2
354   $ u-boot -T
355
356Here, you can use "-T" or "-D" option to specify test.dtb or u-boot.dtb,
357respectively, or "-d <file>" for your own dtb.
358
359With this setup you can issue SPI flash commands as normal::
360
361   =>sf probe
362   SF: Detected M25P16 with page size 64 KiB, total 2 MiB
363   =>sf read 0 0 10000
364   SF: 65536 bytes @ 0x0 Read: OK
365
366Since this is a full SPI emulation (rather than just flash), you can
367also use low-level SPI commands::
368
369   =>sspi 0:0 32 9f
370   FF202015
371
372This is issuing a READ_ID command and getting back 20 (ST Micro) part
3730x2015 (the M25P16).
374
375.. _sandbox_blk:
376
377Block Device Emulation
378----------------------
379
380U-Boot can use raw disk images for block device emulation. To e.g. list
381the contents of the root directory on the second partion of the image
382"disk.raw", you can use the following commands::
383
384   =>host bind 0 ./disk.raw
385   =>ls host 0:2
386
387The device can be marked removeable with 'host bind -r'.
388
389A disk image can be created using the following commands::
390
391   $> truncate -s 1200M ./disk.raw
392   $> /usr/sbin/sgdisk --new=1:0:+64M --typecode=1:EF00 --new=2:0:0 --typecode=2:8300 disk.raw
393   $> lodev=`sudo losetup -P -f --show ./disk.raw`
394   $> sudo mkfs.vfat -n EFI -v ${lodev}p1
395   $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2
396
397or utilize the device described in test/py/make_test_disk.py::
398
399   #!/usr/bin/python
400   import make_test_disk
401   make_test_disk.makeDisk()
402
403For more technical details, see :doc:`block_impl`.
404
405Writing Sandbox Drivers
406-----------------------
407
408Generally you should put your driver in a file containing the word 'sandbox'
409and put it in the same directory as other drivers of its type. You can then
410implement the same hooks as the other drivers.
411
412To access U-Boot's emulated memory, use map_sysmem() as mentioned above.
413
414If your driver needs to store configuration or state (such as SPI flash
415contents or emulated chip registers), you can use the device tree as
416described above. Define handlers for this with the SANDBOX_STATE_IO macro.
417See arch/sandbox/include/asm/state.h for documentation. In short you provide
418a node name, compatible string and functions to read and write the state.
419Since writing the state can expand the device tree, you may need to use
420state_setprop() which does this automatically and avoids running out of
421space. See existing code for examples.
422
423
424VPL (Verifying Program Loader)
425------------------------------
426
427Sandbox provides an example build of vpl called `sandbox_vpl`. To build it:
428
429.. code-block:: bash
430
431   make sandbox_vpl_defconfig all
432
433This can be run using:
434
435.. code-block:: bash
436
437   ./tpl/u-boot-tpl -d u-boot.dtb
438
439It starts up TPL (first-stage init), then VPL, then runs SPL and finally U-Boot
440proper, following the normal flow for a verified boot. At present, no
441verification is actually implemented.
442
443Here is an example trace::
444
445   U-Boot TPL 2024.01-rc2-00129 (Nov 19 2023 - 08:10:12 -0700)
446   Trying to boot from sandbox_image
447   Trying to boot from sandbox_file
448
449   U-Boot VPL 2024.01-rc2-00129 (Nov 19 2023 - 08:10:12 -0700)
450   Trying to boot from vbe_simple
451   Trying to boot from sandbox_image
452   Trying to boot from sandbox_file
453
454   U-Boot SPL 2024.01-rc2-00129 (Nov 19 2023 - 08:10:12 -0700)
455   Trying to boot from vbe_simple
456   Trying to boot from sandbox_image
457   Trying to boot from sandbox_file
458
459
460   U-Boot 2024.01-rc2-00129 (Nov 19 2023 - 08:10:12 -0700)
461
462   Reset Status: COLD
463   Model: sandbox
464   DRAM:  256 MiB
465   using memory 0x1b576000-0x1f578000 for malloc()
466
467   Warning: host_lo MAC addresses don't match:
468   Address in ROM is		96:cd:ef:82:78:51
469   Address in environment is	02:00:11:22:33:44
470   Core:  103 devices, 51 uclasses, devicetree: board
471   MMC:
472   Loading Environment from nowhere... OK
473   In:    serial,cros-ec-keyb,usbkbd
474   Out:   serial,vidconsole
475   Err:   serial,vidconsole
476   Model: sandbox
477   Net:   eth0: host_lo, eth1: host_enp14s0, eth2: host_eth6, eth3: host_wlp15s0, eth4: host_virbr0, eth5: host_docker0, eth6: eth@10002000
478   Hit any key to stop autoboot:  1
479
480
481Debugging the init sequence
482---------------------------
483
484If you get a failure in the initcall sequence, like this::
485
486   initcall sequence 0000560775957c80 failed at call 0000000000048134 (err=-96)
487
488Then you use can use grep to see which init call failed, e.g.::
489
490   $ grep 0000000000048134 u-boot.map
491   stdio_add_devices
492
493Of course another option is to run it with a debugger such as gdb::
494
495   $ gdb u-boot
496   ...
497   (gdb) br initcall.h:41
498   Breakpoint 1 at 0x4db9d: initcall.h:41. (2 locations)
499
500Note that two locations are reported, since this function is used in both
501board_init_f() and board_init_r().
502
503.. code-block:: none
504
505   (gdb) r
506   Starting program: /tmp/b/sandbox/u-boot
507   [Thread debugging using libthread_db enabled]
508   Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
509
510   U-Boot 2018.09-00264-ge0c2ba9814-dirty (Sep 22 2018 - 12:21:46 -0600)
511
512   DRAM:  128 MiB
513   MMC:
514
515   Breakpoint 1, initcall_run_list (init_sequence=0x5555559619e0 <init_sequence_f>)
516       at /scratch/sglass/cosarm/src/third_party/u-boot/files/include/initcall.h:41
517   41                              printf("initcall sequence %p failed at call %p (err=%d)\n",
518   (gdb) print *init_fnc_ptr
519   $1 = (const init_fnc_t) 0x55555559c114 <stdio_add_devices>
520   (gdb)
521
522
523This approach can be used on normal boards as well as sandbox.
524
525For debugging with GDB or LLDB, it is preferable to reduce the compiler
526optimization level (CONFIG_CC_OPTIMIZE_FOR_DEBUG=y) and to disable Link Time
527Optimization (CONFIG_LTO=n).
528
529SDL_CONFIG
530----------
531
532If sdl-config is on a different path from the default, set the SDL_CONFIG
533environment variable to the correct pathname before building U-Boot.
534
535
536Using valgrind / memcheck
537-------------------------
538
539It is possible to run U-Boot under valgrind to check memory allocations::
540
541    valgrind ./u-boot
542
543However, this does not give very useful results. The sandbox allocates a memory
544pool via mmap(). U-Boot's internal malloc() and free() work on this memory pool.
545Custom allocators and deallocators are invisible to valgrind by default. To
546expose U-Boot's malloc() and free() to valgrind, enable ``CONFIG_VALGRIND``.
547Enabling this option will inject placeholder assembler code which valgrind
548interprets. This is used to annotate sections of memory as safe or unsafe, and
549to inform valgrind about malloc()s and free()s. There are currently no standard
550placeholder assembly sequences for RISC-V, so this option cannot be enabled on
551that architecture.
552
553Malloc's bookkeeping information is marked as unsafe by default. However, this
554will generate many false positives when malloc itself accesses this information.
555These warnings can be suppressed with::
556
557    valgrind --suppressions=scripts/u-boot.supp ./u-boot
558
559Additionally, you may experience false positives if U-Boot is using a smaller
560pointer size than your host architecture. This is because the pointers used by
561U-Boot will only contain 32 bits of addressing information. When interpreted as
56264-bit pointers, valgrind will think that they are not initialized properly. To
563fix this, enable ``CONFIG_SANDBOX64`` (such as via ``sandbox64_defconfig``)
564when running on a 64-bit host.
565
566Additional options
567^^^^^^^^^^^^^^^^^^
568
569The following valgrind options are useful in addition to the above examples:
570
571``--trace-childen=yes``
572    tells valgrind to keep tracking subprocesses, such
573    as when U-Boot jumps from TPL to SPL, or from SPL to U-Boot proper.
574
575``--track-origins=yes``
576    will (for a small overhead) tell valgrind to keep
577    track of who allocated some troublesome memory.
578
579``--error-limit``
580    will enable printing more than 1000 errors in a single session.
581
582``--vgdb=yes --vgdb-error=0``
583    will let you use GDB to attach like::
584
585        gdb -ex "target remote | vgdb" u-boot
586
587    This is very helpful for inspecting the program state when there is
588    an error.
589
590The following U-Boot option are also helpful:
591
592``-Tc 'ut all'``
593    lets U-Boot run unit tests automatically. Note
594    that not all unit tests will succeed in the default configuration.
595
596``-t cooked``
597    will keep the console in a sane state if you
598    terminate it early (instead of having to run tset).
599
600Future work
601^^^^^^^^^^^
602
603The biggest limitation to the current approach is that supressions don't
604"un-taint" uninitialized memory accesses. Currently, dlmalloc's bookkeeping
605information is marked as a "red zone." This means that all reads to that zone
606are marked as illegal by valgrind. This is fine for regular code, but dlmalloc
607really does need to access this area, so we suppress its violations. However, if
608dlmalloc then passes a result calculated from a "tainted" access, that result is
609still tainted. So the first accessor will raise a warning. This means that every
610construct like
611
612.. code-block::
613
614    foo = malloc(sizeof(*foo));
615    if (!foo)
616        return -ENOMEM;
617
618will raise a warning when we check the result of malloc. Whoops.
619
620There are at least four possible ways to address this:
621
622* Don't mark dlmalloc bookkeeping information as a red zone. This is the
623  simplest solution, but reduces the power of valgrind immensely, since we can
624  no longer determine that (e.g.) access past the end of an array is undefined.
625* Implement red zones properly. This would involve growing every allocation by a
626  fixed amount (16 bytes or so) and then using that extra space for a real red
627  zone that neither regular code nor dlmalloc needs to access. Unfortunately,
628  this would probably some fairly intensive surgery to dlmalloc to add/remove
629  the offset appropriately.
630* Mark bookkeeping information as valid before we use it in dlmalloc, and then
631  mark it invalid before returning. This would be the most correct, but it would
632  be very tricky to implement since there are so many code paths to mark. I
633  think it would be the most effort out of the three options here.
634* Use the host malloc and free instead of U-Boot's custom allocator. This will
635  eliminate the need to annotate dlmalloc. However, using a different allocator
636  for sandbox will mean that bugs in dlmalloc will only be tested when running
637  on read (or emulated) hardware.
638
639Until one of the above options are implemented, it will remain difficult
640to sift through the massive amount of spurious warnings.
641
642Testing
643-------
644
645U-Boot sandbox can be used to run various tests, mostly in the test/
646directory.
647
648See :doc:`../../develop/tests_sandbox` for more information and
649:doc:`../../develop/testing` for information about testing generally.
650
651
652Memory Map
653----------
654
655Sandbox has its own emulated memory starting at 0. Here are some of the things
656that are mapped into that memory:
657
658=======   ========================   ===============================
659Addr      Config                     Usage
660=======   ========================   ===============================
661    100   CONFIG_SYS_FDT_LOAD_ADDR   Device tree
662   b000   CONFIG_BLOBLIST_ADDR       Blob list
663  10000   CFG_MALLOC_F_ADDR          Early memory allocation
664  f0000   CONFIG_PRE_CON_BUF_ADDR    Pre-console buffer
665 100000   CONFIG_TRACE_EARLY_ADDR    Early trace buffer (if enabled). Also used
666                                     as the SPL load buffer in spl_test_load().
667 200000   CONFIG_TEXT_BASE           Load buffer for U-Boot (sandbox_spl only)
668=======   ========================   ===============================
669