[PATCH 00/18] ulib: Introduce building U-Boot as a shared library

From: Simon Glass <sjg@chromium.org> U-Boot is currently built as a monolithic binary. While there is an API of sorts, allowing U-Boot to be called from another program, it is not widely used. In some cases it is useful to write a separate program which is in control of the boot process, but uses U-Boot to implement some of the functionality. Some examples are: - Creating a main program written in a different language, such as Rust or Python - For Python specifically, an interface on top of U-Boot would permit direct execution of sandbox tests - For Rust specifically, it could make it feasible to progressively rewrite U-Boot in Rust, if that were desirable - For testing, it would permit tests to be in control of execution, rather than being embedded within U-Boot itself This series begins the progress of supporting U-Boot as a shared library. At this point the functionality is very limited: - it targets sandbox only - the test program simply starts U-Boot and boots to a prompt Future work will build on this meagre foundation. Simon Glass (18): doc: Add fuzzing build documentation board_r: Drop MMC init from the startup sequence sandbox: Avoid mon_len being larger than available RAM sandbox: Move PCI functions to separate header file sandbox: Move main.h contents into u-boot-sandbox header sandbox: Split main() into separate file sandbox: Extract init code into sandbox_init() ulib: Add an option to build U-Boot as a library ulib: Support building U-Boot as a shared library ulib: Create a test program for the shared library ulib: Add linker script for shared library build ulib: efi: Disable relocation or runtime-services ulib: Enable building the ulib test program ulib: Implement GD_FLG_ULIB for library-usage mode ulib: Drop the initial banner for the library ulib: Drop DRAM announcements for the library ulib: Allow dropping NAND init from the startup sequence ulib: Drop dm stats for the library Kconfig | 9 + Makefile | 31 ++- arch/sandbox/cpu/Makefile | 7 +- arch/sandbox/cpu/fuzz.c | 81 ++++++++ arch/sandbox/cpu/main.c | 11 ++ arch/sandbox/cpu/mem.c | 1 + arch/sandbox/cpu/os.c | 76 +------- arch/sandbox/cpu/start.c | 26 ++- arch/sandbox/cpu/u-boot-lib.lds | 88 +++++++++ arch/sandbox/include/asm/main.h | 18 -- arch/sandbox/include/asm/sandbox_pci.h | 61 ++++++ arch/sandbox/include/asm/u-boot-sandbox.h | 76 ++++---- common/board_f.c | 24 ++- common/board_r.c | 17 +- configs/tools-only_defconfig | 1 + doc/build/fuzz.rst | 219 ++++++++++++++++++++++ doc/build/index.rst | 1 + drivers/pci/pci-emul-uclass.c | 3 +- include/asm-generic/global_data.h | 12 ++ lib/display_options.c | 15 +- lib/efi_loader/efi_runtime.c | 4 + test/dm/pci.c | 1 + test/ulib/Makefile | 12 ++ test/ulib/ulib_test.c | 37 ++++ 24 files changed, 658 insertions(+), 173 deletions(-) create mode 100644 arch/sandbox/cpu/fuzz.c create mode 100644 arch/sandbox/cpu/main.c create mode 100644 arch/sandbox/cpu/u-boot-lib.lds delete mode 100644 arch/sandbox/include/asm/main.h create mode 100644 arch/sandbox/include/asm/sandbox_pci.h create mode 100644 doc/build/fuzz.rst create mode 100644 test/ulib/Makefile create mode 100644 test/ulib/ulib_test.c -- 2.43.0 base-commit: 9bdc48e838ab200854c37fdb770fdd2abdeacc83 branch: ulib

