[PATCH 00/39] pxe: Support read_all() for extlinux and PXE

This series implements read_all() so that it is possible to read all the files relating to a bootflow, make adjustments and then boot.
Unfortunately quite a few things stand in the way, so this series finishes off several pending items: zboot without CONFIG_CMDLINE, required support in pxe_utils and the differing code in the extlinux and PXE bootmeths. There is very little new code, but quite a lot of refactoring.
The bootm, booti and bootz commands have all been refactored previously, so that they can operate without needing CONFIG_CMDLINE to be enabled. At the, time, zboot was left alone, since it is x86-specific and a bit more trouble.
This series adds a programatic API for zboot and uses the forthcoming bootstd 'image list' to collect information from an extlinux file. It is therefore possible to parse the file, load the resulting images and then examine/adjust the resulting bootflow, before booting.
The addition of options to extlinux resulted in the PXE and extlinux bootmeth having slightly different features. This is tidied up in this series, with common functions for both. This allows the same features (loading images as a separate step) to be provided for PXE.
Simon Glass (39): x86: Make do_zboot_states() static x86: Rename zboot_run() to zboot_run_args() x86: Drop duplicate definition of zimage_dump() x86: Move x86 zboot state into struct bootm_info x86: Rename state to bmi x86: Move the bootm state for zimage into cmd/ bootstd: Correct display of kernel version x86: Drop the unnecessary base_ptr argument to zboot_dump() boot: Split pxe label_boot() into two parts boot: Split pxe label_run_boot() into two parts boot: Pass just the FDT argument to label_process_fdt() bootm: Allow building bootm.c without CONFIG_SYS_BOOTM_LEN boot: pxe: Use bootm_...() functions where possible boot: pxe: Refactor label_run_boot() to avoid cmdline net: Keep the bootstage functions together net: Tidy up the comments to parse_args() net: Simplify parse_args() net: Return the load address from parse_args() net: Return the address and size from parse_addr_size() net: Return the size from parse_args() net: Refactor part of netboot_common() into a function net: Drop #ifdef in parse_args() net: Provide a function to run network operations boot: Avoid using the cmdline in bootmeth_pxe and pxe cmd pxe: Drop the cmdline parameter pxe: Record the bootflow in the PXE context pxe: Allow skipping the boot test: Update bootm test to restore silent_console bootmeth_extlinux: Move extlinux_info into plat bootmeth_extlinux: Move pxe_context into plat bootmeth: Refactor to put options in a common file bootmeth_pxe: Implement the fallback option bootmeth_pxe: Drop the driver-private data bootmeth_extlinux: Move boot code into common file bootstd: Update extlinux and pxe to allow boot interruption pxe: Collect the FDT in the bootflow pxe: Deal with a missing FDT in the bootflow pxe_utils: Refactor to separate reading from booting bootmeth_extlinux: Refactor extlinux to split boot
arch/x86/include/asm/zimage.h | 57 +--- arch/x86/lib/zimage.c | 102 ++++--- boot/Makefile | 6 +- boot/bootm.c | 8 +- boot/bootmeth_cros.c | 6 +- boot/bootmeth_extlinux.c | 97 +------ boot/bootmeth_pxe.c | 48 ++-- boot/ext_pxe_common.c | 134 +++++++++ boot/pxe_utils.c | 507 +++++++++++++++++++++------------- cmd/bootflow.c | 8 +- cmd/net.c | 92 +++--- cmd/pxe.c | 30 +- cmd/sysboot.c | 4 +- cmd/x86/zboot.c | 33 ++- include/bootm.h | 63 ++++- include/bootmeth.h | 8 +- include/extlinux.h | 52 +++- include/net-common.h | 30 ++ include/pxe_utils.h | 56 +++- net/net.c | 44 +++ test/boot/bootflow.c | 71 +++++ test/boot/bootm.c | 7 + 22 files changed, 960 insertions(+), 503 deletions(-) create mode 100644 boot/ext_pxe_common.c

This function is only called within zboot.c so make the function private.
Signed-off-by: Simon Glass sjg@chromium.org ---
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;

Rename this function so we can (later) create a zboot_run() function which looks the same as bootm_run()
Signed-off-by: Simon Glass sjg@chromium.org ---
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 73a21bc8f03..53fc81f57a2 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -436,8 +436,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

This is now defined in bootm.h so drop the duplicate in the x86 code.
Signed-off-by: Simon Glass sjg@chromium.org ---
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 <bootm.h> #include <command.h> #include <mapmem.h> #include <vsprintf.h>

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 sjg@chromium.org ---
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 53fc81f57a2..c2cf52658e9 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) { @@ -643,7 +643,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 *

Use the common name for the struct, in preparation for passing it around between functions.
Signed-off-by: Simon Glass sjg@chromium.org ---
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 c2cf52658e9..1afd3084144 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)) { @@ -431,7 +431,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; } @@ -597,7 +597,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); @@ -643,22 +643,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);

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 sjg@chromium.org ---
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 <asm/bootparam.h> #include <asm/e820.h>
+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 1afd3084144..fb69d0ef561 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)) { @@ -431,7 +428,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; } @@ -439,16 +436,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);
@@ -556,7 +555,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; @@ -597,7 +597,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); @@ -640,25 +640,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 5668a0c9b19..5ab322ef00d 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -381,7 +381,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 <vsprintf.h> #include <asm/zimage.h>
+/* 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

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 sjg@chromium.org ---
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 fb69d0ef561..d74c404464c 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -559,7 +559,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); @@ -596,10 +595,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 5ab322ef00d..b3b78bebaed 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -384,6 +384,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;

This value is include the bootm_info, so drop the unnecessary parameter.
Signed-off-by: Simon Glass sjg@chromium.org ---
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 d74c404464c..4dfcde68060 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -555,12 +555,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 b3b78bebaed..a89c3bfd9c5 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -386,7 +386,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

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.
Also change a strncpy() to strlcpy() to keep checkpatch happy.
Signed-off-by: Simon Glass sjg@chromium.org ---
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 82f217aaf86..edccb29e770 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 initaddr 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) - strncpy(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 */

Hi Simon,
On 11/19/24 2:18 PM, Simon Glass wrote:
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.
Also change a strncpy() to strlcpy() to keep checkpatch happy.
Signed-off-by: Simon Glass sjg@chromium.org
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 82f217aaf86..edccb29e770 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 initaddr address (NULL if none)
s/initaddr/initrd/
And would have preferred the strncpy/strlcpy swap to not be hidden in the big diff :)
Otherwise,
Reviewed-by: Quentin Schulz quentin.schulz@cherry.de
Cheers, Quentin

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 sjg@chromium.org ---
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 edccb29e770..97dd5a36150 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 initaddr 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 initaddr 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;

Hi Simon,
On 11/19/24 2:18 PM, Simon Glass wrote:
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 sjg@chromium.org
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 edccb29e770..97dd5a36150 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 initaddr 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");
I would keep this in the label_process_fdt function as it seems awfully related to fdt handling :)
Reviewed-by: Quentin Schulz quentin.schulz@cherry.de
Thanks! Quentin

On 11/27/24 12:39 PM, Quentin Schulz wrote:
Hi Simon,
On 11/19/24 2:18 PM, Simon Glass wrote:
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 sjg@chromium.org
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 edccb29e770..97dd5a36150 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 initaddr 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");
I would keep this in the label_process_fdt function as it seems awfully related to fdt handling :)
Ignore that, I see it is making sense with the next patch.
Cheers, Quentin

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 sjg@chromium.org ---
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 97dd5a36150..66f82d3fbc1 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;

Hi Simon,
On 11/19/24 2:18 PM, Simon Glass wrote:
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 sjg@chromium.org
Reviewed-by: Quentin Schulz quentin.schulz@cherry.de
Thanks! Quentin

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 sjg@chromium.org ---
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 16a43d519a8..0a1040ef923 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 *

