From 299d24eddfeb18a7576187b3010d5462317335e9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:24:55 -0700 Subject: [PATCH 01/29] x86: Make do_zboot_states() static This function is only called within zboot.c so make the function private. Signed-off-by: Simon Glass --- cmd/x86/zboot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c index 94e602b8a5b..3035172352a 100644 --- a/cmd/x86/zboot.c +++ b/cmd/x86/zboot.c @@ -119,8 +119,8 @@ U_BOOT_SUBCMDS(zboot, U_BOOT_CMD_MKENT(dump, 2, 1, do_zboot_dump, "", ""), ) -int do_zboot_states(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[], int state_mask) +static int do_zboot_states(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[], int state_mask) { int ret = 0; From 95641f4bf98d3c90bfc4ae94515c98c440ffb2e1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:24:56 -0700 Subject: [PATCH 02/29] x86: Rename zboot_run() to zboot_run_args() Rename this function so we can (later) create a zboot_run() function which looks the same as bootm_run() Signed-off-by: Simon Glass --- arch/x86/lib/zimage.c | 4 ++-- boot/bootmeth_cros.c | 6 +++--- include/bootm.h | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 2eece34a073..8d791416066 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -435,8 +435,8 @@ int zboot_go(void) return ret; } -int zboot_run(ulong addr, ulong size, ulong initrd, ulong initrd_size, - ulong base, char *cmdline) +int zboot_run_args(ulong addr, ulong size, ulong initrd, ulong initrd_size, + ulong base, char *cmdline) { int ret; diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index c7b862e512a..ea4c9ed830f 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -446,9 +446,9 @@ static int cros_boot(struct udevice *dev, struct bootflow *bflow) } if (IS_ENABLED(CONFIG_X86)) { - ret = zboot_run(map_to_sysmem(bflow->buf), bflow->size, 0, 0, - map_to_sysmem(bflow->x86_setup), - bflow->cmdline); + ret = zboot_run_args(map_to_sysmem(bflow->buf), bflow->size, 0, + 0, map_to_sysmem(bflow->x86_setup), + bflow->cmdline); } else { ret = bootm_boot_start(map_to_sysmem(bflow->buf), bflow->cmdline); diff --git a/include/bootm.h b/include/bootm.h index 61160705215..154fb98cfcd 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -273,7 +273,7 @@ int bootm_process_cmdline(char *buf, int maxlen, int flags); int bootm_process_cmdline_env(int flags); /** - * zboot_run() - Run through the various steps to boot a zimage + * zboot_run_args() - Run through the various steps to boot a zimage * * Boot a zimage, given the component parts * @@ -289,8 +289,8 @@ int bootm_process_cmdline_env(int flags); * to use for booting * Return: -EFAULT on error (normally it does not return) */ -int zboot_run(ulong addr, ulong size, ulong initrd, ulong initrd_size, - ulong base, char *cmdline); +int zboot_run_args(ulong addr, ulong size, ulong initrd, ulong initrd_size, + ulong base, char *cmdline); /* * zimage_get_kernel_version() - Get the version string from a kernel From 2de073527bb92b47d49366249cd3fdea5016bcaf Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:24:57 -0700 Subject: [PATCH 03/29] x86: Drop duplicate definition of zimage_dump() This is now defined in bootm.h so drop the duplicate in the x86 code. Signed-off-by: Simon Glass --- arch/x86/include/asm/zimage.h | 8 -------- cmd/x86/zboot.c | 1 + 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 8b542605170..76b2a797ccf 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -71,14 +71,6 @@ struct zboot_state { extern struct zboot_state state; -/** - * zimage_dump() - Dump information about a zimage - * - * @base_ptr: Pointer to the boot parameters - * @show_cmdline: true to show the kernel command line - */ -void zimage_dump(struct boot_params *base_ptr, bool show_cmdline); - /** * zboot_load() - Load a zimage * diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c index 3035172352a..40f67a75593 100644 --- a/cmd/x86/zboot.c +++ b/cmd/x86/zboot.c @@ -7,6 +7,7 @@ #define LOG_CATEGORY LOGC_BOOT +#include #include #include #include From 75e85df7963f57e4bb80b3d805ba2295b1843911 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:24:58 -0700 Subject: [PATCH 04/29] x86: Move x86 zboot state into struct bootm_info This structure is supposed to handle any type of booting programmatically, i.e. without needing a command to be executed. Move the x86-specific members into it and use it instead of struct zboot_state. Provide a macro so access is possible without adding lots of #ifdefs to the code. This will allow the struct to be used for all four types of booting (bootm, bootz, booti and zboot). Call bootm_init() to init the state, to match other boot methods. Note that some rationalisation could be performed on this. But this is tricky since addresses are stored as strings in several places. Also some strings combine multiple arguments into one. So to keep this task somewhat manageable, we content ourselves with just getting everything into the same struct Signed-off-by: Simon Glass --- arch/x86/include/asm/zimage.h | 29 +---------------------------- arch/x86/lib/zimage.c | 4 ++-- include/bootm.h | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 76b2a797ccf..13a08850dfb 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -42,34 +42,7 @@ enum { ZBOOT_STATE_COUNT = 5, }; -/** - * struct zboot_state - Current state of the boot - * - * @bzimage_addr: Address of the bzImage to boot, or 0 if the image has already - * been loaded and does not exist (as a cohesive whole) in memory - * @bzimage_size: Size of the bzImage, or 0 to detect this - * @initrd_addr: Address of the initial ramdisk, or 0 if none - * @initrd_size: Size of the initial ramdisk, or 0 if none - * @load_address: Address where the bzImage is moved before booting, either - * BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR - * This is set up when loading the zimage - * @base_ptr: Pointer to the boot parameters, typically at address - * DEFAULT_SETUP_BASE - * This is set up when loading the zimage - * @cmdline: Environment variable containing the 'override' command line, or - * NULL to use the one in the setup block - */ -struct zboot_state { - ulong bzimage_addr; - ulong bzimage_size; - ulong initrd_addr; - ulong initrd_size; - ulong load_address; - struct boot_params *base_ptr; - const char *cmdline; -}; - -extern struct zboot_state state; +extern struct bootm_info state; /** * zboot_load() - Load a zimage diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 8d791416066..1dbebfe8afd 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -56,7 +56,7 @@ DECLARE_GLOBAL_DATA_PTR; #define COMMAND_LINE_SIZE 2048 /* Current state of the boot */ -struct zboot_state state; +struct bootm_info state; static void build_command_line(char *command_line, int auto_boot) { @@ -642,7 +642,7 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr, ulong initrd_size, ulong base_addr, const char *cmdline) { - memset(&state, '\0', sizeof(state)); + bootm_init(&state); state.bzimage_size = bzimage_size; state.initrd_addr = initrd_addr; diff --git a/include/bootm.h b/include/bootm.h index 154fb98cfcd..5fa9761629e 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -44,6 +44,21 @@ struct cmd_tbl; * @argc: Number of arguments to the command (excluding the actual command). * This is 0 if there are no arguments * @argv: NULL-terminated list of arguments, or NULL if there are no arguments + * + * For zboot: + * @bzimage_addr: Address of the bzImage to boot, or 0 if the image has already + * been loaded and does not exist (as a cohesive whole) in memory + * @bzimage_size: Size of the bzImage, or 0 to detect this + * @initrd_addr: Address of the initial ramdisk, or 0 if none + * @initrd_size: Size of the initial ramdisk, or 0 if none + * @load_address: Address where the bzImage is moved before booting, either + * BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR + * This is set up when loading the zimage + * @base_ptr: Pointer to the boot parameters, typically at address + * DEFAULT_SETUP_BASE + * This is set up when loading the zimage + * @cmdline: Environment variable containing the 'override' command line, or + * NULL to use the one in the setup block */ struct bootm_info { const char *addr_img; @@ -54,8 +69,26 @@ struct bootm_info { const char *cmd_name; int argc; char *const *argv; + + /* zboot items */ +#ifdef CONFIG_X86 + ulong bzimage_addr; + ulong bzimage_size; + ulong initrd_addr; + ulong initrd_size; + ulong load_address; + struct boot_params *base_ptr; + const char *cmdline; +#endif }; +/* macro to allow setting fields in generic code */ +#ifdef CONFIG_X86 +#define bootm_x86_set(_bmi, _field, _val) (_bmi)->_field = (_val) +#else +#define bootm_x86_set(_bmi, _field, _val) +#endif + /** * bootm_init() - Set up a bootm_info struct with useful defaults * From 00cfb598e740d8bad79097e7e069ad71d86bbd5a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:24:59 -0700 Subject: [PATCH 05/29] x86: Rename state to bmi Use the common name for the struct, in preparation for passing it around between functions. Signed-off-by: Simon Glass --- arch/x86/include/asm/zimage.h | 2 +- arch/x86/lib/zimage.c | 48 +++++++++++++++++------------------ cmd/x86/zboot.c | 4 +-- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 13a08850dfb..b592057e58b 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -42,7 +42,7 @@ enum { ZBOOT_STATE_COUNT = 5, }; -extern struct bootm_info state; +extern struct bootm_info bmi; /** * zboot_load() - Load a zimage diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 1dbebfe8afd..991d0c84006 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -56,7 +56,7 @@ DECLARE_GLOBAL_DATA_PTR; #define COMMAND_LINE_SIZE 2048 /* Current state of the boot */ -struct bootm_info state; +struct bootm_info bmi; static void build_command_line(char *command_line, int auto_boot) { @@ -371,8 +371,8 @@ int zboot_load(void) struct boot_params *base_ptr; int ret; - if (state.base_ptr) { - struct boot_params *from = (struct boot_params *)state.base_ptr; + if (bmi.base_ptr) { + struct boot_params *from = (struct boot_params *)bmi.base_ptr; base_ptr = (struct boot_params *)DEFAULT_SETUP_BASE; log_debug("Building boot_params at 0x%8.8lx\n", @@ -380,18 +380,18 @@ int zboot_load(void) memset(base_ptr, '\0', sizeof(*base_ptr)); base_ptr->hdr = from->hdr; } else { - base_ptr = load_zimage((void *)state.bzimage_addr, state.bzimage_size, - &state.load_address); + base_ptr = load_zimage((void *)bmi.bzimage_addr, bmi.bzimage_size, + &bmi.load_address); if (!base_ptr) { puts("## Kernel loading failed ...\n"); return -EINVAL; } } - state.base_ptr = base_ptr; + bmi.base_ptr = base_ptr; - ret = env_set_hex("zbootbase", map_to_sysmem(state.base_ptr)); + ret = env_set_hex("zbootbase", map_to_sysmem(bmi.base_ptr)); if (!ret) - ret = env_set_hex("zbootaddr", state.load_address); + ret = env_set_hex("zbootaddr", bmi.load_address); if (ret) return ret; @@ -400,12 +400,12 @@ int zboot_load(void) int zboot_setup(void) { - struct boot_params *base_ptr = state.base_ptr; + struct boot_params *base_ptr = bmi.base_ptr; int ret; ret = setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET, - 0, state.initrd_addr, state.initrd_size, - (ulong)state.cmdline); + 0, bmi.initrd_addr, bmi.initrd_size, + (ulong)bmi.cmdline); if (ret) return -EINVAL; @@ -414,7 +414,7 @@ int zboot_setup(void) int zboot_go(void) { - struct boot_params *params = state.base_ptr; + struct boot_params *params = bmi.base_ptr; struct setup_header *hdr = ¶ms->hdr; bool image_64bit; ulong entry; @@ -422,7 +422,7 @@ int zboot_go(void) disable_interrupts(); - entry = state.load_address; + entry = bmi.load_address; image_64bit = false; if (IS_ENABLED(CONFIG_X86_RUN_64BIT) && (hdr->xloadflags & XLF_KERNEL_64)) { @@ -430,7 +430,7 @@ int zboot_go(void) } /* we assume that the kernel is in place */ - ret = boot_linux_kernel((ulong)state.base_ptr, entry, image_64bit); + ret = boot_linux_kernel((ulong)bmi.base_ptr, entry, image_64bit); return ret; } @@ -596,7 +596,7 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) print_num("Start sys seg", hdr->start_sys_seg); print_num("Kernel version", hdr->kernel_version); version = zimage_get_kernel_version(base_ptr, - (void *)state.bzimage_addr); + (void *)bmi.bzimage_addr); if (version) printf(" @%p: %s\n", version, version); print_num("Type of loader", hdr->type_of_loader); @@ -642,22 +642,22 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr, ulong initrd_size, ulong base_addr, const char *cmdline) { - bootm_init(&state); + bootm_init(&bmi); - state.bzimage_size = bzimage_size; - state.initrd_addr = initrd_addr; - state.initrd_size = initrd_size; + bmi.bzimage_size = bzimage_size; + bmi.initrd_addr = initrd_addr; + bmi.initrd_size = initrd_size; if (base_addr) { - state.base_ptr = map_sysmem(base_addr, 0); - state.load_address = bzimage_addr; + bmi.base_ptr = map_sysmem(base_addr, 0); + bmi.load_address = bzimage_addr; } else { - state.bzimage_addr = bzimage_addr; + bmi.bzimage_addr = bzimage_addr; } - state.cmdline = cmdline; + bmi.cmdline = cmdline; } void zboot_info(void) { printf("Kernel loaded at %08lx, setup_base=%p\n", - state.load_address, state.base_ptr); + bmi.load_address, bmi.base_ptr); } diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c index 40f67a75593..0d0a8e53172 100644 --- a/cmd/x86/zboot.c +++ b/cmd/x86/zboot.c @@ -57,7 +57,7 @@ static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc, static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - if (!state.base_ptr) { + if (!bmi.base_ptr) { printf("base is not set: use 'zboot load' first\n"); return CMD_RET_FAILURE; } @@ -97,7 +97,7 @@ static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc, static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct boot_params *base_ptr = state.base_ptr; + struct boot_params *base_ptr = bmi.base_ptr; if (argc > 1) base_ptr = (void *)hextoul(argv[1], NULL); From 4e36b1739b03e81ff395959b58fe33e67c4d2233 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:00 -0700 Subject: [PATCH 06/29] x86: Move the bootm state for zimage into cmd/ Rather than holding the state in the implementation code, move it to the command code. The state is now passed to the implementation functions and can there (with future work) be pass in from bootstd, without going through the commands. Signed-off-by: Simon Glass --- arch/x86/include/asm/zimage.h | 22 +++++----- arch/x86/lib/zimage.c | 75 +++++++++++++++++------------------ cmd/bootflow.c | 5 ++- cmd/x86/zboot.c | 20 ++++++---- include/bootm.h | 8 +++- 5 files changed, 73 insertions(+), 57 deletions(-) diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index b592057e58b..4ed6d8d5cc2 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -10,6 +10,8 @@ #include #include +struct bootm_info; + /* linux i386 zImage/bzImage header. Offsets relative to * the start of the image */ @@ -42,8 +44,6 @@ enum { ZBOOT_STATE_COUNT = 5, }; -extern struct bootm_info bmi; - /** * zboot_load() - Load a zimage * @@ -51,21 +51,21 @@ extern struct bootm_info bmi; * * Return: 0 if OK, -ve on error */ -int zboot_load(void); +int zboot_load(struct bootm_info *bmi); /** * zboot_setup() - Set up the zboot image reeady for booting * * Return: 0 if OK, -ve on error */ -int zboot_setup(void); +int zboot_setup(struct bootm_info *bmi); /** * zboot_go() - Start the image * * Return: 0 if OK, -ve on error */ -int zboot_go(void); +int zboot_go(struct bootm_info *bmi); /** * load_zimage() - Load a zImage or bzImage @@ -104,6 +104,7 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, * * Record information about a zimage so it can be booted * + * @bmi: Bootm information * @bzimage_addr: Address of the bzImage to boot * @bzimage_size: Size of the bzImage, or 0 to detect this * @initrd_addr: Address of the initial ramdisk, or 0 if none @@ -114,14 +115,17 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, * @cmdline: Environment variable containing the 'override' command line, or * NULL to use the one in the setup block */ -void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr, - ulong initrd_size, ulong base_addr, const char *cmdline); +void zboot_start(struct bootm_info *bmi, ulong bzimage_addr, ulong bzimage_size, + ulong initrd_addr, ulong initrd_size, ulong base_addr, + const char *cmdline); /** * zboot_info() - Show simple info about a zimage * - * Shows wherer the kernel was loaded and also the setup base + * Shows where the kernel was loaded and also the setup base + * + * @bmi: Bootm information */ -void zboot_info(void); +void zboot_info(struct bootm_info *bmi); #endif diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 991d0c84006..7f4b117b403 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -55,9 +55,6 @@ DECLARE_GLOBAL_DATA_PTR; #define COMMAND_LINE_SIZE 2048 -/* Current state of the boot */ -struct bootm_info bmi; - static void build_command_line(char *command_line, int auto_boot) { char *env_command_line; @@ -366,13 +363,13 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, return 0; } -int zboot_load(void) +int zboot_load(struct bootm_info *bmi) { struct boot_params *base_ptr; int ret; - if (bmi.base_ptr) { - struct boot_params *from = (struct boot_params *)bmi.base_ptr; + if (bmi->base_ptr) { + struct boot_params *from = (struct boot_params *)bmi->base_ptr; base_ptr = (struct boot_params *)DEFAULT_SETUP_BASE; log_debug("Building boot_params at 0x%8.8lx\n", @@ -380,41 +377,41 @@ int zboot_load(void) memset(base_ptr, '\0', sizeof(*base_ptr)); base_ptr->hdr = from->hdr; } else { - base_ptr = load_zimage((void *)bmi.bzimage_addr, bmi.bzimage_size, - &bmi.load_address); + base_ptr = load_zimage((void *)bmi->bzimage_addr, + bmi->bzimage_size, &bmi->load_address); if (!base_ptr) { puts("## Kernel loading failed ...\n"); return -EINVAL; } } - bmi.base_ptr = base_ptr; + bmi->base_ptr = base_ptr; - ret = env_set_hex("zbootbase", map_to_sysmem(bmi.base_ptr)); + ret = env_set_hex("zbootbase", map_to_sysmem(bmi->base_ptr)); if (!ret) - ret = env_set_hex("zbootaddr", bmi.load_address); + ret = env_set_hex("zbootaddr", bmi->load_address); if (ret) return ret; return 0; } -int zboot_setup(void) +int zboot_setup(struct bootm_info *bmi) { - struct boot_params *base_ptr = bmi.base_ptr; + struct boot_params *base_ptr = bmi->base_ptr; int ret; ret = setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET, - 0, bmi.initrd_addr, bmi.initrd_size, - (ulong)bmi.cmdline); + 0, bmi->initrd_addr, bmi->initrd_size, + (ulong)bmi->cmdline); if (ret) return -EINVAL; return 0; } -int zboot_go(void) +int zboot_go(struct bootm_info *bmi) { - struct boot_params *params = bmi.base_ptr; + struct boot_params *params = bmi->base_ptr; struct setup_header *hdr = ¶ms->hdr; bool image_64bit; ulong entry; @@ -422,7 +419,7 @@ int zboot_go(void) disable_interrupts(); - entry = bmi.load_address; + entry = bmi->load_address; image_64bit = false; if (IS_ENABLED(CONFIG_X86_RUN_64BIT) && (hdr->xloadflags & XLF_KERNEL_64)) { @@ -430,7 +427,7 @@ int zboot_go(void) } /* we assume that the kernel is in place */ - ret = boot_linux_kernel((ulong)bmi.base_ptr, entry, image_64bit); + ret = boot_linux_kernel((ulong)bmi->base_ptr, entry, image_64bit); return ret; } @@ -438,16 +435,18 @@ int zboot_go(void) int zboot_run_args(ulong addr, ulong size, ulong initrd, ulong initrd_size, ulong base, char *cmdline) { + struct bootm_info bmi; int ret; - zboot_start(addr, size, initrd, initrd_size, base, cmdline); - ret = zboot_load(); + bootm_init(&bmi); + zboot_start(&bmi, addr, size, initrd, initrd_size, base, cmdline); + ret = zboot_load(&bmi); if (ret) return log_msg_ret("ld", ret); - ret = zboot_setup(); + ret = zboot_setup(&bmi); if (ret) return log_msg_ret("set", ret); - ret = zboot_go(); + ret = zboot_go(&bmi); if (ret) return log_msg_ret("go", ret); @@ -555,7 +554,8 @@ static void show_loader(struct setup_header *hdr) printf("\n"); } -void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) +void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, + bool show_cmdline) { struct setup_header *hdr; const char *version; @@ -596,7 +596,7 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) print_num("Start sys seg", hdr->start_sys_seg); print_num("Kernel version", hdr->kernel_version); version = zimage_get_kernel_version(base_ptr, - (void *)bmi.bzimage_addr); + (void *)bmi->bzimage_addr); if (version) printf(" @%p: %s\n", version, version); print_num("Type of loader", hdr->type_of_loader); @@ -639,25 +639,24 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) print_num("Kernel info offset", hdr->kernel_info_offset); } -void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr, - ulong initrd_size, ulong base_addr, const char *cmdline) +void zboot_start(struct bootm_info *bmi, ulong bzimage_addr, ulong bzimage_size, + ulong initrd_addr, ulong initrd_size, ulong base_addr, + const char *cmdline) { - bootm_init(&bmi); - - bmi.bzimage_size = bzimage_size; - bmi.initrd_addr = initrd_addr; - bmi.initrd_size = initrd_size; + bmi->bzimage_size = bzimage_size; + bmi->initrd_addr = initrd_addr; + bmi->initrd_size = initrd_size; if (base_addr) { - bmi.base_ptr = map_sysmem(base_addr, 0); - bmi.load_address = bzimage_addr; + bmi->base_ptr = map_sysmem(base_addr, 0); + bmi->load_address = bzimage_addr; } else { - bmi.bzimage_addr = bzimage_addr; + bmi->bzimage_addr = bzimage_addr; } - bmi.cmdline = cmdline; + bmi->cmdline = cmdline; } -void zboot_info(void) +void zboot_info(struct bootm_info *bmi) { printf("Kernel loaded at %08lx, setup_base=%p\n", - bmi.load_address, bmi.base_ptr); + bmi->load_address, bmi->base_ptr); } diff --git a/cmd/bootflow.c b/cmd/bootflow.c index f88995a478f..72b06a42e4d 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -380,7 +380,10 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, bflow = std->cur_bootflow; if (IS_ENABLED(CONFIG_X86) && x86_setup) { - zimage_dump(bflow->x86_setup, false); + struct bootm_info bmi; + + bootm_init(&bmi); + zimage_dump(&bmi, bflow->x86_setup, false); return 0; } diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c index 0d0a8e53172..029ff4eb9fd 100644 --- a/cmd/x86/zboot.c +++ b/cmd/x86/zboot.c @@ -13,6 +13,9 @@ #include #include +/* Current state of the boot */ +static struct bootm_info bmi; + static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -21,6 +24,8 @@ static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc, ulong base_addr; int i; + bootm_init(&bmi); + log_debug("argc %d:", argc); for (i = 0; i < argc; i++) log_debug(" %s", argv[i]); @@ -36,7 +41,7 @@ static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc, base_addr = argc > 5 ? hextoul(argv[5], NULL) : 0; cmdline = argc > 6 ? env_get(argv[6]) : NULL; - zboot_start(bzimage_addr, bzimage_size, initrd_addr, initrd_size, + zboot_start(&bmi, bzimage_addr, bzimage_size, initrd_addr, initrd_size, base_addr, cmdline); return 0; @@ -47,7 +52,7 @@ static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc, { int ret; - ret = zboot_load(); + ret = zboot_load(&bmi); if (ret) return ret; @@ -61,12 +66,13 @@ static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc, printf("base is not set: use 'zboot load' first\n"); return CMD_RET_FAILURE; } - if (zboot_setup()) { + + if (zboot_setup(&bmi)) { puts("Setting up boot parameters failed ...\n"); return CMD_RET_FAILURE; } - if (zboot_setup()) + if (zboot_setup(&bmi)) return CMD_RET_FAILURE; return 0; @@ -75,7 +81,7 @@ static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc, static int do_zboot_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - zboot_info(); + zboot_info(&bmi); return 0; } @@ -85,7 +91,7 @@ static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc, { int ret; - ret = zboot_go(); + ret = zboot_go(&bmi); if (ret) { printf("Kernel returned! (err=%d)\n", ret); return CMD_RET_FAILURE; @@ -105,7 +111,7 @@ static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc, printf("No zboot setup_base\n"); return CMD_RET_FAILURE; } - zimage_dump(base_ptr, true); + zimage_dump(&bmi, base_ptr, true); return 0; } diff --git a/include/bootm.h b/include/bootm.h index 5fa9761629e..fe7f80b88a5 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -92,6 +92,8 @@ struct bootm_info { /** * bootm_init() - Set up a bootm_info struct with useful defaults * + * @bmi: Bootm information + * * Set up the struct with default values for all members: * @boot_progress is set to true and @images is set to the global images * variable. Everything else is set to NULL except @argc which is 0 @@ -107,7 +109,7 @@ void bootm_init(struct bootm_info *bmi); * - disabled interrupts. * * @flag: Flags indicating what to do (BOOTM_STATE_...) - * bmi: Bootm information + * @bmi: Bootm information * Return: 1 on error. On success the OS boots so this function does * not return. */ @@ -340,11 +342,13 @@ const char *zimage_get_kernel_version(struct boot_params *params, * * This shows all available information in a zimage that has been loaded. * + * @bmi: Bootm information * @base_ptr: Pointer to the boot parameters, typically at address * DEFAULT_SETUP_BASE * @show_cmdline: true to show the full command line */ -void zimage_dump(struct boot_params *base_ptr, bool show_cmdline); +void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, + bool show_cmdline); /* * bootm_boot_start() - Boot an image at the given address From 1592ff27d502efdc79992f57c07ff0cf81bc9305 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:01 -0700 Subject: [PATCH 07/29] bootstd: Correct display of kernel version The address of the bzImage is not recorded in the bootflow, so we cannot actually locate the version at present. Handle this case, to avoid showing invalid data. Signed-off-by: Simon Glass --- arch/x86/lib/zimage.c | 13 ++++++++----- cmd/bootflow.c | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 7f4b117b403..d71285e71d9 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -558,7 +558,6 @@ void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, bool show_cmdline) { struct setup_header *hdr; - const char *version; int i; printf("Setup located at %p:\n\n", base_ptr); @@ -595,10 +594,14 @@ void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, print_num("Real mode switch", hdr->realmode_swtch); print_num("Start sys seg", hdr->start_sys_seg); print_num("Kernel version", hdr->kernel_version); - version = zimage_get_kernel_version(base_ptr, - (void *)bmi->bzimage_addr); - if (version) - printf(" @%p: %s\n", version, version); + if (bmi->bzimage_addr) { + const char *version; + + version = zimage_get_kernel_version(base_ptr, + (void *)bmi->bzimage_addr); + if (version) + printf(" @%p: %s\n", version, version); + } print_num("Type of loader", hdr->type_of_loader); show_loader(hdr); print_num("Load flags", hdr->loadflags); diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 72b06a42e4d..da17fd93b8b 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -383,6 +383,8 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, struct bootm_info bmi; bootm_init(&bmi); + /* we don't know this at present */ + bootm_x86_set(&bmi, bzimage_addr, 0); zimage_dump(&bmi, bflow->x86_setup, false); return 0; From c73da92304280b229e3d8dfd565fae5a24fe3ce8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:02 -0700 Subject: [PATCH 08/29] x86: Drop the unnecessary base_ptr argument to zboot_dump() This value is include the bootm_info, so drop the unnecessary parameter. Signed-off-by: Simon Glass --- arch/x86/lib/zimage.c | 5 +++-- cmd/bootflow.c | 3 ++- cmd/x86/zboot.c | 8 +++----- include/bootm.h | 7 ++----- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index d71285e71d9..145ba0b8ea0 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -554,12 +554,13 @@ static void show_loader(struct setup_header *hdr) printf("\n"); } -void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, - bool show_cmdline) +void zimage_dump(struct bootm_info *bmi, bool show_cmdline) { + struct boot_params *base_ptr; struct setup_header *hdr; int i; + base_ptr = bmi->base_ptr; printf("Setup located at %p:\n\n", base_ptr); print_num64("ACPI RSDP addr", base_ptr->acpi_rsdp_addr); diff --git a/cmd/bootflow.c b/cmd/bootflow.c index da17fd93b8b..6d0be320bdb 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -385,7 +385,8 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, bootm_init(&bmi); /* we don't know this at present */ bootm_x86_set(&bmi, bzimage_addr, 0); - zimage_dump(&bmi, bflow->x86_setup, false); + bootm_x86_set(&bmi, base_ptr, bflow->x86_setup); + zimage_dump(&bmi, false); return 0; } diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c index 029ff4eb9fd..ee099ca041b 100644 --- a/cmd/x86/zboot.c +++ b/cmd/x86/zboot.c @@ -103,15 +103,13 @@ static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc, static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct boot_params *base_ptr = bmi.base_ptr; - if (argc > 1) - base_ptr = (void *)hextoul(argv[1], NULL); - if (!base_ptr) { + bmi.base_ptr = (void *)hextoul(argv[1], NULL); + if (!bmi.base_ptr) { printf("No zboot setup_base\n"); return CMD_RET_FAILURE; } - zimage_dump(&bmi, base_ptr, true); + zimage_dump(&bmi, true); return 0; } diff --git a/include/bootm.h b/include/bootm.h index fe7f80b88a5..c471615b08c 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -342,13 +342,10 @@ const char *zimage_get_kernel_version(struct boot_params *params, * * This shows all available information in a zimage that has been loaded. * - * @bmi: Bootm information - * @base_ptr: Pointer to the boot parameters, typically at address - * DEFAULT_SETUP_BASE + * @bmi: Bootm information, with valid base_ptr * @show_cmdline: true to show the full command line */ -void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, - bool show_cmdline); +void zimage_dump(struct bootm_info *bmi, bool show_cmdline); /* * bootm_boot_start() - Boot an image at the given address From 0fd3ed1cd73d6b262c204c27cbe6dc1ad1c09e91 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:03 -0700 Subject: [PATCH 09/29] boot: Use strlcpy() in label_boot() This function is recommended instead of strncpy() since it always terminates the string. Signed-off-by: Simon Glass --- boot/pxe_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 82f217aaf86..e96935896a9 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -558,7 +558,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) } if (label->append) - strncpy(bootargs, label->append, sizeof(bootargs)); + strlcpy(bootargs, label->append, sizeof(bootargs)); strcat(bootargs, ip_str); strcat(bootargs, mac_str); From ff9fef41fe4d329a5c76746cc45f9fbf8fdb9b12 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:04 -0700 Subject: [PATCH 10/29] boot: Split pxe label_boot() into two parts This function is far too long. Split out the part which builds and runs the bootm/i/z commands into its own function. Add a function comment for the new label_run_boot() function. Signed-off-by: Simon Glass Reviewed-by: Quentin Schulz --- boot/pxe_utils.c | 284 ++++++++++++++++++++++++++--------------------- 1 file changed, 156 insertions(+), 128 deletions(-) diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index e96935896a9..fd1a09225e1 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -433,142 +433,29 @@ skip_overlay: #endif /** - * label_boot() - Boot according to the contents of a pxe_label - * - * If we can't boot for any reason, we return. A successful boot never - * returns. - * - * The kernel will be stored in the location given by the 'kernel_addr_r' - * environment variable. - * - * If the label specifies an initrd file, it will be stored in the location - * given by the 'ramdisk_addr_r' environment variable. - * - * If the label specifies an 'append' line, its contents will overwrite that - * of the 'bootargs' environment variable. + * label_run_boot() - Set up the FDT and call the appropriate bootm/z/i command * * @ctx: PXE context * @label: Label to process - * Returns does not return on success, otherwise returns 0 if a localboot - * label was processed, or 1 on error + * @kernel_addr: String containing kernel address (cannot be NULL) + * @initrd_addr_str: String containing initrd address (NULL if none) + * @initrd_filesize: String containing initrd size (only used if + * @initrd_addr_str) + * @initrd_str: initrd string to process (only used if @initrd_addr_str) + * Return: does not return on success, or returns 0 if the boot command + * returned, or -ve error value on error */ -static int label_boot(struct pxe_context *ctx, struct pxe_label *label) +static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, + char *kernel_addr, char *initrd_addr_str, + char *initrd_filesize, char *initrd_str) { char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL }; - char *kernel_addr = NULL; - char *initrd_addr_str = NULL; - char initrd_filesize[10]; - char initrd_str[28]; - char mac_str[29] = ""; - char ip_str[68] = ""; - char *fit_addr = NULL; + ulong kernel_addr_r; int bootm_argc = 2; int zboot_argc = 3; - int len = 0; - ulong kernel_addr_r; void *buf; - label_print(label); - - label->attempted = 1; - - if (label->localboot) { - if (label->localboot_val >= 0) - label_localboot(label); - return 0; - } - - if (!label->kernel) { - printf("No kernel given, skipping %s\n", - label->name); - return 1; - } - - if (get_relfile_envaddr(ctx, label->kernel, "kernel_addr_r", - (enum bootflow_img_t)IH_TYPE_KERNEL, NULL) - < 0) { - printf("Skipping %s for failure retrieving kernel\n", - label->name); - return 1; - } - - kernel_addr = env_get("kernel_addr_r"); - /* for FIT, append the configuration identifier */ - if (label->config) { - int len = strlen(kernel_addr) + strlen(label->config) + 1; - - fit_addr = malloc(len); - if (!fit_addr) { - printf("malloc fail (FIT address)\n"); - return 1; - } - snprintf(fit_addr, len, "%s%s", kernel_addr, label->config); - kernel_addr = fit_addr; - } - - /* For FIT, the label can be identical to kernel one */ - if (label->initrd && !strcmp(label->kernel_label, label->initrd)) { - initrd_addr_str = kernel_addr; - } else if (label->initrd) { - ulong size; - if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r", - (enum bootflow_img_t)IH_TYPE_RAMDISK, - &size) < 0) { - printf("Skipping %s for failure retrieving initrd\n", - label->name); - goto cleanup; - } - strcpy(initrd_filesize, simple_xtoa(size)); - initrd_addr_str = env_get("ramdisk_addr_r"); - size = snprintf(initrd_str, sizeof(initrd_str), "%s:%lx", - initrd_addr_str, size); - if (size >= sizeof(initrd_str)) - goto cleanup; - } - - if (label->ipappend & 0x1) { - sprintf(ip_str, " ip=%s:%s:%s:%s", - env_get("ipaddr"), env_get("serverip"), - env_get("gatewayip"), env_get("netmask")); - } - - if (IS_ENABLED(CONFIG_CMD_NET)) { - if (label->ipappend & 0x2) { - int err; - - strcpy(mac_str, " BOOTIF="); - err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8); - if (err < 0) - mac_str[0] = '\0'; - } - } - - if ((label->ipappend & 0x3) || label->append) { - char bootargs[CONFIG_SYS_CBSIZE] = ""; - char finalbootargs[CONFIG_SYS_CBSIZE]; - - if (strlen(label->append ?: "") + - strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) { - printf("bootarg overflow %zd+%zd+%zd+1 > %zd\n", - strlen(label->append ?: ""), - strlen(ip_str), strlen(mac_str), - sizeof(bootargs)); - goto cleanup; - } - - if (label->append) - strlcpy(bootargs, label->append, sizeof(bootargs)); - - strcat(bootargs, ip_str); - strcat(bootargs, mac_str); - - cli_simple_process_macros(bootargs, finalbootargs, - sizeof(finalbootargs)); - env_set("bootargs", finalbootargs); - printf("append: %s\n", finalbootargs); - } - /* * fdt usage is optional: * It handles the following scenarios. @@ -607,6 +494,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) } } else if (label->fdtdir) { char *f1, *f2, *f3, *f4, *slash; + int len; f1 = env_get("fdtfile"); if (f1) { @@ -649,7 +537,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) fdtfilefree = malloc(len); if (!fdtfilefree) { printf("malloc fail (FDT filename)\n"); - goto cleanup; + return -ENOMEM; } snprintf(fdtfilefree, len, "%s%s%s%s%s%s", @@ -669,7 +557,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) if (label->fdt) { printf("Skipping %s for failure retrieving FDT\n", label->name); - goto cleanup; + return -ENOENT; } if (label->fdtdir) { @@ -750,10 +638,150 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) unmap_sysmem(buf); + return 0; +} + +/** + * label_boot() - Boot according to the contents of a pxe_label + * + * If we can't boot for any reason, we return. A successful boot never + * returns. + * + * The kernel will be stored in the location given by the 'kernel_addr_r' + * environment variable. + * + * If the label specifies an initrd file, it will be stored in the location + * given by the 'ramdisk_addr_r' environment variable. + * + * If the label specifies an 'append' line, its contents will overwrite that + * of the 'bootargs' environment variable. + * + * @ctx: PXE context + * @label: Label to process + * Returns does not return on success, otherwise returns 0 if a localboot + * label was processed, or 1 on error + */ +static int label_boot(struct pxe_context *ctx, struct pxe_label *label) +{ + char *kernel_addr = NULL; + char *initrd_addr_str = NULL; + char initrd_filesize[10]; + char initrd_str[28]; + char mac_str[29] = ""; + char ip_str[68] = ""; + char *fit_addr = NULL; + + label_print(label); + + label->attempted = 1; + + if (label->localboot) { + if (label->localboot_val >= 0) + label_localboot(label); + return 0; + } + + if (!label->kernel) { + printf("No kernel given, skipping %s\n", + label->name); + return 1; + } + + if (get_relfile_envaddr(ctx, label->kernel, "kernel_addr_r", + (enum bootflow_img_t)IH_TYPE_KERNEL, NULL) + < 0) { + printf("Skipping %s for failure retrieving kernel\n", + label->name); + return 1; + } + + kernel_addr = env_get("kernel_addr_r"); + /* for FIT, append the configuration identifier */ + if (label->config) { + int len = strlen(kernel_addr) + strlen(label->config) + 1; + + fit_addr = malloc(len); + if (!fit_addr) { + printf("malloc fail (FIT address)\n"); + return 1; + } + snprintf(fit_addr, len, "%s%s", kernel_addr, label->config); + kernel_addr = fit_addr; + } + + /* For FIT, the label can be identical to kernel one */ + if (label->initrd && !strcmp(label->kernel_label, label->initrd)) { + initrd_addr_str = kernel_addr; + } else if (label->initrd) { + ulong size; + int ret; + + ret = get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r", + (enum bootflow_img_t)IH_TYPE_RAMDISK, + &size); + if (ret < 0) { + printf("Skipping %s for failure retrieving initrd\n", + label->name); + goto cleanup; + } + strcpy(initrd_filesize, simple_xtoa(size)); + initrd_addr_str = env_get("ramdisk_addr_r"); + size = snprintf(initrd_str, sizeof(initrd_str), "%s:%lx", + initrd_addr_str, size); + if (size >= sizeof(initrd_str)) + goto cleanup; + } + + if (label->ipappend & 0x1) { + sprintf(ip_str, " ip=%s:%s:%s:%s", + env_get("ipaddr"), env_get("serverip"), + env_get("gatewayip"), env_get("netmask")); + } + + if (IS_ENABLED(CONFIG_CMD_NET)) { + if (label->ipappend & 0x2) { + int err; + + strcpy(mac_str, " BOOTIF="); + err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8); + if (err < 0) + mac_str[0] = '\0'; + } + } + + if ((label->ipappend & 0x3) || label->append) { + char bootargs[CONFIG_SYS_CBSIZE] = ""; + char finalbootargs[CONFIG_SYS_CBSIZE]; + + if (strlen(label->append ?: "") + + strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) { + printf("bootarg overflow %zd+%zd+%zd+1 > %zd\n", + strlen(label->append ?: ""), + strlen(ip_str), strlen(mac_str), + sizeof(bootargs)); + goto cleanup; + } + + if (label->append) + strlcpy(bootargs, label->append, sizeof(bootargs)); + + strcat(bootargs, ip_str); + strcat(bootargs, mac_str); + + cli_simple_process_macros(bootargs, finalbootargs, + sizeof(finalbootargs)); + env_set("bootargs", finalbootargs); + printf("append: %s\n", finalbootargs); + } + + label_run_boot(ctx, label, kernel_addr, initrd_addr_str, + initrd_filesize, initrd_str); + /* ignore the error value since we are going to fail anyway */ + cleanup: free(fit_addr); - return 1; + return 1; /* returning is always failure */ } /** enum token_type - Tokens for the pxe file parser */ From f6aa262f55b78e3a21dd020e47601320c2edec4e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:05 -0700 Subject: [PATCH 11/29] boot: Split pxe label_run_boot() into two parts This function is quite long. Split out the FDT processing into its own function. Add a function comment for the new label_process_fdt() function. Signed-off-by: Simon Glass Reviewed-by: Quentin Schulz --- boot/pxe_utils.c | 100 ++++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 40 deletions(-) diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index fd1a09225e1..a14b4eb54c2 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -432,51 +432,37 @@ skip_overlay: } #endif -/** - * label_run_boot() - Set up the FDT and call the appropriate bootm/z/i command +/* + * label_process_fdt() - Process FDT for the label * * @ctx: PXE context * @label: Label to process - * @kernel_addr: String containing kernel address (cannot be NULL) - * @initrd_addr_str: String containing initrd address (NULL if none) - * @initrd_filesize: String containing initrd size (only used if - * @initrd_addr_str) - * @initrd_str: initrd string to process (only used if @initrd_addr_str) - * Return: does not return on success, or returns 0 if the boot command - * returned, or -ve error value on error + * @kernel_addr: String containing kernel address + * @bootm_argv: bootm arguments to fill in (this only adjusts @bootm_argv[3]) + * Return: 0 if OK, -ENOMEM if out of memory, -ENOENT if FDT file could not be + * loaded + * + * fdt usage is optional: + * It handles the following scenarios. + * + * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is + * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to + * bootm, and adjust argc appropriately. + * + * If retrieve fails and no exact fdt blob is specified in pxe file with + * "fdt" label, try Scenario 2. + * + * Scenario 2: If there is an fdt_addr specified, pass it along to + * bootm, and adjust argc appropriately. + * + * Scenario 3: If there is an fdtcontroladdr specified, pass it along to + * bootm, and adjust argc appropriately, unless the image type is fitImage. + * + * Scenario 4: fdt blob is not available. */ -static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, - char *kernel_addr, char *initrd_addr_str, - char *initrd_filesize, char *initrd_str) +static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label, + char *kernel_addr, char *bootm_argv[]) { - char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; - char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL }; - ulong kernel_addr_r; - int bootm_argc = 2; - int zboot_argc = 3; - void *buf; - - /* - * fdt usage is optional: - * It handles the following scenarios. - * - * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is - * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to - * bootm, and adjust argc appropriately. - * - * If retrieve fails and no exact fdt blob is specified in pxe file with - * "fdt" label, try Scenario 2. - * - * Scenario 2: If there is an fdt_addr specified, pass it along to - * bootm, and adjust argc appropriately. - * - * Scenario 3: If there is an fdtcontroladdr specified, pass it along to - * bootm, and adjust argc appropriately, unless the image type is fitImage. - * - * Scenario 4: fdt blob is not available. - */ - bootm_argv[3] = env_get("fdt_addr_r"); - /* For FIT, the label can be identical to kernel one */ if (label->fdt && !strcmp(label->kernel_label, label->fdt)) { bootm_argv[3] = kernel_addr; @@ -578,6 +564,40 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, } } + return 0; +} + +/** + * label_run_boot() - Set up the FDT and call the appropriate bootm/z/i command + * + * @ctx: PXE context + * @label: Label to process + * @kernel_addr: String containing kernel address (cannot be NULL) + * @initrd_addr_str: String containing initrd address (NULL if none) + * @initrd_filesize: String containing initrd size (only used if + * @initrd_addr_str) + * @initrd_str: initrd string to process (only used if @initrd_addr_str) + * Return: does not return on success, or returns 0 if the boot command + * returned, or -ve error value on error + */ +static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, + char *kernel_addr, char *initrd_addr_str, + char *initrd_filesize, char *initrd_str) +{ + char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; + char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL }; + ulong kernel_addr_r; + int bootm_argc = 2; + int zboot_argc = 3; + void *buf; + int ret; + + bootm_argv[3] = env_get("fdt_addr_r"); + + ret = label_process_fdt(ctx, label, kernel_addr, bootm_argv); + if (ret) + return ret; + bootm_argv[1] = kernel_addr; zboot_argv[1] = kernel_addr; From 600bc21da54a300f2825a5e3088719b1ffd5ee53 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:06 -0700 Subject: [PATCH 12/29] boot: Pass just the FDT argument to label_process_fdt() Since this function only adjusts one element of the bootm command, pass just that. This will make it easier to refactor things to remove the bootm command. Signed-off-by: Simon Glass Reviewed-by: Quentin Schulz --- boot/pxe_utils.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index a14b4eb54c2..2ada5c4aaac 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -438,7 +438,7 @@ skip_overlay: * @ctx: PXE context * @label: Label to process * @kernel_addr: String containing kernel address - * @bootm_argv: bootm arguments to fill in (this only adjusts @bootm_argv[3]) + * @fdt_argp: bootm argument to fill in, for FDT * Return: 0 if OK, -ENOMEM if out of memory, -ENOENT if FDT file could not be * loaded * @@ -461,13 +461,13 @@ skip_overlay: * Scenario 4: fdt blob is not available. */ static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label, - char *kernel_addr, char *bootm_argv[]) + char *kernel_addr, char **fdt_argp) { /* For FIT, the label can be identical to kernel one */ if (label->fdt && !strcmp(label->kernel_label, label->fdt)) { - bootm_argv[3] = kernel_addr; + *fdt_argp = kernel_addr; /* if fdt label is defined then get fdt from server */ - } else if (bootm_argv[3]) { + } else if (*fdt_argp) { char *fdtfile = NULL; char *fdtfilefree = NULL; @@ -538,7 +538,7 @@ static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label, free(fdtfilefree); if (err < 0) { - bootm_argv[3] = NULL; + *fdt_argp = NULL; if (label->fdt) { printf("Skipping %s for failure retrieving FDT\n", @@ -560,7 +560,7 @@ static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label, label_boot_fdtoverlay(ctx, label); #endif } else { - bootm_argv[3] = NULL; + *fdt_argp = NULL; } } @@ -594,7 +594,7 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, bootm_argv[3] = env_get("fdt_addr_r"); - ret = label_process_fdt(ctx, label, kernel_addr, bootm_argv); + ret = label_process_fdt(ctx, label, kernel_addr, &bootm_argv[3]); if (ret) return ret; From 7f10a7fe126dce5644d933af693eda40497d7755 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:07 -0700 Subject: [PATCH 13/29] bootm: Allow building bootm.c without CONFIG_SYS_BOOTM_LEN This code cannot be compiled by boards which don't have this option. Add an accessor in the header file to avoid another #ifdef Signed-off-by: Simon Glass Reviewed-by: Quentin Schulz --- boot/bootm.c | 8 ++++---- include/bootm.h | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/boot/bootm.c b/boot/bootm.c index 854ac7ec738..c719a50ef9a 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -633,11 +633,11 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress) load_buf = map_sysmem(load, 0); image_buf = map_sysmem(os.image_start, image_len); err = image_decomp(os.comp, load, os.image_start, os.type, - load_buf, image_buf, image_len, - CONFIG_SYS_BOOTM_LEN, &load_end); + load_buf, image_buf, image_len, bootm_len(), + &load_end); if (err) { - err = handle_decomp_error(os.comp, load_end - load, - CONFIG_SYS_BOOTM_LEN, err); + err = handle_decomp_error(os.comp, load_end - load, bootm_len(), + err); bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return err; } diff --git a/include/bootm.h b/include/bootm.h index c471615b08c..d174f18ac18 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -89,6 +89,14 @@ struct bootm_info { #define bootm_x86_set(_bmi, _field, _val) #endif +static inline ulong bootm_len(void) +{ +#ifdef CONFIG_SYS_BOOTM_LEN + return CONFIG_SYS_BOOTM_LEN; +#endif + return 0; +} + /** * bootm_init() - Set up a bootm_info struct with useful defaults * From 3c7b13b075488ebcff2923b0a7b46cc11f39285e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:08 -0700 Subject: [PATCH 14/29] boot: Convert IMAGE_FORMAT into an enum Use an enum so it is clearer that these options are related. Update genimg_get_format(), tidy up the function comment and move it to the header file, since it is exported. Signed-off-by: Simon Glass --- boot/image-board.c | 18 +++--------------- include/image.h | 26 +++++++++++++++++++++----- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/boot/image-board.c b/boot/image-board.c index 514f8e63f9c..addccf87c80 100644 --- a/boot/image-board.c +++ b/boot/image-board.c @@ -234,21 +234,7 @@ ulong genimg_get_kernel_addr(char * const img_addr) &fit_uname_kernel); } -/** - * genimg_get_format - get image format type - * @img_addr: image start address - * - * genimg_get_format() checks whether provided address points to a valid - * legacy or FIT image. - * - * New uImage format and FDT blob are based on a libfdt. FDT blob - * may be passed directly or embedded in a FIT image. In both situations - * genimg_get_format() must be able to dectect libfdt header. - * - * returns: - * image format type or IMAGE_FORMAT_INVALID if no image is present - */ -int genimg_get_format(const void *img_addr) +enum image_fmt_t genimg_get_format(const void *img_addr) { if (CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)) { const struct legacy_img_hdr *hdr; @@ -434,6 +420,8 @@ static int select_ramdisk(struct bootm_headers *images, const char *select, u8 a done = true; } break; + case IMAGE_FORMAT_INVALID: + break; } if (!done) { diff --git a/include/image.h b/include/image.h index c1db8383459..dc1a7c307cc 100644 --- a/include/image.h +++ b/include/image.h @@ -598,10 +598,12 @@ int boot_get_setup(struct bootm_headers *images, uint8_t arch, ulong *setup_star ulong *setup_len); /* Image format types, returned by _get_format() routine */ -#define IMAGE_FORMAT_INVALID 0x00 -#define IMAGE_FORMAT_LEGACY 0x01 /* legacy image_header based format */ -#define IMAGE_FORMAT_FIT 0x02 /* new, libfdt based format */ -#define IMAGE_FORMAT_ANDROID 0x03 /* Android boot image */ +enum image_fmt_t { + IMAGE_FORMAT_INVALID, + IMAGE_FORMAT_LEGACY, /* legacy image_header based format */ + IMAGE_FORMAT_FIT, /* new, libfdt based format */ + IMAGE_FORMAT_ANDROID, /* Android boot image */ +}; /** * genimg_get_kernel_addr_fit() - Parse FIT specifier @@ -630,7 +632,21 @@ ulong genimg_get_kernel_addr_fit(const char *const img_addr, const char **fit_uname_kernel); ulong genimg_get_kernel_addr(char * const img_addr); -int genimg_get_format(const void *img_addr); + +/** + * genimg_get_format - get image format type + * @img_addr: image start address + * Return: image format type or IMAGE_FORMAT_INVALID if no image is present + * + * genimg_get_format() checks whether provided address points to a valid + * legacy or FIT image. + * + * New uImage format and FDT blob are based on a libfdt. FDT blob + * may be passed directly or embedded in a FIT image. In both situations + * genimg_get_format() must be able to dectect libfdt header. + */ +enum image_fmt_t genimg_get_format(const void *img_addr); + int genimg_has_config(struct bootm_headers *images); /** From 098407e67390ed0c369029bab0777a51e5a7bad2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:09 -0700 Subject: [PATCH 15/29] boot: arm: riscv: sandbox: Add a format for the booti file Arm invented a new format for arm64 and something similar is also used with RISC-V. Add this to the list of supported formats and provide a way for the format to be detected on both architectures. Update the genimg_get_format() function to support this. Fix up switch() statements which don't currently mention this format. Booti does not support a ramdisk, so this can be ignored. Signed-off-by: Simon Glass --- arch/arm/lib/image.c | 9 ++++++++- arch/riscv/lib/image.c | 9 ++++++++- arch/sandbox/lib/bootm.c | 5 +++++ boot/image-board.c | 5 +++++ include/image.h | 9 +++++++++ 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/arch/arm/lib/image.c b/arch/arm/lib/image.c index 1f672eee2c8..d78d704cb58 100644 --- a/arch/arm/lib/image.c +++ b/arch/arm/lib/image.c @@ -28,6 +28,13 @@ struct Image_header { uint32_t res5; }; +bool booti_is_valid(const void *img) +{ + const struct Image_header *ih = img; + + return ih->magic == le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC); +} + int booti_setup(ulong image, ulong *relocated_addr, ulong *size, bool force_reloc) { @@ -39,7 +46,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size, ih = (struct Image_header *)map_sysmem(image, 0); - if (ih->magic != le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC)) { + if (!booti_is_valid(ih)) { puts("Bad Linux ARM64 Image magic!\n"); return 1; } diff --git a/arch/riscv/lib/image.c b/arch/riscv/lib/image.c index a82f48e9a50..859326cbac8 100644 --- a/arch/riscv/lib/image.c +++ b/arch/riscv/lib/image.c @@ -32,6 +32,13 @@ struct linux_image_h { uint32_t res4; /* reserved */ }; +bool booti_is_valid(const void *img) +{ + const struct linux_image_h *lhdr = img; + + return lhdr->magic == LINUX_RISCV_IMAGE_MAGIC; +} + int booti_setup(ulong image, ulong *relocated_addr, ulong *size, bool force_reloc) { @@ -39,7 +46,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size, lhdr = (struct linux_image_h *)map_sysmem(image, 0); - if (lhdr->magic != LINUX_RISCV_IMAGE_MAGIC) { + if (!booti_is_valid(lhdr)) { puts("Bad Linux RISCV Image magic!\n"); return -EINVAL; } diff --git a/arch/sandbox/lib/bootm.c b/arch/sandbox/lib/bootm.c index 44ba8b52e13..8ed923750f4 100644 --- a/arch/sandbox/lib/bootm.c +++ b/arch/sandbox/lib/bootm.c @@ -89,3 +89,8 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size, return 1; } + +bool booti_is_valid(const void *img) +{ + return false; +} diff --git a/boot/image-board.c b/boot/image-board.c index addccf87c80..07931c64198 100644 --- a/boot/image-board.c +++ b/boot/image-board.c @@ -250,6 +250,9 @@ enum image_fmt_t genimg_get_format(const void *img_addr) if (IS_ENABLED(CONFIG_ANDROID_BOOT_IMAGE) && is_android_boot_image_header(img_addr)) return IMAGE_FORMAT_ANDROID; + if (IS_ENABLED(CONFIG_CMD_BOOTI) && + booti_is_valid(img_addr)) + return IMAGE_FORMAT_BOOTI; return IMAGE_FORMAT_INVALID; } @@ -420,6 +423,8 @@ static int select_ramdisk(struct bootm_headers *images, const char *select, u8 a done = true; } break; + case IMAGE_FORMAT_BOOTI: + break; case IMAGE_FORMAT_INVALID: break; } diff --git a/include/image.h b/include/image.h index dc1a7c307cc..f8f2c887a4b 100644 --- a/include/image.h +++ b/include/image.h @@ -603,6 +603,7 @@ enum image_fmt_t { IMAGE_FORMAT_LEGACY, /* legacy image_header based format */ IMAGE_FORMAT_FIT, /* new, libfdt based format */ IMAGE_FORMAT_ANDROID, /* Android boot image */ + IMAGE_FORMAT_BOOTI, /* Arm64/RISC-V boot image */ }; /** @@ -649,6 +650,14 @@ enum image_fmt_t genimg_get_format(const void *img_addr); int genimg_has_config(struct bootm_headers *images); +/** + * booti_is_valid() - Check if an image appears to be an Arm64 image + * + * @img: Pointer to image + * Return: true if the image has the Arm64 magic + */ +bool booti_is_valid(const void *img); + /** * boot_get_fpga() - Locate the FPGA image * From d6bb0ea535e4384ed1975ee9c755488f5036a79e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:10 -0700 Subject: [PATCH 16/29] boot: Support booti format in bootm At present the booti format is handled separately, in its own command. Provide a way to boot uncompressed booti images within the bootm code, so that eventually we can boot these images without CONFIG_CMDLINE Update bootm_init() to attach the images for all formats which use them. Add some debugging while we are here. Signed-off-by: Simon Glass --- boot/bootm.c | 42 +++++++++++++++++++++++++++++++++++++++++- include/image.h | 2 +- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/boot/bootm.c b/boot/bootm.c index c719a50ef9a..272623c9258 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -227,6 +227,12 @@ static int boot_get_kernel(const char *addr_fit, struct bootm_headers *images, break; } #endif + case IMAGE_FORMAT_BOOTI: + if (IS_ENABLED(CONFIG_CMD_BOOTI)) { + *os_data = img_addr; + break; + } + fallthrough; default: bootstage_error(BOOTSTAGE_ID_CHECK_IMAGETYPE); return -EPROTOTYPE; @@ -286,6 +292,24 @@ static int bootm_pre_load(const char *addr_str) return ret; } +static int found_booti_os(enum image_comp_t comp) +{ + images.os.load = images.os.image_start; + images.os.type = IH_TYPE_KERNEL; + images.os.os = IH_OS_LINUX; + images.os.comp = comp; + if (IS_ENABLED(CONFIG_RISCV_SMODE)) + images.os.arch = IH_ARCH_RISCV; + else if (IS_ENABLED(CONFIG_ARM64)) + images.os.arch = IH_ARCH_ARM64; + + log_debug("load %lx start %lx len %lx ep %lx os %x comp %x\n", + images.os.load, images.os.image_start, images.os.image_len, + images.ep, images.os.os, images.os.comp); + + return 0; +} + /** * bootm_find_os(): Find the OS to boot * @@ -390,6 +414,14 @@ static int bootm_find_os(const char *cmd_name, const char *addr_fit) } break; #endif + case IMAGE_FORMAT_BOOTI: + if (IS_ENABLED(CONFIG_CMD_BOOTI)) { + if (found_booti_os(IH_COMP_NONE)) + return 1; + ep_found = true; + break; + } + fallthrough; default: puts("ERROR: unknown image format type!\n"); return 1; @@ -541,6 +573,7 @@ int bootm_find_images(ulong img_addr, const char *conf_ramdisk, static int bootm_find_other(ulong img_addr, const char *conf_ramdisk, const char *conf_fdt) { + log_debug("find_other type %x os %x\n", images.os.type, images.os.os); if ((images.os.type == IH_TYPE_KERNEL || images.os.type == IH_TYPE_KERNEL_NOLOAD || images.os.type == IH_TYPE_MULTI) && @@ -629,6 +662,8 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress) debug("Allocated %lx bytes at %lx for kernel (size %lx) decompression\n", req_size, load, image_len); } + log_debug("load_os load %lx image_start %lx image_len %lx\n", load, + image_start, image_len); load_buf = map_sysmem(load, 0); image_buf = map_sysmem(os.image_start, image_len); @@ -1110,6 +1145,10 @@ int boot_run(struct bootm_info *bmi, const char *cmd, int extra_states) states |= BOOTM_STATE_RAMDISK; states |= extra_states; + log_debug("cmd '%s' states %x addr_img '%s' conf_ramdisk '%s' conf_fdt '%s' images %p\n", + cmd, states, bmi->addr_img, bmi->conf_ramdisk, bmi->conf_fdt, + bmi->images); + return bootm_run_states(bmi, states); } @@ -1166,7 +1205,8 @@ void bootm_init(struct bootm_info *bmi) { memset(bmi, '\0', sizeof(struct bootm_info)); bmi->boot_progress = true; - if (IS_ENABLED(CONFIG_CMD_BOOTM)) + if (IS_ENABLED(CONFIG_CMD_BOOTM) || IS_ENABLED(CONFIG_CMD_BOOTZ) || + IS_ENABLED(CONFIG_CMD_BOOTI) || IS_ENABLED(CONFIG_PXE_UTILS)) bmi->images = &images; } diff --git a/include/image.h b/include/image.h index f8f2c887a4b..5b9bd6a9649 100644 --- a/include/image.h +++ b/include/image.h @@ -244,7 +244,7 @@ enum image_type_t { * New IDs *MUST* be appended at the end of the list and *NEVER* * inserted for backward compatibility. */ -enum { +enum image_comp_t { IH_COMP_NONE = 0, /* No Compression Used */ IH_COMP_GZIP, /* gzip Compression Used */ IH_COMP_BZIP2, /* bzip2 Compression Used */ From ecd50bb4643c9052e5f8b6171ab6c3905ed0ca70 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:11 -0700 Subject: [PATCH 17/29] boot: Support compressed booti images in bootm A compressed booti image relies on the compression-format's header at the start to indicate which compression algorithm is used. We don't support this elsewhere in U-Boot, so assume that a compressed file is always a booti file. Once it is compressed, a check is made to make sure that it actually is. Simplify the implementation by adding a new function which returns the booti image-type if compression is detected. Signed-off-by: Simon Glass --- boot/bootm.c | 37 ++++++++++++++++++++++++++++++------- boot/image-board.c | 13 ++++++++++++- include/image.h | 11 +++++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/boot/bootm.c b/boot/bootm.c index 272623c9258..8a1aac7515f 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -146,7 +146,7 @@ static int boot_get_kernel(const char *addr_fit, struct bootm_headers *images, /* check image type, for FIT images get FIT kernel node */ *os_data = *os_len = 0; buf = map_sysmem(img_addr, 0); - switch (genimg_get_format(buf)) { + switch (genimg_get_format_comp(buf)) { #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT) case IMAGE_FORMAT_LEGACY: printf("## Booting kernel from Legacy Image at %08lx ...\n", @@ -228,11 +228,8 @@ static int boot_get_kernel(const char *addr_fit, struct bootm_headers *images, } #endif case IMAGE_FORMAT_BOOTI: - if (IS_ENABLED(CONFIG_CMD_BOOTI)) { - *os_data = img_addr; - break; - } - fallthrough; + *os_data = img_addr; + break; default: bootstage_error(BOOTSTAGE_ID_CHECK_IMAGETYPE); return -EPROTOTYPE; @@ -306,6 +303,17 @@ static int found_booti_os(enum image_comp_t comp) log_debug("load %lx start %lx len %lx ep %lx os %x comp %x\n", images.os.load, images.os.image_start, images.os.image_len, images.ep, images.os.os, images.os.comp); + if (comp != IH_COMP_NONE) { + images.os.load = env_get_hex("kernel_comp_addr_r", 0); + images.os.image_len = env_get_ulong("kernel_comp_size", 16, 0); + if (!images.os.load || !images.os.image_len) { + puts("kernel_comp_addr_r or kernel_comp_size is not provided!\n"); + return -ENOTSUPP; + } + if (lmb_reserve(images.os.load, images.os.image_len, LMB_NONE) + < 0) + return -EXDEV; + } return 0; } @@ -423,6 +431,19 @@ static int bootm_find_os(const char *cmd_name, const char *addr_fit) } fallthrough; default: + /* any compressed image is probably a booti image */ + if (IS_ENABLED(CONFIG_CMD_BOOTI)) { + int comp; + + comp = image_decomp_type(os_hdr, 2); + if (comp != IH_COMP_NONE) { + if (found_booti_os(comp)) + return 1; + ep_found = true; + } + break; + } + puts("ERROR: unknown image format type!\n"); return 1; } @@ -1166,7 +1187,9 @@ int bootz_run(struct bootm_info *bmi) int booti_run(struct bootm_info *bmi) { - return boot_run(bmi, "booti", 0); + return boot_run(bmi, "booti", BOOTM_STATE_START | BOOTM_STATE_FINDOS | + BOOTM_STATE_PRE_LOAD | BOOTM_STATE_FINDOTHER | + BOOTM_STATE_LOADOS); } int bootm_boot_start(ulong addr, const char *cmdline) diff --git a/boot/image-board.c b/boot/image-board.c index 07931c64198..a2bafba7ae1 100644 --- a/boot/image-board.c +++ b/boot/image-board.c @@ -257,6 +257,17 @@ enum image_fmt_t genimg_get_format(const void *img_addr) return IMAGE_FORMAT_INVALID; } +enum image_fmt_t genimg_get_format_comp(const void *img_addr) +{ + enum image_fmt_t fmt = genimg_get_format(img_addr); + + if (IS_ENABLED(CONFIG_CMD_BOOTI) && fmt == IMAGE_FORMAT_INVALID && + image_decomp_type(img_addr, 2) != IH_COMP_NONE) + fmt = IMAGE_FORMAT_BOOTI; + + return fmt; +} + /** * fit_has_config - check if there is a valid FIT configuration * @images: pointer to the bootm command headers structure @@ -353,7 +364,7 @@ static int select_ramdisk(struct bootm_headers *images, const char *select, u8 a * check image type, for FIT images get FIT node. */ buf = map_sysmem(rd_addr, 0); - switch (genimg_get_format(buf)) { + switch (genimg_get_format_comp(buf)) { case IMAGE_FORMAT_LEGACY: if (CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)) { const struct legacy_img_hdr *rd_hdr; diff --git a/include/image.h b/include/image.h index 5b9bd6a9649..2455baa6667 100644 --- a/include/image.h +++ b/include/image.h @@ -648,6 +648,17 @@ ulong genimg_get_kernel_addr(char * const img_addr); */ enum image_fmt_t genimg_get_format(const void *img_addr); +/** + * genimg_get_format_comp() - Like genimg_get_format() but adds compressed booti + * + * If a compressed file is detected (with image_decomp_type()) and + * CONFIG_CMD_BOOTI is enabled, then this returns IMAGE_FORMAT_BOOTI + * + * @img_addr: image start address + * Return: image format type or IMAGE_FORMAT_INVALID if no image is present + */ +enum image_fmt_t genimg_get_format_comp(const void *img_addr); + int genimg_has_config(struct bootm_headers *images); /** From b13408021d361fbae1c254307f139ad1e6def3d2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:12 -0700 Subject: [PATCH 18/29] boot: pxe: Use bootm_...() functions where possible Rather than building a command line for each operation, use the functions provided by the bootm API. Make sure that the bootm functions are available if pxe_utils is used. Since SYS_BOOTM_LEN is not present for the tools-only build, adjust the code to handle that. Signed-off-by: Simon Glass Reviewed-by: Quentin Schulz --- boot/Makefile | 2 +- boot/pxe_utils.c | 43 ++++++++++++++++++++----------------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/boot/Makefile b/boot/Makefile index 34bac26c4e2..f1e4444aa0a 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o bootm_os.o obj-$(CONFIG_CMD_BOOTZ) += bootm.o bootm_os.o obj-$(CONFIG_CMD_BOOTI) += bootm.o bootm_os.o -obj-$(CONFIG_PXE_UTILS) += pxe_utils.o +obj-$(CONFIG_PXE_UTILS) += bootm.o pxe_utils.o endif diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 2ada5c4aaac..bbb6ff203b6 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -7,6 +7,7 @@ #define LOG_CATEGORY LOGC_BOOT #include +#include #include #include #include @@ -461,7 +462,7 @@ skip_overlay: * Scenario 4: fdt blob is not available. */ static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label, - char *kernel_addr, char **fdt_argp) + char *kernel_addr, const char **fdt_argp) { /* For FIT, the label can be identical to kernel one */ if (label->fdt && !strcmp(label->kernel_label, label->fdt)) { @@ -584,72 +585,66 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, char *kernel_addr, char *initrd_addr_str, char *initrd_filesize, char *initrd_str) { - char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL }; + struct bootm_info bmi; ulong kernel_addr_r; - int bootm_argc = 2; int zboot_argc = 3; void *buf; int ret; - bootm_argv[3] = env_get("fdt_addr_r"); + bootm_init(&bmi); - ret = label_process_fdt(ctx, label, kernel_addr, &bootm_argv[3]); + bmi.conf_fdt = env_get("fdt_addr_r"); + + ret = label_process_fdt(ctx, label, kernel_addr, &bmi.conf_fdt); if (ret) return ret; - bootm_argv[1] = kernel_addr; + bmi.addr_img = kernel_addr; zboot_argv[1] = kernel_addr; if (initrd_addr_str) { - bootm_argv[2] = initrd_str; - bootm_argc = 3; + bmi.conf_ramdisk = initrd_str; zboot_argv[3] = initrd_addr_str; zboot_argv[4] = initrd_filesize; zboot_argc = 5; } - if (!bootm_argv[3]) { + if (!bmi.conf_fdt) { if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { if (strcmp("-", label->fdt)) - bootm_argv[3] = env_get("fdt_addr"); + bmi.conf_fdt = env_get("fdt_addr"); } else { - bootm_argv[3] = env_get("fdt_addr"); + bmi.conf_fdt = env_get("fdt_addr"); } } kernel_addr_r = genimg_get_kernel_addr(kernel_addr); buf = map_sysmem(kernel_addr_r, 0); - if (!bootm_argv[3] && genimg_get_format(buf) != IMAGE_FORMAT_FIT) { + if (!bmi.conf_fdt && genimg_get_format(buf) != IMAGE_FORMAT_FIT) { if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { if (strcmp("-", label->fdt)) - bootm_argv[3] = env_get("fdtcontroladdr"); + bmi.conf_fdt = env_get("fdtcontroladdr"); } else { - bootm_argv[3] = env_get("fdtcontroladdr"); + bmi.conf_fdt = env_get("fdtcontroladdr"); } } - if (bootm_argv[3]) { - if (!bootm_argv[2]) - bootm_argv[2] = "-"; - bootm_argc = 4; - } - /* Try bootm for legacy and FIT format image */ if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID && IS_ENABLED(CONFIG_CMD_BOOTM)) { log_debug("using bootm\n"); - do_bootm(ctx->cmdtp, 0, bootm_argc, bootm_argv); + ret = bootm_run(&bmi); /* Try booting an AArch64 Linux kernel image */ } else if (IS_ENABLED(CONFIG_CMD_BOOTI)) { log_debug("using booti\n"); - do_booti(ctx->cmdtp, 0, bootm_argc, bootm_argv); + ret = booti_run(&bmi); /* Try booting a Image */ } else if (IS_ENABLED(CONFIG_CMD_BOOTZ)) { log_debug("using bootz\n"); - do_bootz(ctx->cmdtp, 0, bootm_argc, bootm_argv); + ret = bootz_run(&bmi); /* Try booting an x86_64 Linux kernel image */ } else if (IS_ENABLED(CONFIG_CMD_ZBOOT)) { log_debug("using zboot\n"); @@ -657,6 +652,8 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, } unmap_sysmem(buf); + if (ret) + return ret; return 0; } From feb8d7fd749413e889ba2c396654f473ba32034d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:13 -0700 Subject: [PATCH 19/29] pxe_utils: Simplify default fdt in label_run_boot() Tidy up this code a little to avoid two calls to env_get() for both fdt_addr and fdtcontroladdr Signed-off-by: Simon Glass Suggested-by: Quentin Schulz --- boot/pxe_utils.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index bbb6ff203b6..37306f37009 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -612,24 +612,18 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, } if (!bmi.conf_fdt) { - if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { - if (strcmp("-", label->fdt)) - bmi.conf_fdt = env_get("fdt_addr"); - } else { + if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || + strcmp("-", label->fdt)) bmi.conf_fdt = env_get("fdt_addr"); - } } kernel_addr_r = genimg_get_kernel_addr(kernel_addr); buf = map_sysmem(kernel_addr_r, 0); if (!bmi.conf_fdt && genimg_get_format(buf) != IMAGE_FORMAT_FIT) { - if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { - if (strcmp("-", label->fdt)) - bmi.conf_fdt = env_get("fdtcontroladdr"); - } else { + if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || + strcmp("-", label->fdt)) bmi.conf_fdt = env_get("fdtcontroladdr"); - } } /* Try bootm for legacy and FIT format image */ From e2e87b840162ddf4ec8df3f235be98a74a964509 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:14 -0700 Subject: [PATCH 20/29] boot: pxe: Refactor label_run_boot() to avoid cmdline Adjust the remaining call in this function to use the bootm API. This will allow PXE to work without the command line. Signed-off-by: Simon Glass --- arch/x86/lib/zimage.c | 29 ++++++++++++++++++++--------- boot/pxe_utils.c | 14 ++++++-------- include/bootm.h | 9 +++++++++ 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 145ba0b8ea0..ba7a008fec7 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -432,6 +432,23 @@ int zboot_go(struct bootm_info *bmi) return ret; } +int zboot_run(struct bootm_info *bmi) +{ + int ret; + + ret = zboot_load(bmi); + if (ret) + return log_msg_ret("ld", ret); + ret = zboot_setup(bmi); + if (ret) + return log_msg_ret("set", ret); + ret = zboot_go(bmi); + if (ret) + return log_msg_ret("go", ret); + + return -EFAULT; +} + int zboot_run_args(ulong addr, ulong size, ulong initrd, ulong initrd_size, ulong base, char *cmdline) { @@ -440,17 +457,11 @@ int zboot_run_args(ulong addr, ulong size, ulong initrd, ulong initrd_size, bootm_init(&bmi); zboot_start(&bmi, addr, size, initrd, initrd_size, base, cmdline); - ret = zboot_load(&bmi); + ret = zboot_run(&bmi); if (ret) - return log_msg_ret("ld", ret); - ret = zboot_setup(&bmi); - if (ret) - return log_msg_ret("set", ret); - ret = zboot_go(&bmi); - if (ret) - return log_msg_ret("go", ret); + return log_msg_ret("zra", ret); - return -EFAULT; + return 0; } static void print_num(const char *name, ulong value) diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 37306f37009..c606da9e96b 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -585,10 +585,8 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, char *kernel_addr, char *initrd_addr_str, char *initrd_filesize, char *initrd_str) { - char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL }; struct bootm_info bmi; ulong kernel_addr_r; - int zboot_argc = 3; void *buf; int ret; @@ -601,14 +599,14 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, return ret; bmi.addr_img = kernel_addr; - zboot_argv[1] = kernel_addr; + bootm_x86_set(&bmi, bzimage_addr, hextoul(kernel_addr, NULL)); if (initrd_addr_str) { bmi.conf_ramdisk = initrd_str; - - zboot_argv[3] = initrd_addr_str; - zboot_argv[4] = initrd_filesize; - zboot_argc = 5; + bootm_x86_set(&bmi, initrd_addr, + hextoul(initrd_addr_str, NULL)); + bootm_x86_set(&bmi, initrd_size, + hextoul(initrd_filesize, NULL)); } if (!bmi.conf_fdt) { @@ -642,7 +640,7 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, /* Try booting an x86_64 Linux kernel image */ } else if (IS_ENABLED(CONFIG_CMD_ZBOOT)) { log_debug("using zboot\n"); - do_zboot_parent(ctx->cmdtp, 0, zboot_argc, zboot_argv, NULL); + ret = zboot_run(&bmi); } unmap_sysmem(buf); diff --git a/include/bootm.h b/include/bootm.h index d174f18ac18..465577a66f5 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -315,6 +315,15 @@ int bootm_process_cmdline(char *buf, int maxlen, int flags); */ int bootm_process_cmdline_env(int flags); +/** + * zboot_run() - Run through the various steps to boot a zimage + * + * @bmi: Bootm information, with bzimage_size, initrd_addr, initrd_size and + * cmdline set up. If base_ptr is 0, then bzimage_addr must be set to the start + * of the bzImage. Otherwise base_ptr and load_address must be provided. + */ +int zboot_run(struct bootm_info *bmi); + /** * zboot_run_args() - Run through the various steps to boot a zimage * From 2c04afbc957d18e61813315a0694db903754a280 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:15 -0700 Subject: [PATCH 21/29] net: Keep the bootstage functions together Move the bootstage_mark() function just before net_loop(), so that the IPv6 code is not in the way. Signed-off-by: Simon Glass --- cmd/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/net.c b/cmd/net.c index 79525f73a51..deebd5b710f 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -413,8 +413,6 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, return CMD_RET_USAGE; } - bootstage_mark(BOOTSTAGE_ID_NET_START); - if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) { char *s, *e; size_t len; @@ -428,6 +426,8 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } + bootstage_mark(BOOTSTAGE_ID_NET_START); + size = net_loop(proto); if (size < 0) { bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); From 3ccbc10cd9e3b28d67fe5008943a648b870db1e6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:16 -0700 Subject: [PATCH 22/29] net: Tidy up the comments to parse_args() This function is a bit vague as to what it does. Expand the comment a little, to specify which args are provided and which variables are updated. Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- cmd/net.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cmd/net.c b/cmd/net.c index deebd5b710f..89a4d9b38d4 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -313,9 +313,18 @@ static int parse_addr_size(char * const argv[]) /** * parse_args() - parse command line arguments * + * Sets: + * + * - net_boot_file_name_explicit to true if a filename was specified + * - net_boot_file_name to that filename, if specified, else the value of the + * 'bootfile' environment variable + * - image_load_addr if a load address was provided + * - image_save_addr and image_save_size, if proto == TFTPPUT + * * @proto: command prototype - * @argc: number of arguments - * @argv: command line arguments + * @argc: number of arguments, include the command, which has already been + * parsed + * @argv: command line arguments, with argv[0] being the command * Return: 0 on success */ static int parse_args(enum proto_t proto, int argc, char *const argv[]) From f1ece5d86e5577ae9bb3325d65ed7003f3cbaf9e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:17 -0700 Subject: [PATCH 23/29] net: Simplify parse_args() This function repeats the same code in a few places, namely setting net_boot_file_name_explicit and copying of the filename to net_boot_file_name Move these two operations to the caller, with just the filename (or NULL) returned by parse_args() This makes things a little easier to follow. Signed-off-by: Simon Glass --- cmd/net.c | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/cmd/net.c b/cmd/net.c index 89a4d9b38d4..cc7d14eb082 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -314,10 +314,6 @@ static int parse_addr_size(char * const argv[]) * parse_args() - parse command line arguments * * Sets: - * - * - net_boot_file_name_explicit to true if a filename was specified - * - net_boot_file_name to that filename, if specified, else the value of the - * 'bootfile' environment variable * - image_load_addr if a load address was provided * - image_save_addr and image_save_size, if proto == TFTPPUT * @@ -325,21 +321,20 @@ static int parse_addr_size(char * const argv[]) * @argc: number of arguments, include the command, which has already been * parsed * @argv: command line arguments, with argv[0] being the command + * @fnamep: set to the filename, if provided, else NULL * Return: 0 on success */ -static int parse_args(enum proto_t proto, int argc, char *const argv[]) +static int parse_args(enum proto_t proto, int argc, char *const argv[], + const char **fnamep) { ulong addr; char *end; + *fnamep = NULL; switch (argc) { case 1: if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) return 1; - - /* refresh bootfile name from env */ - copy_filename(net_boot_file_name, env_get("bootfile"), - sizeof(net_boot_file_name)); break; case 2: @@ -352,16 +347,10 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[]) * mis-interpreted as a valid number. */ addr = hextoul(argv[1], &end); - if (end == (argv[1] + strlen(argv[1]))) { + if (end == (argv[1] + strlen(argv[1]))) image_load_addr = addr; - /* refresh bootfile name from env */ - copy_filename(net_boot_file_name, env_get("bootfile"), - sizeof(net_boot_file_name)); - } else { - net_boot_file_name_explicit = true; - copy_filename(net_boot_file_name, argv[1], - sizeof(net_boot_file_name)); - } + else + *fnamep = argv[1]; break; case 3: @@ -370,9 +359,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[]) return 1; } else { image_load_addr = hextoul(argv[1], NULL); - net_boot_file_name_explicit = true; - copy_filename(net_boot_file_name, argv[2], - sizeof(net_boot_file_name)); + *fnamep = argv[2]; } break; @@ -380,20 +367,20 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[]) case 4: if (parse_addr_size(argv)) return 1; - net_boot_file_name_explicit = true; - copy_filename(net_boot_file_name, argv[3], - sizeof(net_boot_file_name)); + *fnamep = argv[3]; break; #endif default: return 1; } + return 0; } static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { + const char *fname; char *s; int rcode = 0; int size; @@ -417,11 +404,19 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } - if (parse_args(proto, argc, argv)) { + if (parse_args(proto, argc, argv, &fname)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } + if (fname) { + net_boot_file_name_explicit = true; + } else { + net_boot_file_name_explicit = false; + fname = env_get("bootfile"); + } + copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); + if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) { char *s, *e; size_t len; From 4b6070e056fc2c11b7621c32151f95f7a045ac01 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:18 -0700 Subject: [PATCH 24/29] net: Return the load address from parse_args() Rather than updating the global, update the value of a parameter, so the action of the function is simpler. Signed-off-by: Simon Glass --- cmd/net.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmd/net.c b/cmd/net.c index cc7d14eb082..d15d344cb54 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -314,7 +314,6 @@ static int parse_addr_size(char * const argv[]) * parse_args() - parse command line arguments * * Sets: - * - image_load_addr if a load address was provided * - image_save_addr and image_save_size, if proto == TFTPPUT * * @proto: command prototype @@ -322,10 +321,12 @@ static int parse_addr_size(char * const argv[]) * parsed * @argv: command line arguments, with argv[0] being the command * @fnamep: set to the filename, if provided, else NULL + * @addrp: returns the load address, if any is provided, else it is left + * unchanged * Return: 0 on success */ static int parse_args(enum proto_t proto, int argc, char *const argv[], - const char **fnamep) + const char **fnamep, ulong *addrp) { ulong addr; char *end; @@ -348,7 +349,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], */ addr = hextoul(argv[1], &end); if (end == (argv[1] + strlen(argv[1]))) - image_load_addr = addr; + *addrp = addr; else *fnamep = argv[1]; break; @@ -358,7 +359,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], if (parse_addr_size(argv)) return 1; } else { - image_load_addr = hextoul(argv[1], NULL); + *addrp = hextoul(argv[1], NULL); *fnamep = argv[2]; } break; @@ -404,7 +405,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } - if (parse_args(proto, argc, argv, &fname)) { + if (parse_args(proto, argc, argv, &fname, &image_load_addr)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } From f60421204816bd0aa40e9e43c18d4bc5861d3521 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:19 -0700 Subject: [PATCH 25/29] net: Return the address and size from parse_addr_size() Rather than updating the global, update the value of some parameters, so the action of the function is simpler. Signed-off-by: Simon Glass --- cmd/net.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/cmd/net.c b/cmd/net.c index d15d344cb54..cc968e9460f 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -297,13 +297,15 @@ static void netboot_update_env(void) /** * parse_addr_size() - parse address and size arguments for tftpput * - * @argv: command line arguments + * @argv: command line arguments (argv[1] and argv[2] must be valid) + * @addrp: returns the address, on success + * @sizep: returns the size, on success * Return: 0 on success */ -static int parse_addr_size(char * const argv[]) +static int parse_addr_size(char * const argv[], ulong *addrp, ulong *sizep) { - if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 || - strict_strtoul(argv[2], 16, &image_save_size) < 0) { + if (strict_strtoul(argv[1], 16, addrp) < 0 || + strict_strtoul(argv[2], 16, sizep) < 0) { printf("Invalid address/size\n"); return CMD_RET_USAGE; } @@ -356,7 +358,8 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], case 3: if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { - if (parse_addr_size(argv)) + if (parse_addr_size(argv, &image_save_addr, + &image_save_size)) return 1; } else { *addrp = hextoul(argv[1], NULL); @@ -366,7 +369,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], #ifdef CONFIG_CMD_TFTPPUT case 4: - if (parse_addr_size(argv)) + if (parse_addr_size(argv, &image_save_addr, &image_save_size)) return 1; *fnamep = argv[3]; break; From 25d51d3c798f6e256daa628bb2a9fcc36fde0382 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:20 -0700 Subject: [PATCH 26/29] net: Return the size from parse_args() Rather than setting global variables, return the size, if provided. For tftput, use the addr argument to store the save address, to avoid adding yet another parameter. Signed-off-by: Simon Glass --- cmd/net.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/cmd/net.c b/cmd/net.c index cc968e9460f..572fa75a72f 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -323,12 +323,14 @@ static int parse_addr_size(char * const argv[], ulong *addrp, ulong *sizep) * parsed * @argv: command line arguments, with argv[0] being the command * @fnamep: set to the filename, if provided, else NULL - * @addrp: returns the load address, if any is provided, else it is left + * @addrp: returns the load/save address, if any is provided, else it is + * left unchanged + * @sizep: returns the save size, if any is provided, else it is left * unchanged * Return: 0 on success */ static int parse_args(enum proto_t proto, int argc, char *const argv[], - const char **fnamep, ulong *addrp) + const char **fnamep, ulong *addrp, ulong *sizep) { ulong addr; char *end; @@ -358,8 +360,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], case 3: if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { - if (parse_addr_size(argv, &image_save_addr, - &image_save_size)) + if (parse_addr_size(argv, addrp, sizep)) return 1; } else { *addrp = hextoul(argv[1], NULL); @@ -369,7 +370,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], #ifdef CONFIG_CMD_TFTPPUT case 4: - if (parse_addr_size(argv, &image_save_addr, &image_save_size)) + if (parse_addr_size(argv, addrp, sizep)) return 1; *fnamep = argv[3]; break; @@ -385,6 +386,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { const char *fname; + ulong addr; char *s; int rcode = 0; int size; @@ -392,10 +394,10 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, net_boot_file_name_explicit = false; *net_boot_file_name = '\0'; - /* pre-set image_load_addr */ + /* pre-set addr */ s = env_get("loadaddr"); if (s != NULL) - image_load_addr = hextoul(s, NULL); + addr = hextoul(s, NULL); if (IS_ENABLED(CONFIG_IPV6)) { use_ip6 = false; @@ -408,10 +410,14 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } - if (parse_args(proto, argc, argv, &fname, &image_load_addr)) { + if (parse_args(proto, argc, argv, &fname, &addr, &image_save_size)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) + image_save_addr = addr; + else + image_load_addr = addr; if (fname) { net_boot_file_name_explicit = true; From bfffdfaaf6f492865100197a5b141482799afc09 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:21 -0700 Subject: [PATCH 27/29] net: Refactor part of netboot_common() into a function Move the core code for starting an netboot operation into a separate function, so that we can (with additional work) move towards calling it from outside the file. Signed-off-by: Simon Glass --- cmd/net.c | 62 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/cmd/net.c b/cmd/net.c index 572fa75a72f..f980448e0ef 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -382,11 +382,50 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], return 0; } +static int netboot_run_(enum proto_t proto, ulong addr, const char *fname, + ulong size, bool fname_explicit, bool ipv6) +{ + int ret; + + bootstage_mark(BOOTSTAGE_ID_NET_START); + + /* + * For now we use the global variables as that is the only way to + * control the network stack. At some point, perhaps, the state could be + * in a struct + */ + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) + image_save_addr = addr; + else + image_load_addr = addr; + + net_boot_file_name_explicit = fname_explicit; + copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); + if (IS_ENABLED(CONFIG_IPV6)) + use_ip6 = ipv6; + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { + image_save_addr = addr; + image_save_size = size; + } else { + image_load_addr = addr; + } + + ret = net_loop(proto); + if (ret < 0) { + bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); + return ret; + } + bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); + + return 0; +} + static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { + ulong addr, save_size; + bool fname_explicit; const char *fname; - ulong addr; char *s; int rcode = 0; int size; @@ -410,22 +449,17 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } - if (parse_args(proto, argc, argv, &fname, &addr, &image_save_size)) { + if (parse_args(proto, argc, argv, &fname, &addr, &save_size)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } - if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) - image_save_addr = addr; - else - image_load_addr = addr; if (fname) { - net_boot_file_name_explicit = true; + fname_explicit = true; } else { - net_boot_file_name_explicit = false; + fname_explicit = false; fname = env_get("bootfile"); } - copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) { char *s, *e; @@ -440,14 +474,10 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } - bootstage_mark(BOOTSTAGE_ID_NET_START); - - size = net_loop(proto); - if (size < 0) { - bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); + size = netboot_run_(proto, addr, fname, save_size, fname_explicit, + use_ip6); + if (size < 0) return CMD_RET_FAILURE; - } - bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); /* net_loop ok, update environment */ netboot_update_env(); From f278f0cb4996398720328ce33e057678f6ea4109 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:22 -0700 Subject: [PATCH 28/29] net: Drop #ifdef in parse_args() Use IS_ENABLED() to avoid an extra build path. Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- cmd/net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/net.c b/cmd/net.c index f980448e0ef..6d1c6374f76 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -368,13 +368,13 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], } break; -#ifdef CONFIG_CMD_TFTPPUT case 4: - if (parse_addr_size(argv, addrp, sizep)) - return 1; - *fnamep = argv[3]; - break; -#endif + if (IS_ENABLED(CONFIG_CMD_TFTPPUT)) { + if (parse_addr_size(argv, addrp, sizep)) + return 1; + *fnamep = argv[3]; + break; + } default: return 1; } From 0f094b8b146679c3980cd2febde4e902bbc4405d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:23 -0700 Subject: [PATCH 29/29] net: Provide a function to run network operations Add a new netboot_run() function which can be used for simple network operations, such as loading a file. Put the implementation in an internal function, used by the existing code. Place this function into the net/ code, so that it does not need the command line to be available. Document which network operations are supported, i.e. a limited subset, for now. For the one board which uses lwip, it is not quite clear how to avoid using the cmdline interface. This will need some discussion. Signed-off-by: Simon Glass --- cmd/net.c | 40 +--------------------------------------- include/net-common.h | 30 ++++++++++++++++++++++++++++++ net/net.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 39 deletions(-) diff --git a/cmd/net.c b/cmd/net.c index 6d1c6374f76..8f33c9f55d5 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -382,44 +382,6 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], return 0; } -static int netboot_run_(enum proto_t proto, ulong addr, const char *fname, - ulong size, bool fname_explicit, bool ipv6) -{ - int ret; - - bootstage_mark(BOOTSTAGE_ID_NET_START); - - /* - * For now we use the global variables as that is the only way to - * control the network stack. At some point, perhaps, the state could be - * in a struct - */ - if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) - image_save_addr = addr; - else - image_load_addr = addr; - - net_boot_file_name_explicit = fname_explicit; - copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); - if (IS_ENABLED(CONFIG_IPV6)) - use_ip6 = ipv6; - if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { - image_save_addr = addr; - image_save_size = size; - } else { - image_load_addr = addr; - } - - ret = net_loop(proto); - if (ret < 0) { - bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); - return ret; - } - bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); - - return 0; -} - static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { @@ -475,7 +437,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } size = netboot_run_(proto, addr, fname, save_size, fname_explicit, - use_ip6); + IS_ENABLED(CONFIG_IPV6) && use_ip6); if (size < 0) return CMD_RET_FAILURE; diff --git a/include/net-common.h b/include/net-common.h index 29d31f37263..210042fc337 100644 --- a/include/net-common.h +++ b/include/net-common.h @@ -474,6 +474,36 @@ int net_init(void); enum proto_t; int net_loop(enum proto_t protocol); +/* internal function: do not use! */ +int netboot_run_(enum proto_t proto, ulong addr, const char *fname, ulong size, + bool fname_explicit, bool ipv6); + +/** + * netboot_run() - Run a network operation + * + * The following proto values are NOT supported: + * PING, since net_ping_ip cannot be set + * NETCONS, since its parameters cannot bet set + * RS, since first_call cannot be set, along with perhaps other things + * UDP, since udp_ops cannot be set + * DNS, since net_dns_resolve and net_dns_env_var cannot be set + * WGET, since DNS must be done first and that is not supported + * DHCP6, since the required parameters cannot be passed in + * + * To support one of these, either add the required arguments or perhaps a + * separate function and a struct to hold the information. + * + * @proto: Operation to run: TFTPGET, FASTBOOT_UDP, FASTBOOT_TCP, BOOTP, + * TFTPPUT, RARP, NFS, DHCP + * @addr: Load/save address + * @fname: Filename + * @size: Save size (not used for TFTPGET) + * @ipv6: true to use IPv6, false to use IPv4 + * Return 0 on success, else -ve error code + */ +int netboot_run(enum proto_t proto, ulong addr, const char *fname, ulong size, + bool ipv6); + /** * dhcp_run() - Run DHCP on the current ethernet device * diff --git a/net/net.c b/net/net.c index 1828f1cca36..ef97377cdec 100644 --- a/net/net.c +++ b/net/net.c @@ -775,6 +775,50 @@ done: return ret; } +int netboot_run_(enum proto_t proto, ulong addr, const char *fname, ulong size, + bool fname_explicit, bool ipv6) +{ + int ret; + + bootstage_mark(BOOTSTAGE_ID_NET_START); + + /* + * For now we use the global variables as that is the only way to + * control the network stack. At some point, perhaps, the state could be + * in a struct + */ + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) + image_save_addr = addr; + else + image_load_addr = addr; + + net_boot_file_name_explicit = fname_explicit; + copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); + if (IS_ENABLED(CONFIG_IPV6)) + use_ip6 = ipv6; + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { + image_save_addr = addr; + image_save_size = size; + } else { + image_load_addr = addr; + } + + ret = net_loop(proto); + if (ret < 0) { + bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); + return ret; + } + bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); + + return 0; +} + +int netboot_run(enum proto_t proto, ulong addr, const char *fname, ulong size, + bool ipv6) +{ + return netboot_run_(proto, addr, fname, size, true, ipv6); +} + /**********************************************************************/ static void start_again_timeout_handler(void)