From: Simon Glass <sjg@chromium.org> Add some docs for using fuzzing with U-Boot, including building, running tests, and adding new tests. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- doc/build/fuzz.rst | 219 ++++++++++++++++++++++++++++++++++++++++++++ doc/build/index.rst | 1 + 2 files changed, 220 insertions(+) create mode 100644 doc/build/fuzz.rst diff --git a/doc/build/fuzz.rst b/doc/build/fuzz.rst new file mode 100644 index 00000000000..4c05df4dc21 --- /dev/null +++ b/doc/build/fuzz.rst @@ -0,0 +1,219 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +Building U-Boot with Fuzzing Support +===================================== + +U-Boot supports fuzzing through libFuzzer when built for the sandbox +architecture. Fuzzing helps identify security vulnerabilities and crashes by +testing with randomly generated inputs. + +Prerequisites +------------- + +The following tools are required: + +* Clang compiler with fuzzing support +* libstdc++ development libraries + +On Ubuntu/Debian systems, install the required packages:: + + sudo apt install clang libstdc++-dev + +Building with Fuzzing +--------------------- + +The recommended approach is to use buildman, which handles the configuration +automatically: + +1. Build with buildman (recommended):: + + buildman --bo sandbox -a FUZZ=y -O clang -L -o /tmp/fuzz -w + +The buildman options: + +* ``--booard sandbox`` - Build for sandbox board only +* ``-a FUZZ=y`` - Enable fuzzing support via CONFIG_FUZZ=y +* ``-O clang`` - Use Clang compiler (required for fuzzing) +* ``-L`` - Disable LTO to avoid sanitizer coverage linker issues +* ``-o /tmp/fuzz`` - Output directory +* ``-w`` - Use the output directory as the work directory + +Alternative: Manual build +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To build manually with make: + +1. Configure the build with fuzzing enabled:: + + make HOSTCC=clang CC=clang O=/tmp/fuzz LTO_ENABLE= sandbox_defconfig + scripts/config --file /tmp/fuzz/.config --enable FUZZ + +2. Build the fuzzing-enabled binary:: + + make HOSTCC=clang CC=clang O=/tmp/fuzz LTO_ENABLE= -j$(nproc) + +Build Output +------------ + +The fuzzing build produces: + +* ``u-boot`` - Main fuzzing binary with AddressSanitizer and fuzzer + instrumentation +* Significantly larger binary size due to instrumentation (typically 40-50MB) +* Debug symbols included for better crash analysis + +Fuzzing Architecture +-------------------- + +The U-Boot fuzzing implementation consists of: + +* **Fuzzing Engine**: Sandbox-specific driver that interfaces with libFuzzer +* **Threading Model**: Separate threads for fuzzing harness and U-Boot + execution +* **Input Handling**: ``LLVMFuzzerTestOneInput()`` entry point processes + fuzz inputs +* **Command Fuzzing**: Tests U-Boot commands with generated inputs via + ``fuzz`` command + +Key source files: + +* ``arch/sandbox/cpu/fuzz.c`` - Main fuzzing implementation +* ``drivers/fuzz/`` - Fuzzing engine drivers +* ``test/fuzz/`` - Fuzzing test cases +* ``include/fuzzing_engine.h`` - Fuzzing engine interface + +Running Fuzz Tests +------------------ + +To run fuzzing tests, set the test name via environment variable and run the +fuzzing binary from the build directory: + +1. Change to the build directory:: + + cd /tmp/fuzz + +2. Set the fuzz test to run:: + + export UBOOT_SB_FUZZ_TEST=fuzz_vring + +3. Run the fuzzer:: + + ./u-boot + +The fuzzer will start libFuzzer with coverage-guided input generation. You +should see output similar to:: + + INFO: Running with entropic power schedule (0xFF, 100). + INFO: Seed: 1626867009 + INFO: Loaded 1 modules (104150 inline 8-bit counters): ... + #2 INITED cov: 28 ft: 29 corp: 1/1b exec/s: 0 rss: 318Mb + #4 NEW cov: 29 ft: 30 corp: 2/3b lim: 4 exec/s: 0 rss: 319Mb + +Available fuzz tests include: + +* ``fuzz_vring`` - Tests VirtIO ring buffer handling + +To stop fuzzing, use Ctrl+C. The fuzzer will automatically save any crash- +inducing inputs for later analysis. + +Understanding Fuzzer Output +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The fuzzer output shows: + +* ``cov: N`` - Number of code coverage points reached +* ``ft: N`` - Number of features discovered +* ``corp: N/Mb`` - Corpus size (number of test cases / total bytes) +* ``exec/s: N`` - Executions per second (performance metric) +* ``rss: NMb`` - Memory usage + +Error messages from the target code (like VirtIO "out of range" errors) are +expected and indicate the fuzzer is finding edge cases. + +Adding New Fuzz Tests +--------------------- + +To create a new fuzz test, follow these steps: + +1. **Create the test file** in ``test/fuzz/`` directory:: + + /* SPDX-License-Identifier: GPL-2.0+ */ + #include <test/fuzz.h> + + static int fuzz_my_component(const uint8_t *data, size_t size) + { + /* Your fuzzing logic here */ + if (size < 4) + return 0; /* Not enough data */ + + /* Test your component with fuzzed data */ + my_component_function(data, size); + + return 0; + } + FUZZ_TEST(fuzz_my_component, 0); + +2. **Add to Makefile** in ``test/fuzz/Makefile``:: + + obj-$(CONFIG_MY_COMPONENT) += my_component.o + + Or for tests that should always be included:: + + obj-y += my_component.o + +3. **Test the new fuzzer**:: + + export UBOOT_SB_FUZZ_TEST=fuzz_my_component + ./u-boot + +**Best practices for fuzz tests:** + +* **Input validation**: Check minimum data size requirements +* **Error handling**: Handle invalid inputs gracefully, don't panic +* **Resource cleanup**: Free any allocated resources +* **Focused testing**: Target specific functions or code paths +* **Deterministic**: Same input should produce same behavior + +**Example patterns:** + +* Parse structured data (protocols, file formats) +* Test buffer handling with varying sizes +* Exercise error paths with malformed inputs +* Stress test with boundary conditions + +Troubleshooting +--------------- + +**Linker errors about missing libstdc++**: + Install libstdc++ development libraries as shown in Prerequisites. + +**Sanitizer coverage linker errors**: + Ensure LTO is disabled with ``LTO_ENABLE=`` in the make command. + +**Build fails with GCC**: + Fuzzing requires Clang. Ensure both CC and HOSTCC are set to clang. + +**Fuzzer exits with "fdtdec_setup() failed"**: + Run the fuzzer from the build directory where u-boot.dtb is located. + The sandbox requires access to its device tree file. + +Security Considerations +----------------------- + +Fuzzing builds include: + +* **AddressSanitizer**: Detects buffer overflows, use-after-free, and other + memory errors +* **Fuzzer Coverage**: Instruments code for coverage-guided fuzzing +* **Debug Information**: Retained for crash analysis and debugging + +These features significantly increase binary size and runtime overhead, making +fuzzing builds unsuitable for production use. + +Further Reading +--------------- + +* :doc:`/arch/sandbox/sandbox` - General sandbox architecture documentation +* libFuzzer documentation: https://llvm.org/docs/LibFuzzer.html +* AddressSanitizer documentation: + https://clang.llvm.org/docs/AddressSanitizer.html diff --git a/doc/build/index.rst b/doc/build/index.rst index 7a4507b5746..bd380a5e6c2 100644 --- a/doc/build/index.rst +++ b/doc/build/index.rst @@ -9,6 +9,7 @@ Build U-Boot source gcc clang + fuzz reproducible docker tools -- 2.43.0

From: Simon Glass <sjg@chromium.org> This should be handled by driver model now. In any case there is nothing special about MMC which indicates that it should be inited and announced at startup. Drop it. Signed-off-by: Simon Glass <sjg@chromium.org> --- common/board_r.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/common/board_r.c b/common/board_r.c index de28079a0c5..d60cc7aac70 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -381,15 +381,6 @@ static int initr_onenand(void) } #endif -#ifdef CONFIG_MMC -static int initr_mmc(void) -{ - puts("MMC: "); - mmc_initialize(gd->bd); - return 0; -} -#endif - #ifdef CONFIG_PVBLOCK static int initr_pvblock(void) { @@ -667,9 +658,6 @@ static void initcall_run_r(void) #if CONFIG_IS_ENABLED(CMD_ONENAND) INITCALL(initr_onenand); #endif -#if CONFIG_IS_ENABLED(MMC) - INITCALL(initr_mmc); -#endif #if CONFIG_IS_ENABLED(XEN) INITCALL(xen_init); #endif -- 2.43.0