Hi Simon,
On Tue, 19 Nov 2024 at 15:19, Simon Glass sjg@chromium.org wrote:
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 sjg@chromium.org
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 16a43d519a8..0a1040ef923 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;
+}
Do we really need a function for this? Why don't you #ifdef CONFIG_SYS_BOOTM_LEN #define SYS_BOOTM_LEN CONFIG_SYS_BOOTM_LEN #else #define SYS_BOOTM_LEN 0 #endif
Thanks /Ilias
/**
- bootm_init() - Set up a bootm_info struct with useful defaults
-- 2.34.1

Hi Ilias,
On Wed, 20 Nov 2024 at 03:56, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Simon,
On Tue, 19 Nov 2024 at 15:19, Simon Glass sjg@chromium.org wrote:
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 sjg@chromium.org
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 16a43d519a8..0a1040ef923 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;
+}
Do we really need a function for this? Why don't you #ifdef CONFIG_SYS_BOOTM_LEN #define SYS_BOOTM_LEN CONFIG_SYS_BOOTM_LEN #else #define SYS_BOOTM_LEN 0 #endif
Yes, we could. Just trying to avoid #ifdefs in the C files and provide a way to improve this logic later...IMO using this value when it is not defined should be an error, but we cannot do that in the tools-only build, without yet more refactoring.
Regards, Simon

On Tue, Nov 19, 2024 at 06:18:17AM -0700, Simon Glass wrote:
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 sjg@chromium.org
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 16a43d519a8..0a1040ef923 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(),
if (err) {&load_end);
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(),
bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return err; }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
This kind of change is wrong in that it moves a build time failure to a (potentially non-obvious) runtime failure. If we're moving to now dynamically allocating the location where we can decompress to, then it should be part of that abstraction. But that doesn't look to be the case here.

Hi Tom,
On Wed, 20 Nov 2024 at 07:50, Tom Rini trini@konsulko.com wrote:
On Tue, Nov 19, 2024 at 06:18:17AM -0700, Simon Glass wrote:
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 sjg@chromium.org
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 16a43d519a8..0a1040ef923 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
This kind of change is wrong in that it moves a build time failure to a (potentially non-obvious) runtime failure. If we're moving to now dynamically allocating the location where we can decompress to, then it should be part of that abstraction. But that doesn't look to be the case here.
Yes, sure. The right answer is probably to split out parts of bootm.c into a new file. I already have 39 patches...it needs a bit more thought.
Regards, SImon

Hi Simon,
On 11/19/24 2:18 PM, Simon Glass wrote:
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 sjg@chromium.org
Reviewed-by: Quentin Schulz quentin.schulz@cherry.de
Thanks! Quentin

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 sjg@chromium.org ---
boot/Makefile | 2 +- boot/pxe_utils.c | 43 ++++++++++++++++++++----------------------- 2 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/boot/Makefile b/boot/Makefile index 43def7c33d7..9ccdc2dc8f4 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 66f82d3fbc1..2517999d408 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -7,6 +7,7 @@ #define LOG_CATEGORY LOGC_BOOT
#include <bootflow.h> +#include <bootm.h> #include <command.h> #include <dm.h> #include <env.h> @@ -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; }

Hi Simon,
On 11/19/24 2:18 PM, Simon Glass wrote:
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 sjg@chromium.org
boot/Makefile | 2 +- boot/pxe_utils.c | 43 ++++++++++++++++++++----------------------- 2 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/boot/Makefile b/boot/Makefile index 43def7c33d7..9ccdc2dc8f4 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 66f82d3fbc1..2517999d408 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -7,6 +7,7 @@ #define LOG_CATEGORY LOGC_BOOT
#include <bootflow.h> +#include <bootm.h> #include <command.h> #include <dm.h> #include <env.h> @@ -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)
{ /* For FIT, the label can be identical to kernel one */ if (label->fdt && !strcmp(label->kernel_label, label->fdt)) {char *kernel_addr, const char **fdt_argp)
@@ -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");
} else {bmi.conf_fdt = env_get("fdt_addr");
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");
} else {bmi.conf_fdt = env_get("fdtcontroladdr");
bootm_argv[3] = env_get("fdtcontroladdr");
}bmi.conf_fdt = env_get("fdtcontroladdr");
Unrelated remark:
This could be shortened to
if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || strcmp("-", label->fdt)) bmi.conf_fdt = env_get("fdtcontroladdr");
Same for a few lines above.
}
- 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);
/* Try booting an AArch64 Linux kernel image */ } else if (IS_ENABLED(CONFIG_CMD_BOOTI)) { log_debug("using booti\n");ret = bootm_run(&bmi);
do_booti(ctx->cmdtp, 0, bootm_argc, bootm_argv);
/* Try booting a Image */ } else if (IS_ENABLED(CONFIG_CMD_BOOTZ)) { log_debug("using bootz\n");ret = booti_run(&bmi);
do_bootz(ctx->cmdtp, 0, bootm_argc, bootm_argv);
/* Try booting an x86_64 Linux kernel image */ } else if (IS_ENABLED(CONFIG_CMD_ZBOOT)) { log_debug("using zboot\n");ret = bootz_run(&bmi);
@@ -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;
simply
return ret;
?
Reviewed-by: Quentin Schulz quentin.schulz@cherry.de
Thanks! Quentin

Hi Quentin,
On Wed, 27 Nov 2024 at 05:08, Quentin Schulz quentin.schulz@cherry.de wrote:
Hi Simon,
On 11/19/24 2:18 PM, Simon Glass wrote:
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 sjg@chromium.org
boot/Makefile | 2 +- boot/pxe_utils.c | 43 ++++++++++++++++++++----------------------- 2 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/boot/Makefile b/boot/Makefile index 43def7c33d7..9ccdc2dc8f4 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 66f82d3fbc1..2517999d408 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -7,6 +7,7 @@ #define LOG_CATEGORY LOGC_BOOT
#include <bootflow.h> +#include <bootm.h> #include <command.h> #include <dm.h> #include <env.h> @@ -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)
{ /* For FIT, the label can be identical to kernel one */ if (label->fdt && !strcmp(label->kernel_label, label->fdt)) {char *kernel_addr, const char **fdt_argp)
@@ -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"); }
Unrelated remark:
This could be shortened to
if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || strcmp("-", label->fdt)) bmi.conf_fdt = env_get("fdtcontroladdr");
Same for a few lines above.
OK, will add a patch for that, thanks.
}
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;
simply
return ret;
?
Sure, but I try to end with success! It allows addition of logging or other things without hacking the code too much.
Reviewed-by: Quentin Schulz quentin.schulz@cherry.de
Regards, Simon

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 sjg@chromium.org ---
arch/x86/lib/zimage.c | 27 +++++++++++++++++++-------- boot/pxe_utils.c | 13 +++++-------- include/bootm.h | 9 +++++++++ 3 files changed, 33 insertions(+), 16 deletions(-)
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 4dfcde68060..26d623711bc 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -433,27 +433,38 @@ int zboot_go(struct bootm_info *bmi) return ret; }
-int zboot_run_args(ulong addr, ulong size, ulong initrd, ulong initrd_size, - ulong base, char *cmdline) +int zboot_run(struct bootm_info *bmi) { - struct bootm_info bmi; int ret;
- bootm_init(&bmi); - zboot_start(&bmi, addr, size, initrd, initrd_size, base, cmdline); - ret = zboot_load(&bmi); + ret = zboot_load(bmi); if (ret) return log_msg_ret("ld", ret); - ret = zboot_setup(&bmi); + ret = zboot_setup(bmi); if (ret) return log_msg_ret("set", ret); - ret = zboot_go(&bmi); + 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) +{ + struct bootm_info bmi; + int ret; + + bootm_init(&bmi); + zboot_start(&bmi, addr, size, initrd, initrd_size, base, cmdline); + ret = zboot_run(&bmi); + if (ret) + return log_msg_ret("zra", ret); + + return 0; +} + static void print_num(const char *name, ulong value) { printf("%-20s: %lx\n", name, value); diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 2517999d408..73d3114813d 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,13 @@ 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(kernel_addr, NULL)); + bootm_x86_set(&bmi, initrd_size, + hextoul(initrd_filesize, NULL)); }
if (!bmi.conf_fdt) { @@ -648,7 +645,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 *

Move the bootstage_mark() function just before net_loop(), so that the IPv6 code is not in the way.
Signed-off-by: Simon Glass sjg@chromium.org ---
cmd/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index c90578e1b9f..d3e566752d1 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -411,8 +411,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; @@ -426,6 +424,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);

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 sjg@chromium.org ---
cmd/net.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index d3e566752d1..01332d57b98 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -311,9 +311,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[])

On Tue, 19 Nov 2024 at 15:19, Simon Glass sjg@chromium.org wrote:
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 sjg@chromium.org
cmd/net.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index d3e566752d1..01332d57b98 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -311,9 +311,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[])
2.34.1
Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org

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 sjg@chromium.org ---
cmd/net.c | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index 01332d57b98..7c7489efe4d 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -312,10 +312,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 * @@ -323,21 +319,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: @@ -350,16 +345,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: @@ -368,9 +357,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;
@@ -378,20 +365,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; @@ -415,11 +402,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;

Rather than updating the global, update the value of a parameter, so the action of the function is simpler.
Signed-off-by: Simon Glass sjg@chromium.org ---
cmd/net.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index 7c7489efe4d..857daace78d 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -312,7 +312,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 @@ -320,10 +319,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; @@ -346,7 +347,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; @@ -356,7 +357,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; @@ -402,7 +403,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; }

Rather than updating the global, update the value of some parameters, so the action of the function is simpler.
Signed-off-by: Simon Glass sjg@chromium.org ---
cmd/net.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index 857daace78d..920d9918ff6 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -295,13 +295,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; } @@ -354,7 +356,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); @@ -364,7 +367,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;

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 sjg@chromium.org ---
cmd/net.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index 920d9918ff6..8bb8604faf6 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -321,12 +321,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; @@ -356,8 +358,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); @@ -367,7 +368,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; @@ -383,6 +384,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; @@ -390,10 +392,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; @@ -406,10 +408,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;

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 sjg@chromium.org ---
cmd/net.c | 62 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 16 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index 8bb8604faf6..f1b520143df 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -380,11 +380,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; @@ -408,22 +447,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; @@ -438,14 +472,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();

Use IS_ENABLED() to avoid an extra build path.
Signed-off-by: Simon Glass sjg@chromium.org ---
cmd/net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index f1b520143df..03b33aa1f20 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -366,13 +366,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; }

On Tue, 19 Nov 2024 at 15:19, Simon Glass sjg@chromium.org wrote:
Use IS_ENABLED() to avoid an extra build path.
Signed-off-by: Simon Glass sjg@chromium.org
cmd/net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index f1b520143df..03b33aa1f20 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -366,13 +366,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; }
-- 2.34.1
Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org

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 sjg@chromium.org ---
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 03b33aa1f20..8ae4639ecb4 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -380,44 +380,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[]) { @@ -473,7 +435,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 524ed4ad131..839d82f7d1f 100644 --- a/include/net-common.h +++ b/include/net-common.h @@ -463,6 +463,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 f47e9fbe33a..0a1b477bbf8 100644 --- a/net/net.c +++ b/net/net.c @@ -770,6 +770,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)

Use the new netboot_run() function to avoid building a command line, when running these network operations.
For the one board which uses lwip, it is not quite clear how to avoid using the cmdline interface, so produce an error, for now. This can be figured out later.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/bootmeth_pxe.c | 16 ++++++---------- cmd/pxe.c | 21 +++++++-------------- 2 files changed, 13 insertions(+), 24 deletions(-)
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index b91e61bcbc4..c6a132b8de2 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -116,21 +116,17 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, const char *file_path, ulong addr, enum bootflow_img_t type, ulong *sizep) { - char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; - struct pxe_context *ctx = dev_get_priv(dev); - char file_addr[17]; ulong size; int ret;
- sprintf(file_addr, "%lx", addr); - tftp_argv[1] = file_addr; - tftp_argv[2] = (void *)file_path; - - if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv)) - return -ENOENT; - ret = pxe_get_file_size(&size); + if (IS_ENABLED(CONFIG_NET_LWIP)) + return -ENOTSUPP; + ret = netboot_run(TFTPGET, addr, file_path, 0, false); if (ret) return log_msg_ret("tftp", ret); + ret = pxe_get_file_size(&size); + if (ret) + return log_msg_ret("tft2", ret); if (size > *sizep) return log_msg_ret("spc", -ENOSPC); *sizep = size; diff --git a/cmd/pxe.c b/cmd/pxe.c index 37b8dea6ad6..c69b8130423 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -29,25 +29,18 @@ const char *pxe_default_paths[] = { static int do_get_tftp(struct pxe_context *ctx, const char *file_path, char *file_addr, enum bootflow_img_t type, ulong *sizep) { - char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; int ret; - int num_args;
- tftp_argv[1] = file_addr; - tftp_argv[2] = (void *)file_path; - if (ctx->use_ipv6) { - tftp_argv[3] = USE_IP6_CMD_PARAM; - num_args = 4; - } else { - num_args = 3; - } - - if (do_tftpb(ctx->cmdtp, 0, num_args, tftp_argv)) - return -ENOENT; + if (IS_ENABLED(CONFIG_NET_LWIP)) + return -ENOTSUPP; + ret = netboot_run(TFTPGET, hextoul(file_addr, NULL), file_path, 0, + ctx->use_ipv6); + if (ret) + return log_msg_ret("tfp", ret);
ret = pxe_get_file_size(sizep); if (ret) - return log_msg_ret("tftp", ret); + return log_msg_ret("tf2", ret); ctx->pxe_file_size = *sizep;
return 1;

Now that PXE can operate without the command line, drop the parameter throughout the code.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/bootmeth_extlinux.c | 5 ++--- boot/bootmeth_pxe.c | 4 +--- boot/pxe_utils.c | 8 +++----- cmd/pxe.c | 9 ++++----- cmd/sysboot.c | 4 ++-- include/extlinux.h | 1 - include/pxe_utils.h | 10 +++------- 7 files changed, 15 insertions(+), 26 deletions(-)
diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c index 63cb9a4a8af..ac1efa48a91 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -173,7 +173,6 @@ static int extlinux_read_bootflow(struct udevice *dev, struct bootflow *bflow)
static int extlinux_boot(struct udevice *dev, struct bootflow *bflow) { - struct cmd_tbl cmdtp = {}; /* dummy */ struct pxe_context ctx; struct extlinux_info info; struct extlinux_plat *plat; @@ -186,8 +185,8 @@ static int extlinux_boot(struct udevice *dev, struct bootflow *bflow)
plat = dev_get_plat(dev);
- ret = pxe_setup_ctx(&ctx, &cmdtp, extlinux_getfile, &info, true, - bflow->fname, false, plat->use_fallback); + ret = pxe_setup_ctx(&ctx, extlinux_getfile, &info, true, bflow->fname, + false, plat->use_fallback); if (ret) return log_msg_ret("ctx", -EINVAL);
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index c6a132b8de2..59ebf1be83a 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -140,7 +140,6 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, static int extlinux_pxe_boot(struct udevice *dev, struct bootflow *bflow) { struct pxe_context *ctx = dev_get_priv(dev); - struct cmd_tbl cmdtp = {}; /* dummy */ struct extlinux_info info; ulong addr; int ret; @@ -148,8 +147,7 @@ static int extlinux_pxe_boot(struct udevice *dev, struct bootflow *bflow) addr = map_to_sysmem(bflow->buf); info.dev = dev; info.bflow = bflow; - info.cmdtp = &cmdtp; - ret = pxe_setup_ctx(ctx, &cmdtp, extlinux_pxe_getfile, &info, false, + ret = pxe_setup_ctx(ctx, extlinux_pxe_getfile, &info, false, bflow->subdir, false, false); if (ret) return log_msg_ret("ctx", -EINVAL); diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 73d3114813d..8c04f439441 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -1636,16 +1636,14 @@ void handle_pxe_menu(struct pxe_context *ctx, struct pxe_menu *cfg) boot_unattempted_labels(ctx, cfg); }
-int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp, - pxe_getfile_func getfile, void *userdata, - bool allow_abs_path, const char *bootfile, bool use_ipv6, - bool use_fallback) +int pxe_setup_ctx(struct pxe_context *ctx, pxe_getfile_func getfile, + void *userdata, bool allow_abs_path, const char *bootfile, + bool use_ipv6, bool use_fallback) { const char *last_slash; size_t path_len = 0;
memset(ctx, '\0', sizeof(*ctx)); - ctx->cmdtp = cmdtp; ctx->getfile = getfile; ctx->userdata = userdata; ctx->allow_abs_path = allow_abs_path; diff --git a/cmd/pxe.c b/cmd/pxe.c index c69b8130423..530d5d9c35b 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -126,12 +126,11 @@ static int pxe_ipaddr_paths(struct pxe_context *ctx, unsigned long pxefile_addr_
int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep, bool use_ipv6) { - struct cmd_tbl cmdtp[] = {}; /* dummy */ struct pxe_context ctx; int i;
- if (pxe_setup_ctx(&ctx, cmdtp, do_get_tftp, NULL, false, - env_get("bootfile"), use_ipv6, false)) + if (pxe_setup_ctx(&ctx, do_get_tftp, NULL, false, env_get("bootfile"), + use_ipv6, false)) return -ENOMEM;
if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION) && @@ -280,8 +279,8 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) return 1; }
- if (pxe_setup_ctx(&ctx, cmdtp, do_get_tftp, NULL, false, - env_get("bootfile"), use_ipv6, false)) { + if (pxe_setup_ctx(&ctx, do_get_tftp, NULL, false, env_get("bootfile"), + use_ipv6, false)) { printf("Out of memory\n"); return CMD_RET_FAILURE; } diff --git a/cmd/sysboot.c b/cmd/sysboot.c index 93d4a400830..6e899f381ec 100644 --- a/cmd/sysboot.c +++ b/cmd/sysboot.c @@ -105,8 +105,8 @@ static int do_sysboot(struct cmd_tbl *cmdtp, int flag, int argc, return 1; }
- if (pxe_setup_ctx(&ctx, cmdtp, sysboot_read_file, &info, true, - filename, false, false)) { + if (pxe_setup_ctx(&ctx, sysboot_read_file, &info, true, filename, false, + false)) { printf("Out of memory\n"); return CMD_RET_FAILURE; } diff --git a/include/extlinux.h b/include/extlinux.h index 721ba46371c..6747fe01dda 100644 --- a/include/extlinux.h +++ b/include/extlinux.h @@ -18,7 +18,6 @@ struct extlinux_info { struct udevice *dev; struct bootflow *bflow; - struct cmd_tbl *cmdtp; };
#endif diff --git a/include/pxe_utils.h b/include/pxe_utils.h index 0378f2889f7..fb057442d5d 100644 --- a/include/pxe_utils.h +++ b/include/pxe_utils.h @@ -100,7 +100,6 @@ typedef int (*pxe_getfile_func)(struct pxe_context *ctx, const char *file_path, /** * struct pxe_context - context information for PXE parsing * - * @cmdtp: Pointer to command table to use when calling other commands * @getfile: Function called by PXE to read a file * @userdata: Data the caller requires for @getfile * @allow_abs_path: true to allow absolute paths @@ -112,7 +111,6 @@ typedef int (*pxe_getfile_func)(struct pxe_context *ctx, const char *file_path, * "default" option as default */ struct pxe_context { - struct cmd_tbl *cmdtp; /** * getfile() - read a file * @@ -222,7 +220,6 @@ int format_mac_pxe(char *outbuf, size_t outbuf_len); * pxe_setup_ctx() - Setup a new PXE context * * @ctx: Context to set up - * @cmdtp: Command table entry which started this action * @getfile: Function to call to read a file * @userdata: Data the caller requires for @getfile - stored in ctx->userdata * @allow_abs_path: true to allow absolute paths @@ -237,10 +234,9 @@ int format_mac_pxe(char *outbuf, size_t outbuf_len); * Return: 0 if OK, -ENOMEM if out of memory, -E2BIG if bootfile is larger than * MAX_TFTP_PATH_LEN bytes */ -int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp, - pxe_getfile_func getfile, void *userdata, - bool allow_abs_path, const char *bootfile, bool use_ipv6, - bool use_fallback); +int pxe_setup_ctx(struct pxe_context *ctx, pxe_getfile_func getfile, + void *userdata, bool allow_abs_path, const char *bootfile, + bool use_ipv6, bool use_fallback);
/** * pxe_destroy_ctx() - Destroy a PXE context

At present the only option with PXE is to boot it and see what happens.
Provide a bootflow, when available, so that PXE will eventually be able to add some useful information to it.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/bootmeth_extlinux.c | 2 +- boot/bootmeth_pxe.c | 2 +- boot/pxe_utils.c | 3 ++- cmd/pxe.c | 4 ++-- cmd/sysboot.c | 2 +- include/pxe_utils.h | 5 ++++- 6 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c index ac1efa48a91..9cc2032a201 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -186,7 +186,7 @@ static int extlinux_boot(struct udevice *dev, struct bootflow *bflow) plat = dev_get_plat(dev);
ret = pxe_setup_ctx(&ctx, extlinux_getfile, &info, true, bflow->fname, - false, plat->use_fallback); + false, plat->use_fallback, bflow); if (ret) return log_msg_ret("ctx", -EINVAL);
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 59ebf1be83a..f2b9ffaae89 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -148,7 +148,7 @@ static int extlinux_pxe_boot(struct udevice *dev, struct bootflow *bflow) info.dev = dev; info.bflow = bflow; ret = pxe_setup_ctx(ctx, extlinux_pxe_getfile, &info, false, - bflow->subdir, false, false); + bflow->subdir, false, false, bflow); if (ret) return log_msg_ret("ctx", -EINVAL);
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 8c04f439441..b811406102b 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -1638,7 +1638,7 @@ void handle_pxe_menu(struct pxe_context *ctx, struct pxe_menu *cfg)
int pxe_setup_ctx(struct pxe_context *ctx, pxe_getfile_func getfile, void *userdata, bool allow_abs_path, const char *bootfile, - bool use_ipv6, bool use_fallback) + bool use_ipv6, bool use_fallback, struct bootflow *bflow) { const char *last_slash; size_t path_len = 0; @@ -1649,6 +1649,7 @@ int pxe_setup_ctx(struct pxe_context *ctx, pxe_getfile_func getfile, ctx->allow_abs_path = allow_abs_path; ctx->use_ipv6 = use_ipv6; ctx->use_fallback = use_fallback; + ctx->bflow = bflow;
/* figure out the boot directory, if there is one */ if (bootfile && strlen(bootfile) >= MAX_TFTP_PATH_LEN) diff --git a/cmd/pxe.c b/cmd/pxe.c index 530d5d9c35b..7728949d14b 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -130,7 +130,7 @@ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep, bool use_ipv6) int i;
if (pxe_setup_ctx(&ctx, do_get_tftp, NULL, false, env_get("bootfile"), - use_ipv6, false)) + use_ipv6, false, NULL)) return -ENOMEM;
if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION) && @@ -280,7 +280,7 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) }
if (pxe_setup_ctx(&ctx, do_get_tftp, NULL, false, env_get("bootfile"), - use_ipv6, false)) { + use_ipv6, false, NULL)) { printf("Out of memory\n"); return CMD_RET_FAILURE; } diff --git a/cmd/sysboot.c b/cmd/sysboot.c index 6e899f381ec..384d5e15e3d 100644 --- a/cmd/sysboot.c +++ b/cmd/sysboot.c @@ -106,7 +106,7 @@ static int do_sysboot(struct cmd_tbl *cmdtp, int flag, int argc, }
if (pxe_setup_ctx(&ctx, sysboot_read_file, &info, true, filename, false, - false)) { + false, NULL)) { printf("Out of memory\n"); return CMD_RET_FAILURE; } diff --git a/include/pxe_utils.h b/include/pxe_utils.h index fb057442d5d..e8e03430a81 100644 --- a/include/pxe_utils.h +++ b/include/pxe_utils.h @@ -109,6 +109,7 @@ typedef int (*pxe_getfile_func)(struct pxe_context *ctx, const char *file_path, * @use_ipv6: TRUE : use IPv6 addressing, FALSE : use IPv4 addressing * @use_fallback: TRUE : use "fallback" option as default, FALSE : use * "default" option as default + * @bflow: Bootflow being booted, or NULL if none */ struct pxe_context { /** @@ -129,6 +130,7 @@ struct pxe_context { ulong pxe_file_size; bool use_ipv6; bool use_fallback; + struct bootflow *bflow; };
/** @@ -231,12 +233,13 @@ int format_mac_pxe(char *outbuf, size_t outbuf_len); * other choice be selected * FALSE : Use "default" option should no other choice be * selected + * @bflow: Bootflow to update, NULL if none * Return: 0 if OK, -ENOMEM if out of memory, -E2BIG if bootfile is larger than * MAX_TFTP_PATH_LEN bytes */ int pxe_setup_ctx(struct pxe_context *ctx, pxe_getfile_func getfile, void *userdata, bool allow_abs_path, const char *bootfile, - bool use_ipv6, bool use_fallback); + bool use_ipv6, bool use_fallback, struct bootflow *bflow);
/** * pxe_destroy_ctx() - Destroy a PXE context

Provide a way to skip booting the OS and just return. This will allow bootstd to read out useful information.
Add debugging to help figure out the flow.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/pxe_utils.c | 12 ++++++++++-- include/pxe_utils.h | 4 +++- 2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index b811406102b..7106e532e03 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -788,6 +788,9 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) printf("append: %s\n", finalbootargs); }
+ if (ctx->no_boot) + return 0; + 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 */ @@ -1572,11 +1575,15 @@ static void boot_unattempted_labels(struct pxe_context *ctx, struct list_head *pos; struct pxe_label *label;
+ log_debug("Booting unattempted labels\n"); list_for_each(pos, &cfg->labels) { label = list_entry(pos, struct pxe_label, list);
- if (!label->attempted) - label_boot(ctx, label); + if (!label->attempted) { + log_debug("attempt: %s\n", label->name); + if (!label_boot(ctx, label)) + return; + } } }
@@ -1627,6 +1634,7 @@ void handle_pxe_menu(struct pxe_context *ctx, struct pxe_menu *cfg)
if (err == 1) { err = label_boot(ctx, choice); + log_debug("label_boot() returns %d\n", err); if (!err) return; } else if (err != -ENOENT) { diff --git a/include/pxe_utils.h b/include/pxe_utils.h index e8e03430a81..beadd221475 100644 --- a/include/pxe_utils.h +++ b/include/pxe_utils.h @@ -109,7 +109,8 @@ typedef int (*pxe_getfile_func)(struct pxe_context *ctx, const char *file_path, * @use_ipv6: TRUE : use IPv6 addressing, FALSE : use IPv4 addressing * @use_fallback: TRUE : use "fallback" option as default, FALSE : use * "default" option as default - * @bflow: Bootflow being booted, or NULL if none + * @no_boot: Stop show of actually booting and just return + * @bflow: Bootflow being booted, or NULL if none (must be valid if @no_boot) */ struct pxe_context { /** @@ -130,6 +131,7 @@ struct pxe_context { ulong pxe_file_size; bool use_ipv6; bool use_fallback; + bool no_boot; struct bootflow *bflow; };

Unset this environment variable at the end of bootm_test_silent() et al to avoid affecting subsequent tests.
Signed-off-by: Simon Glass sjg@chromium.org ---
test/boot/bootm.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/test/boot/bootm.c b/test/boot/bootm.c index 52b83f149cb..db024bb1b0b 100644 --- a/test/boot/bootm.c +++ b/test/boot/bootm.c @@ -121,6 +121,9 @@ static int bootm_test_silent(struct unit_test_state *uts) ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT)); ut_asserteq_str("console=ttynull something", buf);
+ /* restore settings */ + env_set("silent_linux", NULL); + return 0; } BOOTM_TEST(bootm_test_silent, 0); @@ -226,6 +229,8 @@ static int bootm_test_subst_var(struct unit_test_state *uts) ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); ut_asserteq_str("some${var}thing console=ttynull", env_get("bootargs"));
+ env_set("silent_linux", NULL); + return 0; } BOOTM_TEST(bootm_test_subst_var, 0); @@ -243,6 +248,8 @@ static int bootm_test_subst_both(struct unit_test_state *uts) ut_assertok(bootm_process_cmdline_env(BOOTM_CL_ALL)); ut_asserteq_str("some1234567890thing console=ttynull", env_get("bootargs"));
+ env_set("silent_linux", NULL); + return 0; } BOOTM_TEST(bootm_test_subst_both, 0);