From: Simon Glass <sjg@chromium.org> With the shared library the size can be quite large. Normally sandbox pretends that its code is mapped into emulated RAM, even though it actually isn't. This is fine in most cases, but when mon_len exceeds the RAM size the reservation top starts off at a negative address (i.e. very near the top of the address space), which immediately segfaults. Add a special case for this, for sandbox only. We might consider dropping this mapping altogether, as is down with RISC-V, but that is left for further discussion. With this, the test app boots to a prompt. Signed-off-by: Simon Glass <sjg@chromium.org> --- common/board_f.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/board_f.c b/common/board_f.c index 3a4fb9a42ef..eac51d61fa1 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -460,7 +460,11 @@ static int reserve_uboot(void) * reserve memory for U-Boot code, data & bss * round down to next 4 kB limit */ - gd->relocaddr -= gd->mon_len; + if (IS_ENABLED(CONFIG_SANDBOX) && gd->mon_len > gd->relocaddr) + log_debug("Cannot reserve space for U-Boot\n"); + else + gd->relocaddr -= gd->mon_len; + gd->relocaddr &= ~(4096 - 1); #if defined(CONFIG_E500) || defined(CONFIG_MIPS) /* round down to next 64 kB limit so that IVPR stays aligned */ -- 2.43.0

From: Simon Glass <sjg@chromium.org> Move pci_map_physmem(), pci_unmap_physmem(), and sandbox_set_enable_pci_map() from u-boot-sandbox.h to a new file sandbox_pci.h to simplify dependencies. Fix the header order in the PCI emul file while we are here. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/sandbox/cpu/mem.c | 1 + arch/sandbox/include/asm/sandbox_pci.h | 61 +++++++++++++++++++++++ arch/sandbox/include/asm/u-boot-sandbox.h | 50 +------------------ drivers/pci/pci-emul-uclass.c | 3 +- test/dm/pci.c | 1 + 5 files changed, 67 insertions(+), 49 deletions(-) create mode 100644 arch/sandbox/include/asm/sandbox_pci.h diff --git a/arch/sandbox/cpu/mem.c b/arch/sandbox/cpu/mem.c index 4e9b629e3aa..b5c7ea6493d 100644 --- a/arch/sandbox/cpu/mem.c +++ b/arch/sandbox/cpu/mem.c @@ -13,6 +13,7 @@ #include <os.h> #include <asm/global_data.h> #include <asm/io.h> +#include <asm/sandbox_pci.h> #include <asm/state.h> #include <linux/list.h> diff --git a/arch/sandbox/include/asm/sandbox_pci.h b/arch/sandbox/include/asm/sandbox_pci.h new file mode 100644 index 00000000000..a4a4eaece8f --- /dev/null +++ b/arch/sandbox/include/asm/sandbox_pci.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2011 The Chromium OS Authors. + */ + +#ifndef _ASM_SANDBOX_PCI_H_ +#define _ASM_SANDBOX_PCI_H_ + +#include <asm/types.h> + +struct udevice; + +/** + * pci_map_physmem() - map a PCI device into memory + * + * This is used on sandbox to map a device into memory so that it can be + * used with normal memory access. After this call, some part of the device's + * internal structure becomes visible. + * + * This function is normally called from sandbox's map_sysmem() automatically. + * + * @paddr: Physical memory address, normally corresponding to a PCI BAR + * @lenp: On entry, the size of the area to map, On exit it is updated + * to the size actually mapped, which may be less if the device + * has less space + * @devp: Returns the device which mapped into this space + * @ptrp: Returns a pointer to the mapped address. The device's space + * can be accessed as @lenp bytes starting here + * Return: 0 if OK, -ve on error + */ +int pci_map_physmem(phys_addr_t paddr, unsigned long *lenp, + struct udevice **devp, void **ptrp); + +/** + * pci_unmap_physmem() - undo a memory mapping + * + * This must be called after pci_map_physmem() to undo the mapping. + * + * @paddr: Physical memory address, as passed to pci_map_physmem() + * @len: Size of area mapped, as returned by pci_map_physmem() + * @dev: Device to unmap, as returned by pci_map_physmem() + * Return: 0 if OK, -ve on error + */ +int pci_unmap_physmem(const void *addr, unsigned long len, + struct udevice *dev); + +/** + * sandbox_set_enable_pci_map() - Enable / disable PCI address mapping + * + * Since address mapping involves calling every driver, provide a way to + * enable and disable this. It can be handled automatically by the emulator + * uclass, which knows if any emulators are currently active. + * + * If this is disabled, pci_map_physmem() will not be called from + * map_sysmem(). + * + * @enable: 0 to disable, 1 to enable + */ +void sandbox_set_enable_pci_map(int enable); + +#endif /* _ASM_SANDBOX_PCI_H_ */ diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h index 23eaa3a45e6..3c4347117d4 100644 --- a/arch/sandbox/include/asm/u-boot-sandbox.h +++ b/arch/sandbox/include/asm/u-boot-sandbox.h @@ -14,6 +14,8 @@ #ifndef _U_BOOT_SANDBOX_H_ #define _U_BOOT_SANDBOX_H_ +#include <linux/compiler_attributes.h> + /* board/.../... */ int board_init(void); @@ -26,54 +28,6 @@ int sandbox_lcd_sdl_early_init(void); struct udevice; -/** - * pci_map_physmem() - map a PCI device into memory - * - * This is used on sandbox to map a device into memory so that it can be - * used with normal memory access. After this call, some part of the device's - * internal structure becomes visible. - * - * This function is normally called from sandbox's map_sysmem() automatically. - * - * @paddr: Physical memory address, normally corresponding to a PCI BAR - * @lenp: On entry, the size of the area to map, On exit it is updated - * to the size actually mapped, which may be less if the device - * has less space - * @devp: Returns the device which mapped into this space - * @ptrp: Returns a pointer to the mapped address. The device's space - * can be accessed as @lenp bytes starting here - * Return: 0 if OK, -ve on error - */ -int pci_map_physmem(phys_addr_t paddr, unsigned long *lenp, - struct udevice **devp, void **ptrp); - -/** - * pci_unmap_physmem() - undo a memory mapping - * - * This must be called after pci_map_physmem() to undo the mapping. - * - * @paddr: Physical memory address, as passed to pci_map_physmem() - * @len: Size of area mapped, as returned by pci_map_physmem() - * @dev: Device to unmap, as returned by pci_map_physmem() - * Return: 0 if OK, -ve on error - */ -int pci_unmap_physmem(const void *addr, unsigned long len, - struct udevice *dev); - -/** - * sandbox_set_enable_pci_map() - Enable / disable PCI address mapping - * - * Since address mapping involves calling every driver, provide a way to - * enable and disable this. It can be handled automatically by the emulator - * uclass, which knows if any emulators are currently active. - * - * If this is disabled, pci_map_physmem() will not be called from - * map_sysmem(). - * - * @enable: 0 to disable, 1 to enable - */ -void sandbox_set_enable_pci_map(int enable); - /** * sandbox_reset() - reset sandbox * diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index 166ee9fcd43..b0b229595ae 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -7,9 +7,10 @@ #include <dm.h> #include <fdtdec.h> #include <log.h> -#include <linux/libfdt.h> #include <pci.h> +#include <asm/sandbox_pci.h> #include <dm/lists.h> +#include <linux/libfdt.h> struct sandbox_pci_emul_priv { int dev_count; diff --git a/test/dm/pci.c b/test/dm/pci.c index bcd274d1879..4f7ee8ab845 100644 --- a/test/dm/pci.c +++ b/test/dm/pci.c @@ -5,6 +5,7 @@ #include <dm.h> #include <asm/io.h> +#include <asm/sandbox_pci.h> #include <asm/test.h> #include <dm/test.h> #include <test/test.h> -- 2.43.0