Move this struct into the plat data so that we can use it multiple times during the boot process.
This struct is missing a comment, so add one.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/bootmeth_extlinux.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c index 9cc2032a201..b48f96b16ef 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -21,8 +21,15 @@ #include <mmc.h> #include <pxe_utils.h>
+/** + * struct extlinux_plat - locate state for this bootmeth + * + * @use_fallback: true to boot with the fallback option + * @info: Info passed to the extlinux_getfile() function + */ struct extlinux_plat { bool use_fallback; + struct extlinux_info info; };
enum extlinux_option_type { @@ -173,20 +180,18 @@ static int extlinux_read_bootflow(struct udevice *dev, struct bootflow *bflow)
static int extlinux_boot(struct udevice *dev, struct bootflow *bflow) { + struct extlinux_plat *plat = dev_get_plat(dev); struct pxe_context ctx; - struct extlinux_info info; - struct extlinux_plat *plat; ulong addr; int ret;
addr = map_to_sysmem(bflow->buf); - info.dev = dev; - info.bflow = bflow;
- plat = dev_get_plat(dev); + plat->info.dev = dev; + plat->info.bflow = bflow;
- ret = pxe_setup_ctx(&ctx, extlinux_getfile, &info, true, bflow->fname, - false, plat->use_fallback, bflow); + ret = pxe_setup_ctx(&ctx, extlinux_getfile, &plat->info, true, + bflow->fname, false, plat->use_fallback, bflow); if (ret) return log_msg_ret("ctx", -EINVAL);

Move this struct into the plat data so that we can use it multiple times during the boot process.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/bootmeth_extlinux.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c index b48f96b16ef..2f8e579540b 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -26,9 +26,11 @@ * * @use_fallback: true to boot with the fallback option * @info: Info passed to the extlinux_getfile() function + * @ctx: holds the PXE context, if it should be saved */ struct extlinux_plat { bool use_fallback; + struct pxe_context ctx; struct extlinux_info info; };
@@ -181,7 +183,6 @@ static int extlinux_read_bootflow(struct udevice *dev, struct bootflow *bflow) static int extlinux_boot(struct udevice *dev, struct bootflow *bflow) { struct extlinux_plat *plat = dev_get_plat(dev); - struct pxe_context ctx; ulong addr; int ret;
@@ -190,12 +191,12 @@ static int extlinux_boot(struct udevice *dev, struct bootflow *bflow) plat->info.dev = dev; plat->info.bflow = bflow;
- ret = pxe_setup_ctx(&ctx, extlinux_getfile, &plat->info, true, + ret = pxe_setup_ctx(&plat->ctx, extlinux_getfile, &plat->info, true, bflow->fname, false, plat->use_fallback, bflow); if (ret) return log_msg_ret("ctx", -EINVAL);
- ret = pxe_process(&ctx, addr, false); + ret = pxe_process(&plat->ctx, addr, false); if (ret) return log_msg_ret("bread", -EINVAL);

The fallback feature is implemented for extlinux but not for PXE. Move the code into common files so we can keep both pieces in sync.
Tidy up the comment for set_property() while we are here, fixing the return value and some missing hyphens.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/Makefile | 4 +-- boot/bootmeth_extlinux.c | 74 -------------------------------------- boot/ext_pxe_common.c | 76 ++++++++++++++++++++++++++++++++++++++++ include/bootmeth.h | 8 ++--- include/extlinux.h | 29 +++++++++++++++ 5 files changed, 111 insertions(+), 80 deletions(-) create mode 100644 boot/ext_pxe_common.c
diff --git a/boot/Makefile b/boot/Makefile index 9ccdc2dc8f4..882cd760027 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -27,8 +27,8 @@ obj-$(CONFIG_$(PHASE_)BOOTSTD) += bootstd-uclass.o obj-$(CONFIG_$(PHASE_)BOOTSTD_MENU) += bootflow_menu.o obj-$(CONFIG_$(PHASE_)BOOTSTD_PROG) += prog_boot.o
-obj-$(CONFIG_$(PHASE_)BOOTMETH_EXTLINUX) += bootmeth_extlinux.o -obj-$(CONFIG_$(PHASE_)BOOTMETH_EXTLINUX_PXE) += bootmeth_pxe.o +obj-$(CONFIG_$(PHASE_)BOOTMETH_EXTLINUX) += ext_pxe_common.o bootmeth_extlinux.o +obj-$(CONFIG_$(PHASE_)BOOTMETH_EXTLINUX_PXE) += ext_pxe_common.o bootmeth_pxe.o obj-$(CONFIG_$(PHASE_)BOOTMETH_EFILOADER) += bootmeth_efi.o obj-$(CONFIG_$(PHASE_)BOOTMETH_CROS) += bootm.o bootm_os.o bootmeth_cros.o obj-$(CONFIG_$(PHASE_)BOOTMETH_QFW) += bootmeth_qfw.o diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c index 2f8e579540b..ce11077ee35 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -21,48 +21,6 @@ #include <mmc.h> #include <pxe_utils.h>
-/** - * struct extlinux_plat - locate state for this bootmeth - * - * @use_fallback: true to boot with the fallback option - * @info: Info passed to the extlinux_getfile() function - * @ctx: holds the PXE context, if it should be saved - */ -struct extlinux_plat { - bool use_fallback; - struct pxe_context ctx; - struct extlinux_info info; -}; - -enum extlinux_option_type { - EO_FALLBACK, - EO_INVALID -}; - -struct extlinux_option { - char *name; - enum extlinux_option_type option; -}; - -static const struct extlinux_option options[] = { - {"fallback", EO_FALLBACK}, - {NULL, EO_INVALID} -}; - -static enum extlinux_option_type get_option(const char *option) -{ - int i = 0; - - while (options[i].name) { - if (!strcmp(options[i].name, option)) - return options[i].option; - - i++; - } - - return EO_INVALID; -}; - static int extlinux_get_state_desc(struct udevice *dev, char *buf, int maxsize) { if (IS_ENABLED(CONFIG_SANDBOX)) { @@ -203,38 +161,6 @@ static int extlinux_boot(struct udevice *dev, struct bootflow *bflow) return 0; }
-static int extlinux_set_property(struct udevice *dev, const char *property, const char *value) -{ - struct extlinux_plat *plat; - static enum extlinux_option_type option; - - plat = dev_get_plat(dev); - - option = get_option(property); - if (option == EO_INVALID) { - printf("Invalid option\n"); - return -EINVAL; - } - - switch (option) { - case EO_FALLBACK: - if (!strcmp(value, "1")) { - plat->use_fallback = true; - } else if (!strcmp(value, "0")) { - plat->use_fallback = false; - } else { - printf("Unexpected value '%s'\n", value); - return -EINVAL; - } - break; - default: - printf("Unrecognised property '%s'\n", property); - return -EINVAL; - } - - return 0; -} - static int extlinux_bootmeth_bind(struct udevice *dev) { struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); diff --git a/boot/ext_pxe_common.c b/boot/ext_pxe_common.c new file mode 100644 index 00000000000..e42865b84f5 --- /dev/null +++ b/boot/ext_pxe_common.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Common functions for extlinux and PXE + * + * Copyright 2024 Collabora + * Written by Martyn Welch martyn.welch@collabora.com + */ + +#define LOG_CATEGORY UCLASS_BOOTSTD + +#include <dm.h> +#include <extlinux.h> +#include <mapmem.h> +#include <linux/string.h> + +enum extlinux_option_type { + EO_FALLBACK, + EO_INVALID +}; + +struct extlinux_option { + char *name; + enum extlinux_option_type option; +}; + +static const struct extlinux_option options[] = { + {"fallback", EO_FALLBACK}, + {NULL, EO_INVALID} +}; + +static enum extlinux_option_type extlinux_get_option(const char *option) +{ + int i = 0; + + while (options[i].name) { + if (!strcmp(options[i].name, option)) + return options[i].option; + + i++; + } + + return EO_INVALID; +}; + +int extlinux_set_property(struct udevice *dev, const char *property, + const char *value) +{ + struct extlinux_plat *plat; + static enum extlinux_option_type option; + + plat = dev_get_plat(dev); + + option = extlinux_get_option(property); + if (option == EO_INVALID) { + printf("Invalid option\n"); + return -EINVAL; + } + + switch (option) { + case EO_FALLBACK: + if (!strcmp(value, "1")) { + plat->use_fallback = true; + } else if (!strcmp(value, "0")) { + plat->use_fallback = false; + } else { + printf("Unexpected value '%s'\n", value); + return -EINVAL; + } + break; + default: + printf("Unrecognised property '%s'\n", property); + return -EINVAL; + } + + return 0; +} diff --git a/include/bootmeth.h b/include/bootmeth.h index 26de593a9a4..03301c90580 100644 --- a/include/bootmeth.h +++ b/include/bootmeth.h @@ -151,15 +151,15 @@ struct bootmeth_ops { /** * set_property() - set the bootmeth property * - * This allows the setting of boot method specific properties to enable - * automated finer grain control of the boot process + * This allows the setting of bootmeth-specific properties to enable + * automated finer-grained control of the boot process * * @name: String containing the name of the relevant boot method * @property: String containing the name of the property to set * @value: String containing the value to be set for the specified * property - * Return: 0 if OK, -ENODEV if an unknown bootmeth or property is - * provided, -ENOENT if there are no bootmeth devices + * Return: 0 if OK, -EINVAL if an unknown property or invalid value is + * provided */ int (*set_property)(struct udevice *dev, const char *property, const char *value); diff --git a/include/extlinux.h b/include/extlinux.h index 6747fe01dda..f97164954cc 100644 --- a/include/extlinux.h +++ b/include/extlinux.h @@ -7,6 +7,8 @@ #ifndef __extlinux_h #define __extlinux_h
+#include <pxe_utils.h> + #define EXTLINUX_FNAME "extlinux/extlinux.conf"
/** @@ -20,4 +22,31 @@ struct extlinux_info { struct bootflow *bflow; };
+/** + * struct extlinux_plat - locate state for this bootmeth + * + * @use_falllback: true to boot with the fallback option + * @ctx: holds the PXE context, if it should be saved + * @info: information used for the getfile() method + */ +struct extlinux_plat { + bool use_fallback; + struct pxe_context ctx; + struct extlinux_info info; +}; + +/** + * extlinux_set_property() - set an extlinux property + * + * This allows the setting of bootmeth-specific properties to enable + * automated finer-grained control of the boot process + * + * @name: String containing the name of the relevant boot method + * @property: String containing the name of the property to set + * @value: String containing the value to be set for the specified property + * Return: 0 if OK, -EINVAL if an unknown property or invalid value is provided + */ +int extlinux_set_property(struct udevice *dev, const char *property, + const char *value); + #endif

Provide this feature in PXE, so that it matches extlinux. Use plat data for this, just like extlinux.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/bootmeth_pxe.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index f2b9ffaae89..6b3cb3c4b91 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -139,16 +139,16 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow,
static int extlinux_pxe_boot(struct udevice *dev, struct bootflow *bflow) { + struct extlinux_plat *plat = dev_get_plat(dev); struct pxe_context *ctx = dev_get_priv(dev); - struct extlinux_info info; ulong addr; int ret;
addr = map_to_sysmem(bflow->buf); - info.dev = dev; - info.bflow = bflow; - ret = pxe_setup_ctx(ctx, extlinux_pxe_getfile, &info, false, - bflow->subdir, false, false, bflow); + plat->info.dev = dev; + plat->info.bflow = bflow; + ret = pxe_setup_ctx(ctx, extlinux_pxe_getfile, &plat->info, false, + bflow->subdir, false, plat->use_fallback, bflow); if (ret) return log_msg_ret("ctx", -EINVAL);
@@ -174,6 +174,7 @@ static struct bootmeth_ops extlinux_bootmeth_pxe_ops = { .read_bootflow = extlinux_pxe_read_bootflow, .read_file = extlinux_pxe_read_file, .boot = extlinux_pxe_boot, + .set_property = extlinux_set_property, };
static const struct udevice_id extlinux_bootmeth_pxe_ids[] = { @@ -188,4 +189,5 @@ U_BOOT_DRIVER(bootmeth_zpxe) = { .ops = &extlinux_bootmeth_pxe_ops, .bind = extlinux_bootmeth_pxe_bind, .priv_auto = sizeof(struct pxe_context), + .plat_auto = sizeof(struct extlinux_plat) };

Since this driver's plat-data already contains a PXE context, use that. Drop the priv-data. Use the extlinux_info which is in there, as well.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/bootmeth_pxe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 6b3cb3c4b91..a9608edcef9 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -140,7 +140,7 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, static int extlinux_pxe_boot(struct udevice *dev, struct bootflow *bflow) { struct extlinux_plat *plat = dev_get_plat(dev); - struct pxe_context *ctx = dev_get_priv(dev); + struct pxe_context *ctx = &plat->ctx; ulong addr; int ret;
@@ -188,6 +188,5 @@ U_BOOT_DRIVER(bootmeth_zpxe) = { .of_match = extlinux_bootmeth_pxe_ids, .ops = &extlinux_bootmeth_pxe_ops, .bind = extlinux_bootmeth_pxe_bind, - .priv_auto = sizeof(struct pxe_context), .plat_auto = sizeof(struct extlinux_plat) };

The extlinux and PXE code for booting is almost the same. Move it into the common file so it is easier to keep it in sync.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/bootmeth_extlinux.c | 24 +++--------------------- boot/bootmeth_pxe.c | 19 +------------------ boot/ext_pxe_common.c | 24 ++++++++++++++++++++++++ include/extlinux.h | 11 +++++++++++ 4 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c index ce11077ee35..df5b5ea7bf4 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -138,27 +138,9 @@ static int extlinux_read_bootflow(struct udevice *dev, struct bootflow *bflow) return 0; }
-static int extlinux_boot(struct udevice *dev, struct bootflow *bflow) +static int extlinux_local_boot(struct udevice *dev, struct bootflow *bflow) { - struct extlinux_plat *plat = dev_get_plat(dev); - ulong addr; - int ret; - - addr = map_to_sysmem(bflow->buf); - - plat->info.dev = dev; - plat->info.bflow = bflow; - - ret = pxe_setup_ctx(&plat->ctx, extlinux_getfile, &plat->info, true, - bflow->fname, false, plat->use_fallback, bflow); - if (ret) - return log_msg_ret("ctx", -EINVAL); - - ret = pxe_process(&plat->ctx, addr, false); - if (ret) - return log_msg_ret("bread", -EINVAL); - - return 0; + return extlinux_boot(dev, bflow, extlinux_getfile); }
static int extlinux_bootmeth_bind(struct udevice *dev) @@ -176,7 +158,7 @@ static struct bootmeth_ops extlinux_bootmeth_ops = { .check = extlinux_check, .read_bootflow = extlinux_read_bootflow, .read_file = bootmeth_common_read_file, - .boot = extlinux_boot, + .boot = extlinux_local_boot, .set_property = extlinux_set_property, };
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index a9608edcef9..6ecf81d7878 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -139,24 +139,7 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow,
static int extlinux_pxe_boot(struct udevice *dev, struct bootflow *bflow) { - struct extlinux_plat *plat = dev_get_plat(dev); - struct pxe_context *ctx = &plat->ctx; - ulong addr; - int ret; - - addr = map_to_sysmem(bflow->buf); - plat->info.dev = dev; - plat->info.bflow = bflow; - ret = pxe_setup_ctx(ctx, extlinux_pxe_getfile, &plat->info, false, - bflow->subdir, false, plat->use_fallback, bflow); - if (ret) - return log_msg_ret("ctx", -EINVAL); - - ret = pxe_process(ctx, addr, false); - if (ret) - return log_msg_ret("bread", -EINVAL); - - return 0; + return extlinux_boot(dev, bflow, extlinux_pxe_getfile); }
static int extlinux_bootmeth_pxe_bind(struct udevice *dev) diff --git a/boot/ext_pxe_common.c b/boot/ext_pxe_common.c index e42865b84f5..7b9c41b5f77 100644 --- a/boot/ext_pxe_common.c +++ b/boot/ext_pxe_common.c @@ -74,3 +74,27 @@ int extlinux_set_property(struct udevice *dev, const char *property,
return 0; } + +int extlinux_boot(struct udevice *dev, struct bootflow *bflow, + pxe_getfile_func getfile) +{ + struct extlinux_plat *plat = dev_get_plat(dev); + ulong addr; + int ret; + + addr = map_to_sysmem(bflow->buf); + + plat->info.dev = dev; + plat->info.bflow = bflow; + + ret = pxe_setup_ctx(&plat->ctx, getfile, &plat->info, true, + bflow->fname, false, plat->use_fallback, bflow); + if (ret) + return log_msg_ret("ctx", -EINVAL); + + ret = pxe_process(&plat->ctx, addr, false); + if (ret) + return log_msg_ret("bread", -EINVAL); + + return 0; +} diff --git a/include/extlinux.h b/include/extlinux.h index f97164954cc..69781e666c3 100644 --- a/include/extlinux.h +++ b/include/extlinux.h @@ -49,4 +49,15 @@ struct extlinux_plat { int extlinux_set_property(struct udevice *dev, const char *property, const char *value);
+/** + * extlinux_boot() - Boot a bootflow + * + * @dev: bootmeth device + * @bflow: Bootflow to boot + * @getfile: Function to use to read files + * Return: 0 if OK, -ve error code on failure + */ +int extlinux_boot(struct udevice *dev, struct bootflow *bflow, + pxe_getfile_func getfile); + #endif

It is useful to be able to inspect things before the OS is actually booted, perhaps to check that all is well or to adjust the kernel command-line. Implement the 'read_all()' method to allow this.
Provide a simple test to check that the images are found.
For now it is not possible to actually continue the uninterrupted boot, without re-reading all the images.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/bootmeth_extlinux.c | 10 ++++++++++ boot/bootmeth_pxe.c | 10 ++++++++++ boot/ext_pxe_common.c | 23 +++++++++++++++++++-- include/extlinux.h | 11 ++++++++++ test/boot/bootflow.c | 43 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 2 deletions(-)
diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c index df5b5ea7bf4..14c13971852 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -143,6 +143,13 @@ static int extlinux_local_boot(struct udevice *dev, struct bootflow *bflow) return extlinux_boot(dev, bflow, extlinux_getfile); }
+#if CONFIG_IS_ENABLED(BOOTSTD_FULL) +static int extlinux_local_read_all(struct udevice *dev, struct bootflow *bflow) +{ + return extlinux_read_all(dev, bflow, extlinux_getfile); +} +#endif + static int extlinux_bootmeth_bind(struct udevice *dev) { struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); @@ -160,6 +167,9 @@ static struct bootmeth_ops extlinux_bootmeth_ops = { .read_file = bootmeth_common_read_file, .boot = extlinux_local_boot, .set_property = extlinux_set_property, +#if CONFIG_IS_ENABLED(BOOTSTD_FULL) + .read_all = extlinux_local_read_all, +#endif };
static const struct udevice_id extlinux_bootmeth_ids[] = { diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 6ecf81d7878..a4dd48a7010 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -142,6 +142,13 @@ static int extlinux_pxe_boot(struct udevice *dev, struct bootflow *bflow) return extlinux_boot(dev, bflow, extlinux_pxe_getfile); }
+#if CONFIG_IS_ENABLED(BOOTSTD_FULL) +static int extlinux_pxe_read_all(struct udevice *dev, struct bootflow *bflow) +{ + return extlinux_read_all(dev, bflow, extlinux_pxe_getfile); +} +#endif + static int extlinux_bootmeth_pxe_bind(struct udevice *dev) { struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); @@ -158,6 +165,9 @@ static struct bootmeth_ops extlinux_bootmeth_pxe_ops = { .read_file = extlinux_pxe_read_file, .boot = extlinux_pxe_boot, .set_property = extlinux_set_property, +#if CONFIG_IS_ENABLED(BOOTSTD_FULL) + .read_all = extlinux_pxe_read_all, +#endif };
static const struct udevice_id extlinux_bootmeth_pxe_ids[] = { diff --git a/boot/ext_pxe_common.c b/boot/ext_pxe_common.c index 7b9c41b5f77..c7f690dee17 100644 --- a/boot/ext_pxe_common.c +++ b/boot/ext_pxe_common.c @@ -75,8 +75,8 @@ int extlinux_set_property(struct udevice *dev, const char *property, return 0; }
-int extlinux_boot(struct udevice *dev, struct bootflow *bflow, - pxe_getfile_func getfile) +static int extlinux_process(struct udevice *dev, struct bootflow *bflow, + pxe_getfile_func getfile, bool no_boot) { struct extlinux_plat *plat = dev_get_plat(dev); ulong addr; @@ -91,6 +91,7 @@ int extlinux_boot(struct udevice *dev, struct bootflow *bflow, bflow->fname, false, plat->use_fallback, bflow); if (ret) return log_msg_ret("ctx", -EINVAL); + plat->ctx.no_boot = no_boot;
ret = pxe_process(&plat->ctx, addr, false); if (ret) @@ -98,3 +99,21 @@ int extlinux_boot(struct udevice *dev, struct bootflow *bflow,
return 0; } + +int extlinux_boot(struct udevice *dev, struct bootflow *bflow, + pxe_getfile_func getfile) +{ + return extlinux_process(dev, bflow, getfile, false); +} + +int extlinux_read_all(struct udevice *dev, struct bootflow *bflow, + pxe_getfile_func getfile) +{ + int ret; + + ret = extlinux_process(dev, bflow, getfile, true); + if (ret) + return log_msg_ret("era", -EINVAL); + + return 0; +} diff --git a/include/extlinux.h b/include/extlinux.h index 69781e666c3..ab93761c54c 100644 --- a/include/extlinux.h +++ b/include/extlinux.h @@ -60,4 +60,15 @@ int extlinux_set_property(struct udevice *dev, const char *property, int extlinux_boot(struct udevice *dev, struct bootflow *bflow, pxe_getfile_func getfile);
+/** + * extlinux_read_all() - read all files for a bootflow + * + * @dev: Bootmethod device to boot + * @bflow: Bootflow to read + * @getfile: Function to use to read files + * Return: 0 if OK, -EIO on I/O error, other -ve on other error + */ +int extlinux_read_all(struct udevice *dev, struct bootflow *bflow, + pxe_getfile_func getfile); + #endif diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 749d79d3295..4671bd7ab1f 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -1410,3 +1410,46 @@ static int bootstd_adhoc(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootstd_adhoc, UTF_CONSOLE); + +/* Check scanning extlinux, adjusting cmdline and booting */ +static int bootflow_scan_extlinux(struct unit_test_state *uts) +{ + const struct bootflow_img *img; + struct bootstd_priv *std; + struct bootflow *bflow; + + ut_assertok(run_command("bootflow scan", 0)); + ut_assert_console_end(); + ut_assertok(bootstd_get_priv(&std)); + + ut_asserteq(1, std->bootflows.count); + + bflow = alist_getw(&std->bootflows, 0, struct bootflow); + std->cur_bootflow = bflow; + + /* read all the images, but don't actually boot */ + ut_assertok(inject_response(uts)); + ut_assertok(bootflow_read_all(bflow)); + + /* check that the command line is now present */ + ut_asserteq_str( + "ro root=UUID=9732b35b-4cd5-458b-9b91-80f7047e0b8a rhgb quiet LANG=en_US.UTF-8 cma=192MB cma=256MB", + bflow->cmdline); + + ut_asserteq(3, bflow->images.count); + + /* check each image */ + img = alist_get(&bflow->images, 0, struct bootflow_img); + ut_asserteq_strn("# extlinux.conf", map_sysmem(img->addr, 0)); + + img = alist_get(&bflow->images, 1, struct bootflow_img); + ut_asserteq(IH_TYPE_KERNEL, img->type); + ut_asserteq(0x1000000, img->addr); /* kernel_addr_r */ + + img = alist_get(&bflow->images, 2, struct bootflow_img); + ut_asserteq(IH_TYPE_RAMDISK, img->type); + ut_asserteq(0x2000000, img->addr); /* ramdisk_addr_r */ + + return 0; +} +BOOTSTD_TEST(bootflow_scan_extlinux, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);

Move processing of the FDT so that it happens before booting. Add a test to check that the FDT is now visible.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/pxe_utils.c | 22 +++++++++++++--------- test/boot/bootflow.c | 6 +++++- 2 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 7106e532e03..ca91bff7e51 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -578,26 +578,23 @@ static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label, * @initrd_filesize: String containing initrd size (only used if * @initrd_addr_str) * @initrd_str: initrd string to process (only used if @initrd_addr_str) + * @conf_fdt: string containing the FDT address * 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 *initrd_filesize, char *initrd_str, + const char *conf_fdt) { struct bootm_info bmi; ulong kernel_addr_r; + int ret = 0; void *buf; - int ret;
bootm_init(&bmi);
- bmi.conf_fdt = env_get("fdt_addr_r"); - - ret = label_process_fdt(ctx, label, kernel_addr, &bmi.conf_fdt); - if (ret) - return ret; - + bmi.conf_fdt = conf_fdt; bmi.addr_img = kernel_addr; bootm_x86_set(&bmi, bzimage_addr, hextoul(kernel_addr, NULL));
@@ -684,6 +681,8 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) char mac_str[29] = ""; char ip_str[68] = ""; char *fit_addr = NULL; + const char *conf_fdt; + int ret;
label_print(label);
@@ -788,11 +787,16 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) printf("append: %s\n", finalbootargs); }
+ conf_fdt = env_get("fdt_addr_r"); + ret = label_process_fdt(ctx, label, kernel_addr, &conf_fdt); + if (ret) + return ret; + if (ctx->no_boot) return 0;
label_run_boot(ctx, label, kernel_addr, initrd_addr_str, - initrd_filesize, initrd_str); + initrd_filesize, initrd_str, conf_fdt); /* ignore the error value since we are going to fail anyway */
cleanup: diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 4671bd7ab1f..cbd65cb3eb5 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -1436,7 +1436,7 @@ static int bootflow_scan_extlinux(struct unit_test_state *uts) "ro root=UUID=9732b35b-4cd5-458b-9b91-80f7047e0b8a rhgb quiet LANG=en_US.UTF-8 cma=192MB cma=256MB", bflow->cmdline);
- ut_asserteq(3, bflow->images.count); + ut_asserteq(4, bflow->images.count);
/* check each image */ img = alist_get(&bflow->images, 0, struct bootflow_img); @@ -1450,6 +1450,10 @@ static int bootflow_scan_extlinux(struct unit_test_state *uts) ut_asserteq(IH_TYPE_RAMDISK, img->type); ut_asserteq(0x2000000, img->addr); /* ramdisk_addr_r */
+ img = alist_get(&bflow->images, 3, struct bootflow_img); + ut_asserteq(IH_TYPE_FLATDT, img->type); + ut_asserteq(0xc00000, img->addr); /* fdt_addr_r */ + return 0; } BOOTSTD_TEST(bootflow_scan_extlinux, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);

Move processing of a missing FDT so that it happens before booting, so we can see the result in the bootflow.
Signed-off-by: Simon Glass sjg@chromium.org
pxe: Deal with using the control FDT
Move selection of the control FDT so that it happens before booting, so we can see the result in the bootflow.
---
boot/pxe_utils.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-)
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index ca91bff7e51..99c968a1202 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -605,27 +605,9 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, hextoul(initrd_filesize, NULL)); }
- if (!bmi.conf_fdt) { - if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { - if (strcmp("-", label->fdt)) - bmi.conf_fdt = env_get("fdt_addr"); - } else { - 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 { - bmi.conf_fdt = env_get("fdtcontroladdr"); - } - } - /* Try bootm for legacy and FIT format image */ if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID && IS_ENABLED(CONFIG_CMD_BOOTM)) { @@ -792,6 +774,34 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) if (ret) return ret;
+ if (!conf_fdt) { + if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { + if (strcmp("-", label->fdt)) + conf_fdt = env_get("fdt_addr"); + } else { + conf_fdt = env_get("fdt_addr"); + } + } + + if (!conf_fdt) { + ulong kernel_addr_r; + void *buf; + + kernel_addr_r = genimg_get_kernel_addr(kernel_addr); + buf = map_sysmem(kernel_addr_r, 0); + if (genimg_get_format(buf) != IMAGE_FORMAT_FIT) { + if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { + if (strcmp("-", label->fdt)) + conf_fdt = env_get("fdtcontroladdr"); + } else { + conf_fdt = env_get("fdtcontroladdr"); + } + } + unmap_sysmem(buf); + } + if (ctx->bflow) + ctx->bflow->fdt_addr = hextoul(conf_fdt, NULL); + if (ctx->no_boot) return 0;

It is useful to be able to select a bootflow and read its images, without actually doing the boot. This allows adjusting the bootargs, for example.
Provide support for this in the pxe_utils module, by adding a 'probe' method which selects a label and saves its settings, so it can be booted later, if desired.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/pxe_utils.c | 72 +++++++++++++++++++++++++++++++++++++++++---- include/pxe_utils.h | 41 ++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 5 deletions(-)
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 99c968a1202..01fff350f1b 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -802,8 +802,31 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) if (ctx->bflow) ctx->bflow->fdt_addr = hextoul(conf_fdt, NULL);
- if (ctx->no_boot) + if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && ctx->no_boot) { + ctx->label = label; + ctx->kernel_addr = strdup(kernel_addr); + if (initrd_addr_str) { + ctx->initrd_addr_str = strdup(initrd_addr_str); + ctx->initrd_filesize = strdup(initrd_filesize); + ctx->initrd_str = strdup(initrd_str); + } + ctx->conf_fdt = strdup(conf_fdt); + log_debug("Saving label '%s':\n", label->name); + log_debug("- kernel_addr '%s' conf_fdt '%s'\n", + ctx->kernel_addr, ctx->conf_fdt); + if (initrd_addr_str) { + log_debug("- initrd addr '%s' filesize '%s' str '%s'\n", + ctx->initrd_addr_str, ctx->initrd_filesize, + ctx->initrd_str); + } + if (!ctx->kernel_addr || !ctx->conf_fdt || + (initrd_addr_str && (!ctx->initrd_addr_str || + !ctx->initrd_filesize || !ctx->initrd_str))) { + printf("malloc fail (saving label)\n"); + return 1; + } return 0; + }
label_run_boot(ctx, label, kernel_addr, initrd_addr_str, initrd_filesize, initrd_str, conf_fdt); @@ -1695,18 +1718,29 @@ void pxe_destroy_ctx(struct pxe_context *ctx) free(ctx->bootdir); }
-int pxe_process(struct pxe_context *ctx, ulong pxefile_addr_r, bool prompt) +struct pxe_menu *pxe_prepare(struct pxe_context *ctx, ulong pxefile_addr_r, + bool prompt) { struct pxe_menu *cfg;
cfg = parse_pxefile(ctx, pxefile_addr_r); if (!cfg) { printf("Error parsing config file\n"); - return 1; + return NULL; }
- if (prompt) - cfg->prompt = 1; + cfg->prompt = prompt; + + return cfg; +} + +int pxe_process(struct pxe_context *ctx, ulong pxefile_addr_r, bool prompt) +{ + struct pxe_menu *cfg; + + cfg = pxe_prepare(ctx, pxefile_addr_r, prompt); + if (!cfg) + return 1;
handle_pxe_menu(ctx, cfg);
@@ -1714,3 +1748,31 @@ int pxe_process(struct pxe_context *ctx, ulong pxefile_addr_r, bool prompt)
return 0; } + +int pxe_probe(struct pxe_context *ctx, ulong pxefile_addr_r, bool prompt) +{ + ctx->cfg = pxe_prepare(ctx, pxefile_addr_r, prompt); + if (!ctx->cfg) + return -EINVAL; + ctx->no_boot = true; + + handle_pxe_menu(ctx, ctx->cfg); + + return 0; +} + +int pxe_do_boot(struct pxe_context *ctx) +{ + int ret; + + if (!ctx->label) + return log_msg_ret("pxb", -ENOENT); + + ret = label_run_boot(ctx, ctx->label, ctx->kernel_addr, + ctx->initrd_addr_str, ctx->initrd_filesize, + ctx->initrd_str, ctx->conf_fdt); + if (ret) + return log_msg_ret("lrb", ret); + + return 0; +} diff --git a/include/pxe_utils.h b/include/pxe_utils.h index beadd221475..6425e349d19 100644 --- a/include/pxe_utils.h +++ b/include/pxe_utils.h @@ -111,6 +111,16 @@ typedef int (*pxe_getfile_func)(struct pxe_context *ctx, const char *file_path, * "default" option as default * @no_boot: Stop show of actually booting and just return * @bflow: Bootflow being booted, or NULL if none (must be valid if @no_boot) + * @cfg: PXE menu (NULL if not yet probed) + * + * The following are only used when probing for a label + * @label: Label to process + * @kernel_addr: String containing kernel address (cannot be NULL) + * @initrd_addr_str: String containing initaddr 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) + * @conf_fdt: string containing the FDT address */ struct pxe_context { /** @@ -133,6 +143,15 @@ struct pxe_context { bool use_fallback; bool no_boot; struct bootflow *bflow; + struct pxe_menu *cfg; + + /* information on the selected label to boot */ + struct pxe_label *label; + char *kernel_addr; + char *initrd_addr_str; + char *initrd_filesize; + char *initrd_str; + char *conf_fdt; };
/** @@ -283,4 +302,26 @@ int pxe_get_file_size(ulong *sizep); */ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep, bool use_ipv6);
+/** + * pxe_probe() - Process a PXE file to find the label to boot + * + * This fills in the label, etc. fields in @ctx, assuming it funds something to + * boot. Then pxe_do_boot() can be called to boot it. + * + * @ctx: PXE context created with pxe_setup_ctx() + * @pxefile_addr_r: Address to load file + * @prompt: Force a prompt for the user + * Return: 0 if OK, -ve on error + */ +int pxe_probe(struct pxe_context *ctx, ulong pxefile_addr_r, bool prompt); + +/** + * pxe_do_boot() - Boot the selected label + * + * This boots the label discovered by pxe_probe() + * + * Return: Does not return, on success, otherwise returns a -ve error code + */ +int pxe_do_boot(struct pxe_context *ctx); + #endif /* __PXE_UTILS_H */