From: Simon Glass <sjg@chromium.org> It isn't really necessary to have a header file for just one function. This makes it harder to see the full interface provided by sandbox. Move the sandbox_main() declaration into u-boot-sandbox.h Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/sandbox/cpu/os.c | 2 +- arch/sandbox/include/asm/main.h | 18 ------------------ arch/sandbox/include/asm/u-boot-sandbox.h | 12 ++++++++++++ 3 files changed, 13 insertions(+), 19 deletions(-) delete mode 100644 arch/sandbox/include/asm/main.h diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 101d695a556..d1632e6af69 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -30,9 +30,9 @@ #include <asm/fuzzing_engine.h> #include <asm/getopt.h> -#include <asm/main.h> #include <asm/sections.h> #include <asm/state.h> +#include <asm/u-boot-sandbox.h> #include <os.h> #include <rtc_def.h> diff --git a/arch/sandbox/include/asm/main.h b/arch/sandbox/include/asm/main.h deleted file mode 100644 index 7a2f0d3a8d5..00000000000 --- a/arch/sandbox/include/asm/main.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2022 Google, Inc. - * Written by Andrew Scull <ascull@google.com> - */ - -#ifndef __ASM_SANDBOX_MAIN_H -#define __ASM_SANDBOX_MAIN_H - -/** - * sandbox_main() - main entrypoint for sandbox - * - * @argc: the number of arguments passed to the program - * @argv: array of argc+1 pointers, of which the last one is null - */ -int sandbox_main(int argc, char *argv[]); - -#endif /* __ASM_SANDBOX_MAIN_H */ diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h index 3c4347117d4..54f0d9832b1 100644 --- a/arch/sandbox/include/asm/u-boot-sandbox.h +++ b/arch/sandbox/include/asm/u-boot-sandbox.h @@ -41,4 +41,16 @@ void sandbox_reset(void); /* Exit sandbox (quit U-Boot) */ void __noreturn sandbox_exit(void); +/** + * sandbox_main() - main entrypoint for sandbox + * + * @argc: the number of arguments passed to the program + * @argv: array of argc+1 pointers, of which the last one is null + + * This starts sandbox. It does not return unless something goes wrong. + * + * Return: 1 on error + */ +int sandbox_main(int argc, char *argv[]); + #endif /* _U_BOOT_SANDBOX_H_ */ -- 2.43.0