Add a new extlinux_setup() function which sets things up so that the bootflow can either be booted, or just probed.
Provide a readall() method so that images can be read into memory, without booting the OS. Adjust the boot() method so that it can boot, after any changes have been made by the user.
Update the test to change the bootargs and check that they are booted with the changes intact.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/ext_pxe_common.c | 47 ++++++++++++++++++++++++++++--------------- test/boot/bootflow.c | 24 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 16 deletions(-)
diff --git a/boot/ext_pxe_common.c b/boot/ext_pxe_common.c index c7f690dee17..7fdd3d98834 100644 --- a/boot/ext_pxe_common.c +++ b/boot/ext_pxe_common.c @@ -75,27 +75,19 @@ int extlinux_set_property(struct udevice *dev, const char *property, return 0; }
-static int extlinux_process(struct udevice *dev, struct bootflow *bflow, - pxe_getfile_func getfile, bool no_boot) +static int extlinux_setup(struct udevice *dev, struct bootflow *bflow, + pxe_getfile_func getfile, struct pxe_context *ctx) { struct extlinux_plat *plat = dev_get_plat(dev); - ulong addr; int ret;
- addr = map_to_sysmem(bflow->buf); - plat->info.dev = dev; plat->info.bflow = bflow;
- ret = pxe_setup_ctx(&plat->ctx, getfile, &plat->info, true, - bflow->fname, false, plat->use_fallback, bflow); - if (ret) - return log_msg_ret("ctx", -EINVAL); - plat->ctx.no_boot = no_boot; - - ret = pxe_process(&plat->ctx, addr, false); + ret = pxe_setup_ctx(ctx, getfile, &plat->info, true, bflow->fname, + false, plat->use_fallback, bflow); if (ret) - return log_msg_ret("bread", -EINVAL); + return log_msg_ret("ctx", ret);
return 0; } @@ -103,17 +95,40 @@ static int extlinux_process(struct udevice *dev, struct bootflow *bflow, int extlinux_boot(struct udevice *dev, struct bootflow *bflow, pxe_getfile_func getfile) { - return extlinux_process(dev, bflow, getfile, false); + struct extlinux_plat *plat = dev_get_plat(dev); + ulong addr; + int ret; + + /* if we have already selected a label, just boot it */ + if (plat->ctx.label) { + ret = pxe_do_boot(&plat->ctx); + } else { + ret = extlinux_setup(dev, bflow, getfile, &plat->ctx); + if (ret) + return log_msg_ret("elb", ret); + addr = map_to_sysmem(bflow->buf); + ret = pxe_process(&plat->ctx, addr, false); + } + if (ret) + return log_msg_ret("elb", -EFAULT); + + return 0; }
int extlinux_read_all(struct udevice *dev, struct bootflow *bflow, pxe_getfile_func getfile) { + struct extlinux_plat *plat = dev_get_plat(dev); + ulong addr; int ret;
- ret = extlinux_process(dev, bflow, getfile, true); + ret = extlinux_setup(dev, bflow, getfile, &plat->ctx); + if (ret) + return log_msg_ret("era", ret); + addr = map_to_sysmem(bflow->buf); + ret = pxe_probe(&plat->ctx, addr, false); if (ret) - return log_msg_ret("era", -EINVAL); + return log_msg_ret("elb", -EFAULT);
return 0; } diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index cbd65cb3eb5..4d21054e10a 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -21,6 +21,7 @@ #endif #include <dm/device-internal.h> #include <dm/lists.h> +#include <linux/libfdt.h> #include <test/suites.h> #include <test/ut.h> #include "bootstd_common.h" @@ -1417,6 +1418,9 @@ static int bootflow_scan_extlinux(struct unit_test_state *uts) const struct bootflow_img *img; struct bootstd_priv *std; struct bootflow *bflow; + const char *cline; + const void *fdt; + int node;
ut_assertok(run_command("bootflow scan", 0)); ut_assert_console_end(); @@ -1454,6 +1458,26 @@ static int bootflow_scan_extlinux(struct unit_test_state *uts) ut_asserteq(IH_TYPE_FLATDT, img->type); ut_asserteq(0xc00000, img->addr); /* fdt_addr_r */
+ /* adjust the command line */ + ut_assertok(run_command("bootflow cmdline set root /dev/mmc2", 0)); + + ut_asserteq(-EFAULT, bootflow_boot(bflow)); + ut_assert_skip_to_line("sandbox: continuing, as we cannot run Linux"); + ut_assert_console_end(); + + /* check that the images were not loaded again */ + ut_asserteq(4, bflow->images.count); + + /* check the cmdline in the booted FDT */ + fdt = working_fdt; + node = fdt_subnode_offset(fdt, 0, "chosen"); + ut_assert(node > 0); + cline = fdt_getprop(fdt, node, "bootargs", 0); + ut_assertnonnull(cline); + ut_asserteq_str( + "ro root=/dev/mmc2 rhgb quiet LANG=en_US.UTF-8 cma=192MB cma=256MB", + bflow->cmdline); + return 0; } BOOTSTD_TEST(bootflow_scan_extlinux, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);

On Tue, Nov 19, 2024 at 06:18:05AM -0700, Simon Glass wrote:
This series implements read_all() so that it is possible to read all the files relating to a bootflow, make adjustments and then boot.
Unfortunately quite a few things stand in the way, so this series finishes off several pending items: zboot without CONFIG_CMDLINE, required support in pxe_utils and the differing code in the extlinux and PXE bootmeths. There is very little new code, but quite a lot of refactoring.
The bootm, booti and bootz commands have all been refactored previously, so that they can operate without needing CONFIG_CMDLINE to be enabled. At the, time, zboot was left alone, since it is x86-specific and a bit more trouble.
This series adds a programatic API for zboot and uses the forthcoming bootstd 'image list' to collect information from an extlinux file. It is therefore possible to parse the file, load the resulting images and then examine/adjust the resulting bootflow, before booting.
The addition of options to extlinux resulted in the PXE and extlinux bootmeth having slightly different features. This is tidied up in this series, with common functions for both. This allows the same features (loading images as a separate step) to be provided for PXE.
This doesn't apply cleanly to -next and doesn't say what other series it depends on.

Hi Tom,
On Tue, 19 Nov 2024 at 09:27, Tom Rini trini@konsulko.com wrote:
On Tue, Nov 19, 2024 at 06:18:05AM -0700, Simon Glass wrote:
This series implements read_all() so that it is possible to read all the files relating to a bootflow, make adjustments and then boot.
Unfortunately quite a few things stand in the way, so this series finishes off several pending items: zboot without CONFIG_CMDLINE, required support in pxe_utils and the differing code in the extlinux and PXE bootmeths. There is very little new code, but quite a lot of refactoring.
The bootm, booti and bootz commands have all been refactored previously, so that they can operate without needing CONFIG_CMDLINE to be enabled. At the, time, zboot was left alone, since it is x86-specific and a bit more trouble.
This series adds a programatic API for zboot and uses the forthcoming bootstd 'image list' to collect information from an extlinux file. It is therefore possible to parse the file, load the resulting images and then examine/adjust the resulting bootflow, before booting.
The addition of options to extlinux resulted in the PXE and extlinux bootmeth having slightly different features. This is tidied up in this series, with common functions for both. This allows the same features (loading images as a separate step) to be provided for PXE.
This doesn't apply cleanly to -next and doesn't say what other series it depends on.
Yes, that is a bit vague, sorry. The 'forthcoming bootstd image list' is the dependency.
Regards, Simon