From: Simon Glass <sjg@chromium.org> Normally sandbox includes a main() function so that it can be started correctly. When fuzzing is enabled, main() is not required. When sandbox is built as a library, the main program will be somewhere else so must not be in the library. Split the main() function out into a new main.c file. Split the fuzzing code into a new fuzz.c file. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/sandbox/cpu/Makefile | 7 +- arch/sandbox/cpu/fuzz.c | 81 +++++++++++++++++++++++ arch/sandbox/cpu/main.c | 11 +++ arch/sandbox/cpu/os.c | 74 --------------------- arch/sandbox/cpu/start.c | 1 + arch/sandbox/include/asm/u-boot-sandbox.h | 5 +- 6 files changed, 102 insertions(+), 77 deletions(-) create mode 100644 arch/sandbox/cpu/fuzz.c create mode 100644 arch/sandbox/cpu/main.c diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile index 03cdf2ae0f1..35f853776f7 100644 --- a/arch/sandbox/cpu/Makefile +++ b/arch/sandbox/cpu/Makefile @@ -6,13 +6,18 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. obj-y := cache.o cpu.o mem.o state.o os.o +ifdef CONFIG_FUZZ +obj-y += fuzz.o +else +obj-y += main.o +endif extra-y := start.o extra-$(CONFIG_SANDBOX_SDL) += sdl.o obj-$(CONFIG_XPL_BUILD) += spl.o obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o # Compile these files with system headers -CFLAGS_USE_SYSHDRS := eth-raw-os.o os.o sdl.o +CFLAGS_USE_SYSHDRS := eth-raw-os.o fuzz.o main.o os.o sdl.o # sdl.c fails to build with -fshort-wchar using musl cmd_cc_sdl.o = $(CC) $(filter-out -nostdinc -fshort-wchar, \ diff --git a/arch/sandbox/cpu/fuzz.c b/arch/sandbox/cpu/fuzz.c new file mode 100644 index 00000000000..f017c3a33ad --- /dev/null +++ b/arch/sandbox/cpu/fuzz.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2022 Google, Inc. + * Written by Andrew Scull <ascull@google.com> + */ + +#include <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> + +#include <os.h> +#include <asm/fuzzing_engine.h> +#include <asm/u-boot-sandbox.h> + +static void *fuzzer_thread(void *ptr) +{ + char cmd[64]; + char *argv[5] = {"./u-boot", "-T", "-c", cmd, NULL}; + const char *fuzz_test; + + /* Find which test to run from an environment variable. */ + fuzz_test = getenv("UBOOT_SB_FUZZ_TEST"); + if (!fuzz_test) + os_abort(); + + snprintf(cmd, sizeof(cmd), "fuzz %s", fuzz_test); + + sandbox_main(4, argv); + os_abort(); + return NULL; +} + +static bool fuzzer_initialized; +static pthread_mutex_t fuzzer_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t fuzzer_cond = PTHREAD_COND_INITIALIZER; +static const uint8_t *fuzzer_data; +static size_t fuzzer_size; + +int sandbox_fuzzing_engine_get_input(const uint8_t **data, size_t *size) +{ + if (!fuzzer_initialized) + return -ENOSYS; + + /* Tell the main thread we need new inputs then wait for them. */ + pthread_mutex_lock(&fuzzer_mutex); + pthread_cond_signal(&fuzzer_cond); + pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex); + *data = fuzzer_data; + *size = fuzzer_size; + pthread_mutex_unlock(&fuzzer_mutex); + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + static pthread_t tid; + + pthread_mutex_lock(&fuzzer_mutex); + + /* Initialize the sandbox on another thread. */ + if (!fuzzer_initialized) { + fuzzer_initialized = true; + if (pthread_create(&tid, NULL, fuzzer_thread, NULL)) + os_abort(); + pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex); + } + + /* Hand over the input. */ + fuzzer_data = data; + fuzzer_size = size; + pthread_cond_signal(&fuzzer_cond); + + /* Wait for the inputs to be finished with. */ + pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex); + pthread_mutex_unlock(&fuzzer_mutex); + + return 0; +} diff --git a/arch/sandbox/cpu/main.c b/arch/sandbox/cpu/main.c new file mode 100644 index 00000000000..617295d142c --- /dev/null +++ b/arch/sandbox/cpu/main.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2011 The Chromium OS Authors. + */ + +#include <asm/u-boot-sandbox.h> + +int main(int argc, char *argv[]) +{ + return sandbox_main(argc, argv); +} diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index d1632e6af69..1c4e23cb4eb 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -10,7 +10,6 @@ #include <fcntl.h> #include <pthread.h> #include <getopt.h> -#include <setjmp.h> #include <signal.h> #include <stdarg.h> #include <stdio.h> @@ -28,7 +27,6 @@ #include <linux/compiler_attributes.h> #include <linux/types.h> -#include <asm/fuzzing_engine.h> #include <asm/getopt.h> #include <asm/sections.h> #include <asm/state.h> @@ -1151,75 +1149,3 @@ void os_relaunch(char *argv[]) execv(argv[0], argv); os_exit(1); } - -#ifdef CONFIG_FUZZ -static void *fuzzer_thread(void * ptr) -{ - char cmd[64]; - char *argv[5] = {"./u-boot", "-T", "-c", cmd, NULL}; - const char *fuzz_test; - - /* Find which test to run from an environment variable. */ - fuzz_test = getenv("UBOOT_SB_FUZZ_TEST"); - if (!fuzz_test) - os_abort(); - - snprintf(cmd, sizeof(cmd), "fuzz %s", fuzz_test); - - sandbox_main(4, argv); - os_abort(); - return NULL; -} - -static bool fuzzer_initialized = false; -static pthread_mutex_t fuzzer_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t fuzzer_cond = PTHREAD_COND_INITIALIZER; -static const uint8_t *fuzzer_data; -static size_t fuzzer_size; - -int sandbox_fuzzing_engine_get_input(const uint8_t **data, size_t *size) -{ - if (!fuzzer_initialized) - return -ENOSYS; - - /* Tell the main thread we need new inputs then wait for them. */ - pthread_mutex_lock(&fuzzer_mutex); - pthread_cond_signal(&fuzzer_cond); - pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex); - *data = fuzzer_data; - *size = fuzzer_size; - pthread_mutex_unlock(&fuzzer_mutex); - return 0; -} - -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) -{ - static pthread_t tid; - - pthread_mutex_lock(&fuzzer_mutex); - - /* Initialize the sandbox on another thread. */ - if (!fuzzer_initialized) { - fuzzer_initialized = true; - if (pthread_create(&tid, NULL, fuzzer_thread, NULL)) - os_abort(); - pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex); - } - - /* Hand over the input. */ - fuzzer_data = data; - fuzzer_size = size; - pthread_cond_signal(&fuzzer_cond); - - /* Wait for the inputs to be finished with. */ - pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex); - pthread_mutex_unlock(&fuzzer_mutex); - - return 0; -} -#else -int main(int argc, char *argv[]) -{ - return sandbox_main(argc, argv); -} -#endif diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 8ee12ed1500..40a3559d244 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -22,6 +22,7 @@ #include <asm/malloc.h> #include <asm/sections.h> #include <asm/state.h> +#include <asm/u-boot-sandbox.h> #include <dm/root.h> #include <linux/ctype.h> #include <linux/log2.h> diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h index 54f0d9832b1..001b00fe41e 100644 --- a/arch/sandbox/include/asm/u-boot-sandbox.h +++ b/arch/sandbox/include/asm/u-boot-sandbox.h @@ -46,8 +46,9 @@ void __noreturn sandbox_exit(void); * * @argc: the number of arguments passed to the program * @argv: array of argc+1 pointers, of which the last one is null - - * This starts sandbox. It does not return unless something goes wrong. + * + * This calls sandbox_init(), then board_init_f/r(). It does not return unless + * something goes wrong. * * Return: 1 on error */ -- 2.43.0