On 19.11.24 14:18, Simon Glass wrote:
This series implements read_all() so that it is possible to read all the files relating to a bootflow, make adjustments and then boot.
Unfortunately quite a few things stand in the way, so this series finishes off several pending items: zboot without CONFIG_CMDLINE, required support in pxe_utils and the differing code in the extlinux and PXE bootmeths. There is very little new code, but quite a lot of refactoring.
The bootm, booti and bootz commands have all been refactored previously, so that they can operate without needing CONFIG_CMDLINE to be enabled. At the, time, zboot was left alone, since it is x86-specific and a bit more trouble.
This series adds a programatic API for zboot and uses the forthcoming bootstd 'image list' to collect information from an extlinux file. It is therefore possible to parse the file, load the resulting images and then examine/adjust the resulting bootflow, before booting.
The addition of options to extlinux resulted in the PXE and extlinux bootmeth having slightly different features. This is tidied up in this series, with common functions for both. This allows the same features (loading images as a separate step) to be provided for PXE.
The biggest problem I see currently with PXE in U-Boot is:
eth_bootdev_hunt() invokes dhcp_run() which may lead to actually downloading and booting a file (assuming autostart=yes).
We should only check that a network device exists and can be probed. Maybe check that the medium is attached when probing. But actually reading a file should be left to one of the different boot methods that can make use of the boot device (PXE, HTTP-Boot, ...).
But I cannot see a fix for net/eth_bootdev.c in this series.
Best regards
Heinrich
Simon Glass (39): x86: Make do_zboot_states() static x86: Rename zboot_run() to zboot_run_args() x86: Drop duplicate definition of zimage_dump() x86: Move x86 zboot state into struct bootm_info x86: Rename state to bmi x86: Move the bootm state for zimage into cmd/ bootstd: Correct display of kernel version x86: Drop the unnecessary base_ptr argument to zboot_dump() boot: Split pxe label_boot() into two parts boot: Split pxe label_run_boot() into two parts boot: Pass just the FDT argument to label_process_fdt() bootm: Allow building bootm.c without CONFIG_SYS_BOOTM_LEN boot: pxe: Use bootm_...() functions where possible boot: pxe: Refactor label_run_boot() to avoid cmdline net: Keep the bootstage functions together net: Tidy up the comments to parse_args() net: Simplify parse_args() net: Return the load address from parse_args() net: Return the address and size from parse_addr_size() net: Return the size from parse_args() net: Refactor part of netboot_common() into a function net: Drop #ifdef in parse_args() net: Provide a function to run network operations boot: Avoid using the cmdline in bootmeth_pxe and pxe cmd pxe: Drop the cmdline parameter pxe: Record the bootflow in the PXE context pxe: Allow skipping the boot test: Update bootm test to restore silent_console bootmeth_extlinux: Move extlinux_info into plat bootmeth_extlinux: Move pxe_context into plat bootmeth: Refactor to put options in a common file bootmeth_pxe: Implement the fallback option bootmeth_pxe: Drop the driver-private data bootmeth_extlinux: Move boot code into common file bootstd: Update extlinux and pxe to allow boot interruption pxe: Collect the FDT in the bootflow pxe: Deal with a missing FDT in the bootflow pxe_utils: Refactor to separate reading from booting bootmeth_extlinux: Refactor extlinux to split boot
arch/x86/include/asm/zimage.h | 57 +--- arch/x86/lib/zimage.c | 102 ++++--- boot/Makefile | 6 +- boot/bootm.c | 8 +- boot/bootmeth_cros.c | 6 +- boot/bootmeth_extlinux.c | 97 +------ boot/bootmeth_pxe.c | 48 ++-- boot/ext_pxe_common.c | 134 +++++++++ boot/pxe_utils.c | 507 +++++++++++++++++++++------------- cmd/bootflow.c | 8 +- cmd/net.c | 92 +++--- cmd/pxe.c | 30 +- cmd/sysboot.c | 4 +- cmd/x86/zboot.c | 33 ++- include/bootm.h | 63 ++++- include/bootmeth.h | 8 +- include/extlinux.h | 52 +++- include/net-common.h | 30 ++ include/pxe_utils.h | 56 +++- net/net.c | 44 +++ test/boot/bootflow.c | 71 +++++ test/boot/bootm.c | 7 + 22 files changed, 960 insertions(+), 503 deletions(-) create mode 100644 boot/ext_pxe_common.c

Hi Heinrich,
On Tue, 19 Nov 2024 at 10:12, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 19.11.24 14:18, Simon Glass wrote:
This series implements read_all() so that it is possible to read all the files relating to a bootflow, make adjustments and then boot.
Unfortunately quite a few things stand in the way, so this series finishes off several pending items: zboot without CONFIG_CMDLINE, required support in pxe_utils and the differing code in the extlinux and PXE bootmeths. There is very little new code, but quite a lot of refactoring.
The bootm, booti and bootz commands have all been refactored previously, so that they can operate without needing CONFIG_CMDLINE to be enabled. At the, time, zboot was left alone, since it is x86-specific and a bit more trouble.
This series adds a programatic API for zboot and uses the forthcoming bootstd 'image list' to collect information from an extlinux file. It is therefore possible to parse the file, load the resulting images and then examine/adjust the resulting bootflow, before booting.
The addition of options to extlinux resulted in the PXE and extlinux bootmeth having slightly different features. This is tidied up in this series, with common functions for both. This allows the same features (loading images as a separate step) to be provided for PXE.
The biggest problem I see currently with PXE in U-Boot is:
eth_bootdev_hunt() invokes dhcp_run() which may lead to actually downloading and booting a file (assuming autostart=yes).
We should only check that a network device exists and can be probed. Maybe check that the medium is attached when probing. But actually reading a file should be left to one of the different boot methods that can make use of the boot device (PXE, HTTP-Boot, ...).
But I cannot see a fix for net/eth_bootdev.c in this series.
No, it doesn't include anything for that.
We could maintain a flag to indicate whether the net dev has had DHCP run on it, then make sure only to do it once.
Regards, Simon
participants (5)
-
Heinrich Schuchardt
-
Ilias Apalodimas
-
Quentin Schulz
-
Simon Glass
-
Tom Rini