From: Simon Glass <sjg@chromium.org> Split the init code from sandbox_main() into a separate sandbox_init() function that handles all setup up to the call to board_init_f(). This allows the init to be called independently of the main execution flow. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/sandbox/cpu/start.c | 25 ++++++++++++++++------- arch/sandbox/include/asm/u-boot-sandbox.h | 21 +++++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 40a3559d244..59682b039e5 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -601,18 +601,16 @@ static int last_stage_init(void) } EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, last_stage_init); -int sandbox_main(int argc, char *argv[]) +int sandbox_init(int argc, char *argv[], struct global_data *data) { struct sandbox_state *state; void * text_base; - gd_t data; int size; int ret; text_base = os_find_text_base(); - memset(&data, '\0', sizeof(data)); - gd = &data; + gd = data; /* * This must be the first invocation of os_malloc() to have @@ -620,7 +618,7 @@ int sandbox_main(int argc, char *argv[]) */ ret = state_init(); if (ret) - goto err; + return ret; /* * Copy argv[] so that we can pass the arguments in the original @@ -663,13 +661,13 @@ int sandbox_main(int argc, char *argv[]) if (state->read_state && state->state_fname) { ret = sandbox_read_state(state, state->state_fname); if (ret) - goto err; + return ret; } if (state->handle_signals) { ret = os_setup_signal_handlers(); if (ret) - goto err; + return ret; } if (state->upl) @@ -692,6 +690,19 @@ int sandbox_main(int argc, char *argv[]) /* sandbox test: log functions called before log_init in board_init_f */ log_debug("debug: %s\n", __func__); + return 0; +} + +int sandbox_main(int argc, char *argv[]) +{ + gd_t data; + int ret; + + memset(&data, '\0', sizeof(data)); + ret = sandbox_init(argc, argv, &data); + if (ret) + goto err; + /* Do pre- and post-relocation init */ board_init_f(gd->flags); diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h index 001b00fe41e..941f35f9e69 100644 --- a/arch/sandbox/include/asm/u-boot-sandbox.h +++ b/arch/sandbox/include/asm/u-boot-sandbox.h @@ -16,6 +16,8 @@ #include <linux/compiler_attributes.h> +struct global_data; + /* board/.../... */ int board_init(void); @@ -41,6 +43,22 @@ void sandbox_reset(void); /* Exit sandbox (quit U-Boot) */ void __noreturn sandbox_exit(void); +/** + * sandbox_init() - init sandbox + * + * This function initialises sandbox state, parses arguments, and sets up the + * global data structure, but does not call board_init_f(). + * + * The caller must zero @data before calling this function. This function sets + * gd to point to @data so it must remain valid for the life of sandbox. + * + * @argc: the number of arguments passed to the program + * @argv: array of argc pointers, plus a NULL terminator + * @data: pointer to global data structure to init + * Return: 0 if OK, -ve on error + */ +int sandbox_init(int argc, char *argv[], struct global_data *data); + /** * sandbox_main() - main entrypoint for sandbox * @@ -50,6 +68,9 @@ void __noreturn sandbox_exit(void); * This calls sandbox_init(), then board_init_f/r(). It does not return unless * something goes wrong. * + * @argc: the number of arguments passed to the program + * @argv: array of argc pointers, plus a NULL terminator + * * Return: 1 on error */ int sandbox_main(int argc, char *argv[]); -- 2.43.0

From: Simon Glass <sjg@chromium.org> It is sometimes useful to create a different main program for U-Boot, or even to use some parts of U-Boot in an entirely different project. Add a new option to allow building a .so from parts of U-Boot. For now this does nothing. Enable it by default for sandbox, excluding the tools-only build, where it has no meaning. Signed-off-by: Simon Glass <sjg@chromium.org> --- Kconfig | 9 +++++++++ configs/tools-only_defconfig | 1 + 2 files changed, 10 insertions(+) diff --git a/Kconfig b/Kconfig index de9d9ad5653..3b136a5f897 100644 --- a/Kconfig +++ b/Kconfig @@ -98,6 +98,15 @@ config CC_OPTIMIZE_FOR_DEBUG endchoice +config ULIB + bool "Build U-Boot as a library" + default y if SANDBOX + help + Enable this to build a library which can be linked to other programs, + to extend U-Boot's functionality. + + The library is called libu-boot.so + config OPTIMIZE_INLINING bool "Allow compiler to uninline functions marked 'inline' in full U-Boot" help diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig index 20ac1e63f09..9e4866b494c 100644 --- a/configs/tools-only_defconfig +++ b/configs/tools-only_defconfig @@ -5,6 +5,7 @@ CONFIG_DEFAULT_DEVICE_TREE="sandbox" CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y # CONFIG_SANDBOX_SDL is not set +# CONFIG_ULIB is not set # CONFIG_EFI_LOADER is not set CONFIG_ANDROID_BOOT_IMAGE=y CONFIG_TIMESTAMP=y -- 2.43.0

From: Simon Glass <sjg@chromium.org> Provide a rule which creates a libu-boot.so file which can be used to provide some of U-Boot's functionality to another program. Move the RISCV up a line so it is clear that it relates to the u-boot target. For now this is not very useful, as everything is bound together, and U-Boot will just start normally when the library is used (including waiting for the user to type commands!). Further work will improve this over time. Signed-off-by: Simon Glass <sjg@chromium.org> --- Makefile | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fb4358b1753..c4f3065d2e6 100644 --- a/Makefile +++ b/Makefile @@ -1043,6 +1043,8 @@ INPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \ $(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \ $(if $(CONFIG_TPL_X86_16BIT_INIT),tpl/u-boot-tpl.bin) +INPUTS-$(CONFIG_ULIB) += libu-boot.so + LDFLAGS_u-boot += $(LDFLAGS_FINAL) # Avoid 'Not enough room for program headers' error on binutils 2.28 onwards. @@ -1843,11 +1845,24 @@ ifeq ($(CONFIG_KALLSYMS),y) $(call cmd,u-boot__) common/system_map.o endif $(call cmd,llcheck,u-boot) - ifeq ($(CONFIG_RISCV),y) @tools/prelink-riscv $@ endif +# Build U-Boot as a shared library +quiet_cmd_libu-boot.so = LD $@ + cmd_libu-boot.so = $(CC) -shared -o $@ -Wl,--build-id=none \ + $(u-boot-init) \ + $(KBUILD_LDFLAGS:%=-Wl,%) $(SANITIZERS) $(LTO_FINAL_LDFLAGS) \ + -Wl,--whole-archive \ + $(filter-out %/main.o,$(u-boot-main)) \ + $(u-boot-keep-syms-lto) \ + -Wl,--no-whole-archive \ + $(PLATFORM_LIBS) -Wl,-Map -Wl,libu-boot.map + +libu-boot.so: $(u-boot-init) $(u-boot-main) $(u-boot-keep-syms-lto) FORCE + $(call if_changed,libu-boot.so) + quiet_cmd_sym ?= SYM $@ cmd_sym ?= $(OBJDUMP) -t $< > $@ u-boot.sym: u-boot FORCE -- 2.43.0

From: Simon Glass <sjg@chromium.org> Provide a host program which can use the shared library. For now this operates similarly to sandbox itself, but future work will make it more flexible. Leave it out of the build, since there are a few other pieces needed. Signed-off-by: Simon Glass <sjg@chromium.org> --- Makefile | 9 +++++++++ test/ulib/Makefile | 12 ++++++++++++ test/ulib/ulib_test.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 test/ulib/Makefile create mode 100644 test/ulib/ulib_test.c diff --git a/Makefile b/Makefile index c4f3065d2e6..a0a9ce3196b 100644 --- a/Makefile +++ b/Makefile @@ -1863,6 +1863,15 @@ quiet_cmd_libu-boot.so = LD $@ libu-boot.so: $(u-boot-init) $(u-boot-main) $(u-boot-keep-syms-lto) FORCE $(call if_changed,libu-boot.so) +# Build ulib_test that links with shared library +quiet_cmd_ulib_test = HOSTCC $@ + cmd_ulib_test = $(HOSTCC) $(HOSTCFLAGS) \ + -I$(srctree)/arch/sandbox/include -o $@ $< -L$(obj) -lu-boot \ + -Wl,-rpath,$(obj) + +test/ulib/ulib_test: test/ulib/ulib_test.o libu-boot.so FORCE + $(call if_changed,ulib_test) + quiet_cmd_sym ?= SYM $@ cmd_sym ?= $(OBJDUMP) -t $< > $@ u-boot.sym: u-boot FORCE diff --git a/test/ulib/Makefile b/test/ulib/Makefile new file mode 100644 index 00000000000..ae58e01fccd --- /dev/null +++ b/test/ulib/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2025 Simon Glass <sjg@chromium.org> + +obj-y += ulib_test.o + +# Link with the shared library +HOSTCFLAGS_ulib_test.o += -I$(srctree)/arch/sandbox/include +HOSTLDLIBS_ulib_test += -L$(obj)/../.. -lu-boot -Wl,-rpath,$(obj)/../.. + +# Ensure shared library is built first +$(obj)/ulib_test: $(obj)/../../libu-boot.so diff --git a/test/ulib/ulib_test.c b/test/ulib/ulib_test.c new file mode 100644 index 00000000000..dd9cc0bb978 --- /dev/null +++ b/test/ulib/ulib_test.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test application for U-Boot shared library + * + * This demonstrates linking against libu-boot.so + * + * Copyright 2025 Canonical + * Written by Simon Glass <simon.glass@canonical.com> + */ + +/* Use system headers, not U-Boot headers */ +#include <stdio.h> +#include <string.h> +#include <init.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +int main(int argc, char *argv[]) +{ + struct global_data data; + int ret; + + printf("Calling U-Boot initialization via shared library...\n"); + + /* init global data */ + memset(&data, '\0', sizeof(data)); + + ret = sandbox_init(argc, argv, &data); + + /* Do pre- and post-relocation init */ + board_init_f(gd->flags); + board_init_r(data.new_gd, 0); + + return ret; +} -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a proper linker script (u-boot-lib.lds) for building libu-boot.so to ensure correct section alignment and placement, particularly for the linker lists. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/sandbox/cpu/u-boot-lib.lds | 88 +++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 arch/sandbox/cpu/u-boot-lib.lds diff --git a/arch/sandbox/cpu/u-boot-lib.lds b/arch/sandbox/cpu/u-boot-lib.lds new file mode 100644 index 00000000000..f57292b0a8d --- /dev/null +++ b/arch/sandbox/cpu/u-boot-lib.lds @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2025 Canonical + * Written by Simon Glass <simon.glass@canonical.com> + * + * Linker script for U-Boot shared library (libu-boot.so) + */ + +SECTIONS +{ + /* Text sections first */ + .text : { + *(.text*) + } + + . = ALIGN(32); + __u_boot_list : { + KEEP(*(SORT(__u_boot_list*))); + } + + _u_boot_sandbox_getopt : { + *(_u_boot_sandbox_getopt_start) + KEEP(*(_u_boot_sandbox_getopt)) + *(_u_boot_sandbox_getopt_end) + } + + efi_runtime : { + __efi_runtime_start = .; + *(efi_runtime_text) + *(efi_runtime_data) + __efi_runtime_stop = .; + } + + efi_runtime_rel : { + __efi_runtime_rel_start = .; + *(.relefi_runtime_text) + *(.relefi_runtime_data) + __efi_runtime_rel_stop = .; + } + + /* Read-only data */ + . = ALIGN(8); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + /* Data sections */ + . = ALIGN(8); + .data : { + *(.data*) + } + + /* BSS section */ + . = ALIGN(8); + .bss : { + __bss_start = .; + *(.bss*) + *(COMMON) + . = ALIGN(8); + __bss_end = .; + } + + /* Dynamic linking sections for shared library */ + .dynamic : { *(.dynamic) } + .dynsym : { + __dyn_sym_start = .; + *(.dynsym) + __dyn_sym_end = .; + } + .dynstr : { *(.dynstr) } + .gnu.hash : { *(.gnu.hash) } + .hash : { *(.hash) } + .got : { *(.got) } + .got.plt : { *(.got.plt) } + .plt : { *(.plt) } + .rela.dyn : { *(.rela.dyn) } + .rela.plt : { *(.rela.plt) } + + /* Debugging sections */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_ranges 0 : { *(.debug_ranges) } + .debug_line 0 : { *(.debug_line) } + .debug_str 0 : { *(.debug_str) } + .debug_frame 0 : { *(.debug_frame) } + .debug_loc 0 : { *(.debug_loc) } + + /DISCARD/ : { *(.note*) } +} -- 2.43.0

From: Simon Glass <sjg@chromium.org> This cannot work with the shared library at present, since the symbols are not defined. Disable it for now. Signed-off-by: Simon Glass <sjg@chromium.org> --- lib/efi_loader/efi_runtime.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 58c3ea1870f..2bd2582ede5 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -717,6 +717,10 @@ static __efi_runtime void efi_relocate_runtime_table(ulong offset) /* Relocate EFI runtime to uboot_reloc_base = offset */ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) { + /* Skip EFI runtime relocation when building as a library */ + if (IS_ENABLED(CONFIG_ULIB)) + return; + #ifdef IS_RELA struct elf_rela *rel = (void *)__efi_runtime_rel_start; #else -- 2.43.0

From: Simon Glass <sjg@chromium.org> Now that the required pieces are in place, add the test program into the build. Provide the linker script too. The library requires CONFIG_CMDLINE, at least initially, so don't attempt to build it when there is no command line. For clang, an error is produced, so disable it in that case too: test/ulib/ulib_test.o: file not recognized: file format not recognized For now the program just crashes on startup, due to mon_len being larger than available RAM. Signed-off-by: Simon Glass <sjg@chromium.org> --- Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a0a9ce3196b..b43e028a06e 100644 --- a/Makefile +++ b/Makefile @@ -1043,7 +1043,11 @@ INPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \ $(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \ $(if $(CONFIG_TPL_X86_16BIT_INIT),tpl/u-boot-tpl.bin) -INPUTS-$(CONFIG_ULIB) += libu-boot.so +ifdef CONFIG_CMDLINE +ifneq ($(cc-name),clang) +INPUTS-$(CONFIG_ULIB) += libu-boot.so test/ulib/ulib_test +endif +endif LDFLAGS_u-boot += $(LDFLAGS_FINAL) @@ -1852,6 +1856,7 @@ endif # Build U-Boot as a shared library quiet_cmd_libu-boot.so = LD $@ cmd_libu-boot.so = $(CC) -shared -o $@ -Wl,--build-id=none \ + -Wl,-T,$(srctree)/arch/sandbox/cpu/u-boot-lib.lds \ $(u-boot-init) \ $(KBUILD_LDFLAGS:%=-Wl,%) $(SANITIZERS) $(LTO_FINAL_LDFLAGS) \ -Wl,--whole-archive \ -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a new global_data flag GD_FLG_ULIB to indicate that U-Boot is being used as a shared library. This allows suppressing console output that is inappropriate for library usage while preserving normal boot messages for standalone operation. For now the flag must be enabled by the caller and it has no effect. Signed-off-by: Simon Glass <sjg@chromium.org> --- include/asm-generic/global_data.h | 12 ++++++++++++ test/ulib/ulib_test.c | 1 + 2 files changed, 13 insertions(+) diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index fc99411e5fb..8b59df66ec5 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -758,8 +758,20 @@ enum gd_flags { * drivers shall not be called. */ GD_FLG_HAVE_CONSOLE = 0x8000000, + /** + * @GD_FLG_ULIB: U-Boot is running as a library + * + * For now, this just avoids console output on startup + */ + GD_FLG_ULIB = 0x10000000, }; +#if CONFIG_IS_ENABLED(ULIB) +#define gd_ulib() (gd->flags & GD_FLG_ULIB) +#else +#define gd_ulib() 0 +#endif + #endif /* __ASSEMBLY__ */ #endif /* __ASM_GENERIC_GBL_DATA_H */ diff --git a/test/ulib/ulib_test.c b/test/ulib/ulib_test.c index dd9cc0bb978..621bcd49be9 100644 --- a/test/ulib/ulib_test.c +++ b/test/ulib/ulib_test.c @@ -25,6 +25,7 @@ int main(int argc, char *argv[]) /* init global data */ memset(&data, '\0', sizeof(data)); + data.flags = GD_FLG_ULIB; ret = sandbox_init(argc, argv, &data); -- 2.43.0

From: Simon Glass <sjg@chromium.org> When using the library it should start up silently. Drop the initial banner. Signed-off-by: Simon Glass <sjg@chromium.org> --- lib/display_options.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/display_options.c b/lib/display_options.c index 9c6722f0c64..7f9dfcc43ee 100644 --- a/lib/display_options.c +++ b/lib/display_options.c @@ -9,11 +9,14 @@ #include <display_options.h> #include <div64.h> #include <version_string.h> -#include <linux/ctype.h> -#include <linux/kernel.h> -#include <asm/io.h> #include <stdio.h> #include <vsprintf.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <linux/ctype.h> +#include <linux/kernel.h> + +DECLARE_GLOBAL_DATA_PTR; char *display_options_get_banner_priv(bool newlines, const char *build_tag, char *buf, int size) @@ -47,8 +50,10 @@ int display_options(void) { char buf[DISPLAY_OPTIONS_BANNER_LENGTH]; - display_options_get_banner(true, buf, sizeof(buf)); - printf("%s", buf); + if (!gd_ulib()) { + display_options_get_banner(true, buf, sizeof(buf)); + printf("%s", buf); + } return 0; } -- 2.43.0

From: Simon Glass <sjg@chromium.org> We don't want any initial console output from the library, so check the ULIB flag and skip any output related to DRAM. Note that debug output is unaffected, but this is only visible if debug is enabled. Signed-off-by: Simon Glass <sjg@chromium.org> --- common/board_f.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/common/board_f.c b/common/board_f.c index eac51d61fa1..ef8b0ff7ef1 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -181,7 +181,9 @@ static int print_cpuinfo(void) static int announce_dram_init(void) { - puts("DRAM: "); + if (!gd_ulib()) + puts("DRAM: "); + return 0; } @@ -231,13 +233,15 @@ static int show_dram_config(void) } debug("\nDRAM: "); - print_size(gd->ram_size, ""); - if (!sizes_near(gd->ram_size, size)) { - printf(" (total "); - print_size(size, ")"); + if (!gd_ulib()) { + print_size(gd->ram_size, ""); + if (!sizes_near(gd->ram_size, size)) { + printf(" (total "); + print_size(size, ")"); + } + board_add_ram_info(0); + putc('\n'); } - board_add_ram_info(0); - putc('\n'); return 0; } -- 2.43.0

From: Simon Glass <sjg@chromium.org> This should be handled by driver model now. Some tests rely on this happening early, so just disable it for the shared library. Signed-off-by: Simon Glass <sjg@chromium.org> --- common/board_r.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/board_r.c b/common/board_r.c index d60cc7aac70..297fdc29ca9 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -364,6 +364,9 @@ static int initr_flash(void) /* go init the NAND */ static int initr_nand(void) { + if (gd_ulib()) + return 0; + puts("NAND: "); nand_init(); printf("%lu MiB\n", nand_size() / 1024); -- 2.43.0

From: Simon Glass <sjg@chromium.org> When using the library it should start up silently. Drop the driver model message about the number of devices, etc. Signed-off-by: Simon Glass <sjg@chromium.org> --- common/board_r.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/board_r.c b/common/board_r.c index 297fdc29ca9..ca1498de11e 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -504,7 +504,7 @@ static int dm_announce(void) int device_count; int uclass_count; - if (IS_ENABLED(CONFIG_DM)) { + if (IS_ENABLED(CONFIG_DM) && !gd_ulib()) { dm_get_stats(&device_count, &uclass_count); printf("Core: %d devices, %d uclasses", device_count, uclass_count); -- 2.43.0
participants (1)
-
Simon Glass