[PATCH v2 00/41] 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.
Changes in v2: - Split out strlcpy() change into new patch - Move strlcpy() change into an earlier patch - Fix 'initaddr' typo' - Rebase on earlier change - Add new patch to simplify the code reading fdtcontroladdr and fdt_addr
Simon Glass (41): 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: Use strlcpy() in label_boot() 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 pxe_utils: Simplify default fdt in label_run_boot() 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, 957 insertions(+), 506 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 ---
(no changes since v1)
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 ---
(no changes since v1)
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 ---
(no changes since v1)
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 ---
(no changes since v1)
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 ---
(no changes since v1)
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 ---
(no changes since v1)
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 ---
(no changes since v1)
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 ---
(no changes since v1)
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 recommended instead of strncpy() since it always terminates the string.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Split out strlcpy() change into new patch
boot/pxe_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 82f217aaf86..e96935896a9 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -558,7 +558,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) }
if (label->append) - strncpy(bootargs, label->append, sizeof(bootargs)); + strlcpy(bootargs, label->append, sizeof(bootargs));
strcat(bootargs, ip_str); strcat(bootargs, mac_str);

This function is far too long. Split out the part which builds and runs the bootm/i/z commands into its own function.
Add a function comment for the new label_run_boot() function.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Quentin Schulz quentin.schulz@cherry.de ---
Changes in v2: - Move strlcpy() change into an earlier patch - Fix 'initaddr' typo'
boot/pxe_utils.c | 284 ++++++++++++++++++++++++++--------------------- 1 file changed, 156 insertions(+), 128 deletions(-)
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index e96935896a9..fd1a09225e1 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -433,142 +433,29 @@ skip_overlay: #endif
/** - * label_boot() - Boot according to the contents of a pxe_label - * - * If we can't boot for any reason, we return. A successful boot never - * returns. - * - * The kernel will be stored in the location given by the 'kernel_addr_r' - * environment variable. - * - * If the label specifies an initrd file, it will be stored in the location - * given by the 'ramdisk_addr_r' environment variable. - * - * If the label specifies an 'append' line, its contents will overwrite that - * of the 'bootargs' environment variable. + * label_run_boot() - Set up the FDT and call the appropriate bootm/z/i command * * @ctx: PXE context * @label: Label to process - * Returns does not return on success, otherwise returns 0 if a localboot - * label was processed, or 1 on error + * @kernel_addr: String containing kernel address (cannot be NULL) + * @initrd_addr_str: String containing initrd address (NULL if none) + * @initrd_filesize: String containing initrd size (only used if + * @initrd_addr_str) + * @initrd_str: initrd string to process (only used if @initrd_addr_str) + * Return: does not return on success, or returns 0 if the boot command + * returned, or -ve error value on error */ -static int label_boot(struct pxe_context *ctx, struct pxe_label *label) +static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, + char *kernel_addr, char *initrd_addr_str, + char *initrd_filesize, char *initrd_str) { char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL }; - char *kernel_addr = NULL; - char *initrd_addr_str = NULL; - char initrd_filesize[10]; - char initrd_str[28]; - char mac_str[29] = ""; - char ip_str[68] = ""; - char *fit_addr = NULL; + ulong kernel_addr_r; int bootm_argc = 2; int zboot_argc = 3; - int len = 0; - ulong kernel_addr_r; void *buf;
- label_print(label); - - label->attempted = 1; - - if (label->localboot) { - if (label->localboot_val >= 0) - label_localboot(label); - return 0; - } - - if (!label->kernel) { - printf("No kernel given, skipping %s\n", - label->name); - return 1; - } - - if (get_relfile_envaddr(ctx, label->kernel, "kernel_addr_r", - (enum bootflow_img_t)IH_TYPE_KERNEL, NULL) - < 0) { - printf("Skipping %s for failure retrieving kernel\n", - label->name); - return 1; - } - - kernel_addr = env_get("kernel_addr_r"); - /* for FIT, append the configuration identifier */ - if (label->config) { - int len = strlen(kernel_addr) + strlen(label->config) + 1; - - fit_addr = malloc(len); - if (!fit_addr) { - printf("malloc fail (FIT address)\n"); - return 1; - } - snprintf(fit_addr, len, "%s%s", kernel_addr, label->config); - kernel_addr = fit_addr; - } - - /* For FIT, the label can be identical to kernel one */ - if (label->initrd && !strcmp(label->kernel_label, label->initrd)) { - initrd_addr_str = kernel_addr; - } else if (label->initrd) { - ulong size; - if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r", - (enum bootflow_img_t)IH_TYPE_RAMDISK, - &size) < 0) { - printf("Skipping %s for failure retrieving initrd\n", - label->name); - goto cleanup; - } - strcpy(initrd_filesize, simple_xtoa(size)); - initrd_addr_str = env_get("ramdisk_addr_r"); - size = snprintf(initrd_str, sizeof(initrd_str), "%s:%lx", - initrd_addr_str, size); - if (size >= sizeof(initrd_str)) - goto cleanup; - } - - if (label->ipappend & 0x1) { - sprintf(ip_str, " ip=%s:%s:%s:%s", - env_get("ipaddr"), env_get("serverip"), - env_get("gatewayip"), env_get("netmask")); - } - - if (IS_ENABLED(CONFIG_CMD_NET)) { - if (label->ipappend & 0x2) { - int err; - - strcpy(mac_str, " BOOTIF="); - err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8); - if (err < 0) - mac_str[0] = '\0'; - } - } - - if ((label->ipappend & 0x3) || label->append) { - char bootargs[CONFIG_SYS_CBSIZE] = ""; - char finalbootargs[CONFIG_SYS_CBSIZE]; - - if (strlen(label->append ?: "") + - strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) { - printf("bootarg overflow %zd+%zd+%zd+1 > %zd\n", - strlen(label->append ?: ""), - strlen(ip_str), strlen(mac_str), - sizeof(bootargs)); - goto cleanup; - } - - if (label->append) - strlcpy(bootargs, label->append, sizeof(bootargs)); - - strcat(bootargs, ip_str); - strcat(bootargs, mac_str); - - cli_simple_process_macros(bootargs, finalbootargs, - sizeof(finalbootargs)); - env_set("bootargs", finalbootargs); - printf("append: %s\n", finalbootargs); - } - /* * fdt usage is optional: * It handles the following scenarios. @@ -607,6 +494,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) } } else if (label->fdtdir) { char *f1, *f2, *f3, *f4, *slash; + int len;
f1 = env_get("fdtfile"); if (f1) { @@ -649,7 +537,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) fdtfilefree = malloc(len); if (!fdtfilefree) { printf("malloc fail (FDT filename)\n"); - goto cleanup; + return -ENOMEM; }
snprintf(fdtfilefree, len, "%s%s%s%s%s%s", @@ -669,7 +557,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) if (label->fdt) { printf("Skipping %s for failure retrieving FDT\n", label->name); - goto cleanup; + return -ENOENT; }
if (label->fdtdir) { @@ -750,10 +638,150 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
unmap_sysmem(buf);
+ return 0; +} + +/** + * label_boot() - Boot according to the contents of a pxe_label + * + * If we can't boot for any reason, we return. A successful boot never + * returns. + * + * The kernel will be stored in the location given by the 'kernel_addr_r' + * environment variable. + * + * If the label specifies an initrd file, it will be stored in the location + * given by the 'ramdisk_addr_r' environment variable. + * + * If the label specifies an 'append' line, its contents will overwrite that + * of the 'bootargs' environment variable. + * + * @ctx: PXE context + * @label: Label to process + * Returns does not return on success, otherwise returns 0 if a localboot + * label was processed, or 1 on error + */ +static int label_boot(struct pxe_context *ctx, struct pxe_label *label) +{ + char *kernel_addr = NULL; + char *initrd_addr_str = NULL; + char initrd_filesize[10]; + char initrd_str[28]; + char mac_str[29] = ""; + char ip_str[68] = ""; + char *fit_addr = NULL; + + label_print(label); + + label->attempted = 1; + + if (label->localboot) { + if (label->localboot_val >= 0) + label_localboot(label); + return 0; + } + + if (!label->kernel) { + printf("No kernel given, skipping %s\n", + label->name); + return 1; + } + + if (get_relfile_envaddr(ctx, label->kernel, "kernel_addr_r", + (enum bootflow_img_t)IH_TYPE_KERNEL, NULL) + < 0) { + printf("Skipping %s for failure retrieving kernel\n", + label->name); + return 1; + } + + kernel_addr = env_get("kernel_addr_r"); + /* for FIT, append the configuration identifier */ + if (label->config) { + int len = strlen(kernel_addr) + strlen(label->config) + 1; + + fit_addr = malloc(len); + if (!fit_addr) { + printf("malloc fail (FIT address)\n"); + return 1; + } + snprintf(fit_addr, len, "%s%s", kernel_addr, label->config); + kernel_addr = fit_addr; + } + + /* For FIT, the label can be identical to kernel one */ + if (label->initrd && !strcmp(label->kernel_label, label->initrd)) { + initrd_addr_str = kernel_addr; + } else if (label->initrd) { + ulong size; + int ret; + + ret = get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r", + (enum bootflow_img_t)IH_TYPE_RAMDISK, + &size); + if (ret < 0) { + printf("Skipping %s for failure retrieving initrd\n", + label->name); + goto cleanup; + } + strcpy(initrd_filesize, simple_xtoa(size)); + initrd_addr_str = env_get("ramdisk_addr_r"); + size = snprintf(initrd_str, sizeof(initrd_str), "%s:%lx", + initrd_addr_str, size); + if (size >= sizeof(initrd_str)) + goto cleanup; + } + + if (label->ipappend & 0x1) { + sprintf(ip_str, " ip=%s:%s:%s:%s", + env_get("ipaddr"), env_get("serverip"), + env_get("gatewayip"), env_get("netmask")); + } + + if (IS_ENABLED(CONFIG_CMD_NET)) { + if (label->ipappend & 0x2) { + int err; + + strcpy(mac_str, " BOOTIF="); + err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8); + if (err < 0) + mac_str[0] = '\0'; + } + } + + if ((label->ipappend & 0x3) || label->append) { + char bootargs[CONFIG_SYS_CBSIZE] = ""; + char finalbootargs[CONFIG_SYS_CBSIZE]; + + if (strlen(label->append ?: "") + + strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) { + printf("bootarg overflow %zd+%zd+%zd+1 > %zd\n", + strlen(label->append ?: ""), + strlen(ip_str), strlen(mac_str), + sizeof(bootargs)); + goto cleanup; + } + + if (label->append) + strlcpy(bootargs, label->append, sizeof(bootargs)); + + strcat(bootargs, ip_str); + strcat(bootargs, mac_str); + + cli_simple_process_macros(bootargs, finalbootargs, + sizeof(finalbootargs)); + env_set("bootargs", finalbootargs); + printf("append: %s\n", finalbootargs); + } + + label_run_boot(ctx, label, kernel_addr, initrd_addr_str, + initrd_filesize, initrd_str); + /* ignore the error value since we are going to fail anyway */ + cleanup: free(fit_addr);
- return 1; + return 1; /* returning is always failure */ }
/** enum token_type - Tokens for the pxe file parser */

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 Reviewed-by: Quentin Schulz quentin.schulz@cherry.de ---
Changes in v2: - Rebase on earlier change
boot/pxe_utils.c | 100 ++++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 40 deletions(-)
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index fd1a09225e1..a14b4eb54c2 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -432,51 +432,37 @@ skip_overlay: } #endif
-/** - * label_run_boot() - Set up the FDT and call the appropriate bootm/z/i command +/* + * label_process_fdt() - Process FDT for the label * * @ctx: PXE context * @label: Label to process - * @kernel_addr: String containing kernel address (cannot be NULL) - * @initrd_addr_str: String containing initrd address (NULL if none) - * @initrd_filesize: String containing initrd size (only used if - * @initrd_addr_str) - * @initrd_str: initrd string to process (only used if @initrd_addr_str) - * Return: does not return on success, or returns 0 if the boot command - * returned, or -ve error value on error + * @kernel_addr: String containing kernel address + * @bootm_argv: bootm arguments to fill in (this only adjusts @bootm_argv[3]) + * Return: 0 if OK, -ENOMEM if out of memory, -ENOENT if FDT file could not be + * loaded + * + * fdt usage is optional: + * It handles the following scenarios. + * + * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is + * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to + * bootm, and adjust argc appropriately. + * + * If retrieve fails and no exact fdt blob is specified in pxe file with + * "fdt" label, try Scenario 2. + * + * Scenario 2: If there is an fdt_addr specified, pass it along to + * bootm, and adjust argc appropriately. + * + * Scenario 3: If there is an fdtcontroladdr specified, pass it along to + * bootm, and adjust argc appropriately, unless the image type is fitImage. + * + * Scenario 4: fdt blob is not available. */ -static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, - char *kernel_addr, char *initrd_addr_str, - char *initrd_filesize, char *initrd_str) +static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label, + char *kernel_addr, char *bootm_argv[]) { - char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; - char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL }; - ulong kernel_addr_r; - int bootm_argc = 2; - int zboot_argc = 3; - void *buf; - - /* - * fdt usage is optional: - * It handles the following scenarios. - * - * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is - * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to - * bootm, and adjust argc appropriately. - * - * If retrieve fails and no exact fdt blob is specified in pxe file with - * "fdt" label, try Scenario 2. - * - * Scenario 2: If there is an fdt_addr specified, pass it along to - * bootm, and adjust argc appropriately. - * - * Scenario 3: If there is an fdtcontroladdr specified, pass it along to - * bootm, and adjust argc appropriately, unless the image type is fitImage. - * - * Scenario 4: fdt blob is not available. - */ - bootm_argv[3] = env_get("fdt_addr_r"); - /* For FIT, the label can be identical to kernel one */ if (label->fdt && !strcmp(label->kernel_label, label->fdt)) { bootm_argv[3] = kernel_addr; @@ -578,6 +564,40 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, } }
+ return 0; +} + +/** + * label_run_boot() - Set up the FDT and call the appropriate bootm/z/i command + * + * @ctx: PXE context + * @label: Label to process + * @kernel_addr: String containing kernel address (cannot be NULL) + * @initrd_addr_str: String containing initrd address (NULL if none) + * @initrd_filesize: String containing initrd size (only used if + * @initrd_addr_str) + * @initrd_str: initrd string to process (only used if @initrd_addr_str) + * Return: does not return on success, or returns 0 if the boot command + * returned, or -ve error value on error + */ +static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, + char *kernel_addr, char *initrd_addr_str, + char *initrd_filesize, char *initrd_str) +{ + char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; + char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL }; + ulong kernel_addr_r; + int bootm_argc = 2; + int zboot_argc = 3; + void *buf; + int ret; + + bootm_argv[3] = env_get("fdt_addr_r"); + + ret = label_process_fdt(ctx, label, kernel_addr, bootm_argv); + if (ret) + return ret; + bootm_argv[1] = kernel_addr; zboot_argv[1] = kernel_addr;

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 ---
(no changes since v1)
boot/pxe_utils.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index a14b4eb54c2..2ada5c4aaac 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -438,7 +438,7 @@ skip_overlay: * @ctx: PXE context * @label: Label to process * @kernel_addr: String containing kernel address - * @bootm_argv: bootm arguments to fill in (this only adjusts @bootm_argv[3]) + * @fdt_argp: bootm argument to fill in, for FDT * Return: 0 if OK, -ENOMEM if out of memory, -ENOENT if FDT file could not be * loaded * @@ -461,13 +461,13 @@ skip_overlay: * Scenario 4: fdt blob is not available. */ static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label, - char *kernel_addr, char *bootm_argv[]) + char *kernel_addr, char **fdt_argp) { /* For FIT, the label can be identical to kernel one */ if (label->fdt && !strcmp(label->kernel_label, label->fdt)) { - bootm_argv[3] = kernel_addr; + *fdt_argp = kernel_addr; /* if fdt label is defined then get fdt from server */ - } else if (bootm_argv[3]) { + } else if (*fdt_argp) { char *fdtfile = NULL; char *fdtfilefree = NULL;
@@ -538,7 +538,7 @@ static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label,
free(fdtfilefree); if (err < 0) { - bootm_argv[3] = NULL; + *fdt_argp = NULL;
if (label->fdt) { printf("Skipping %s for failure retrieving FDT\n", @@ -560,7 +560,7 @@ static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label, label_boot_fdtoverlay(ctx, label); #endif } else { - bootm_argv[3] = NULL; + *fdt_argp = NULL; } }
@@ -594,7 +594,7 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label,
bootm_argv[3] = env_get("fdt_addr_r");
- ret = label_process_fdt(ctx, label, kernel_addr, bootm_argv); + ret = label_process_fdt(ctx, label, kernel_addr, &bootm_argv[3]); if (ret) return ret;

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 ---
(no changes since v1)
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 *

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 Reviewed-by: Quentin Schulz quentin.schulz@cherry.de ---
(no changes since v1)
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 2ada5c4aaac..bbb6ff203b6 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; }

Tidy up this code a little to avoid two calls to env_get() for both fdt_addr and fdtcontroladdr
Signed-off-by: Simon Glass sjg@chromium.org Suggested-by: Quentin Schulz quentin.schulz@cherry.de ---
Changes in v2: - Add new patch to simplify the code reading fdtcontroladdr and fdt_addr
boot/pxe_utils.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index bbb6ff203b6..37306f37009 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -612,24 +612,18 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, }
if (!bmi.conf_fdt) { - if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { - if (strcmp("-", label->fdt)) - bmi.conf_fdt = env_get("fdt_addr"); - } else { + if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || + strcmp("-", label->fdt)) bmi.conf_fdt = env_get("fdt_addr"); - } }
kernel_addr_r = genimg_get_kernel_addr(kernel_addr); buf = map_sysmem(kernel_addr_r, 0);
if (!bmi.conf_fdt && genimg_get_format(buf) != IMAGE_FORMAT_FIT) { - if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { - if (strcmp("-", label->fdt)) - bmi.conf_fdt = env_get("fdtcontroladdr"); - } else { + if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || + strcmp("-", label->fdt)) bmi.conf_fdt = env_get("fdtcontroladdr"); - } }
/* Try bootm for legacy and FIT format image */

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 ---
(no changes since v1)
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 37306f37009..a91372407eb 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) { @@ -642,7 +639,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 ---
(no changes since v1)
cmd/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index 79525f73a51..deebd5b710f 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -413,8 +413,6 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, return CMD_RET_USAGE; }
- bootstage_mark(BOOTSTAGE_ID_NET_START); - if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) { char *s, *e; size_t len; @@ -428,6 +426,8 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } }
+ bootstage_mark(BOOTSTAGE_ID_NET_START); + size = net_loop(proto); if (size < 0) { bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);

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 Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org ---
(no changes since v1)
cmd/net.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index deebd5b710f..89a4d9b38d4 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -313,9 +313,18 @@ static int parse_addr_size(char * const argv[]) /** * parse_args() - parse command line arguments * + * Sets: + * + * - net_boot_file_name_explicit to true if a filename was specified + * - net_boot_file_name to that filename, if specified, else the value of the + * 'bootfile' environment variable + * - image_load_addr if a load address was provided + * - image_save_addr and image_save_size, if proto == TFTPPUT + * * @proto: command prototype - * @argc: number of arguments - * @argv: command line arguments + * @argc: number of arguments, include the command, which has already been + * parsed + * @argv: command line arguments, with argv[0] being the command * Return: 0 on success */ static int parse_args(enum proto_t proto, int argc, char *const argv[])

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 ---
(no changes since v1)
cmd/net.c | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index 89a4d9b38d4..cc7d14eb082 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -314,10 +314,6 @@ static int parse_addr_size(char * const argv[]) * parse_args() - parse command line arguments * * Sets: - * - * - net_boot_file_name_explicit to true if a filename was specified - * - net_boot_file_name to that filename, if specified, else the value of the - * 'bootfile' environment variable * - image_load_addr if a load address was provided * - image_save_addr and image_save_size, if proto == TFTPPUT * @@ -325,21 +321,20 @@ static int parse_addr_size(char * const argv[]) * @argc: number of arguments, include the command, which has already been * parsed * @argv: command line arguments, with argv[0] being the command + * @fnamep: set to the filename, if provided, else NULL * Return: 0 on success */ -static int parse_args(enum proto_t proto, int argc, char *const argv[]) +static int parse_args(enum proto_t proto, int argc, char *const argv[], + const char **fnamep) { ulong addr; char *end;
+ *fnamep = NULL; switch (argc) { case 1: if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) return 1; - - /* refresh bootfile name from env */ - copy_filename(net_boot_file_name, env_get("bootfile"), - sizeof(net_boot_file_name)); break;
case 2: @@ -352,16 +347,10 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[]) * mis-interpreted as a valid number. */ addr = hextoul(argv[1], &end); - if (end == (argv[1] + strlen(argv[1]))) { + if (end == (argv[1] + strlen(argv[1]))) image_load_addr = addr; - /* refresh bootfile name from env */ - copy_filename(net_boot_file_name, env_get("bootfile"), - sizeof(net_boot_file_name)); - } else { - net_boot_file_name_explicit = true; - copy_filename(net_boot_file_name, argv[1], - sizeof(net_boot_file_name)); - } + else + *fnamep = argv[1]; break;
case 3: @@ -370,9 +359,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[]) return 1; } else { image_load_addr = hextoul(argv[1], NULL); - net_boot_file_name_explicit = true; - copy_filename(net_boot_file_name, argv[2], - sizeof(net_boot_file_name)); + *fnamep = argv[2]; } break;
@@ -380,20 +367,20 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[]) case 4: if (parse_addr_size(argv)) return 1; - net_boot_file_name_explicit = true; - copy_filename(net_boot_file_name, argv[3], - sizeof(net_boot_file_name)); + *fnamep = argv[3]; break; #endif default: return 1; } + return 0; }
static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { + const char *fname; char *s; int rcode = 0; int size; @@ -417,11 +404,19 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } }
- if (parse_args(proto, argc, argv)) { + if (parse_args(proto, argc, argv, &fname)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; }
+ if (fname) { + net_boot_file_name_explicit = true; + } else { + net_boot_file_name_explicit = false; + fname = env_get("bootfile"); + } + copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); + if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) { char *s, *e; size_t len;

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 ---
(no changes since v1)
cmd/net.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index cc7d14eb082..d15d344cb54 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -314,7 +314,6 @@ static int parse_addr_size(char * const argv[]) * parse_args() - parse command line arguments * * Sets: - * - image_load_addr if a load address was provided * - image_save_addr and image_save_size, if proto == TFTPPUT * * @proto: command prototype @@ -322,10 +321,12 @@ static int parse_addr_size(char * const argv[]) * parsed * @argv: command line arguments, with argv[0] being the command * @fnamep: set to the filename, if provided, else NULL + * @addrp: returns the load address, if any is provided, else it is left + * unchanged * Return: 0 on success */ static int parse_args(enum proto_t proto, int argc, char *const argv[], - const char **fnamep) + const char **fnamep, ulong *addrp) { ulong addr; char *end; @@ -348,7 +349,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], */ addr = hextoul(argv[1], &end); if (end == (argv[1] + strlen(argv[1]))) - image_load_addr = addr; + *addrp = addr; else *fnamep = argv[1]; break; @@ -358,7 +359,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], if (parse_addr_size(argv)) return 1; } else { - image_load_addr = hextoul(argv[1], NULL); + *addrp = hextoul(argv[1], NULL); *fnamep = argv[2]; } break; @@ -404,7 +405,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } }
- if (parse_args(proto, argc, argv, &fname)) { + if (parse_args(proto, argc, argv, &fname, &image_load_addr)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; }

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 ---
(no changes since v1)
cmd/net.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index d15d344cb54..cc968e9460f 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -297,13 +297,15 @@ static void netboot_update_env(void) /** * parse_addr_size() - parse address and size arguments for tftpput * - * @argv: command line arguments + * @argv: command line arguments (argv[1] and argv[2] must be valid) + * @addrp: returns the address, on success + * @sizep: returns the size, on success * Return: 0 on success */ -static int parse_addr_size(char * const argv[]) +static int parse_addr_size(char * const argv[], ulong *addrp, ulong *sizep) { - if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 || - strict_strtoul(argv[2], 16, &image_save_size) < 0) { + if (strict_strtoul(argv[1], 16, addrp) < 0 || + strict_strtoul(argv[2], 16, sizep) < 0) { printf("Invalid address/size\n"); return CMD_RET_USAGE; } @@ -356,7 +358,8 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[],
case 3: if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { - if (parse_addr_size(argv)) + if (parse_addr_size(argv, &image_save_addr, + &image_save_size)) return 1; } else { *addrp = hextoul(argv[1], NULL); @@ -366,7 +369,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[],
#ifdef CONFIG_CMD_TFTPPUT case 4: - if (parse_addr_size(argv)) + if (parse_addr_size(argv, &image_save_addr, &image_save_size)) return 1; *fnamep = argv[3]; break;

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 ---
(no changes since v1)
cmd/net.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index cc968e9460f..572fa75a72f 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -323,12 +323,14 @@ static int parse_addr_size(char * const argv[], ulong *addrp, ulong *sizep) * parsed * @argv: command line arguments, with argv[0] being the command * @fnamep: set to the filename, if provided, else NULL - * @addrp: returns the load address, if any is provided, else it is left + * @addrp: returns the load/save address, if any is provided, else it is + * left unchanged + * @sizep: returns the save size, if any is provided, else it is left * unchanged * Return: 0 on success */ static int parse_args(enum proto_t proto, int argc, char *const argv[], - const char **fnamep, ulong *addrp) + const char **fnamep, ulong *addrp, ulong *sizep) { ulong addr; char *end; @@ -358,8 +360,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[],
case 3: if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { - if (parse_addr_size(argv, &image_save_addr, - &image_save_size)) + if (parse_addr_size(argv, addrp, sizep)) return 1; } else { *addrp = hextoul(argv[1], NULL); @@ -369,7 +370,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[],
#ifdef CONFIG_CMD_TFTPPUT case 4: - if (parse_addr_size(argv, &image_save_addr, &image_save_size)) + if (parse_addr_size(argv, addrp, sizep)) return 1; *fnamep = argv[3]; break; @@ -385,6 +386,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { const char *fname; + ulong addr; char *s; int rcode = 0; int size; @@ -392,10 +394,10 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, net_boot_file_name_explicit = false; *net_boot_file_name = '\0';
- /* pre-set image_load_addr */ + /* pre-set addr */ s = env_get("loadaddr"); if (s != NULL) - image_load_addr = hextoul(s, NULL); + addr = hextoul(s, NULL);
if (IS_ENABLED(CONFIG_IPV6)) { use_ip6 = false; @@ -408,10 +410,14 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } }
- if (parse_args(proto, argc, argv, &fname, &image_load_addr)) { + if (parse_args(proto, argc, argv, &fname, &addr, &image_save_size)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) + image_save_addr = addr; + else + image_load_addr = addr;
if (fname) { net_boot_file_name_explicit = true;

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 ---
(no changes since v1)
cmd/net.c | 62 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 16 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index 572fa75a72f..f980448e0ef 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -382,11 +382,50 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], return 0; }
+static int netboot_run_(enum proto_t proto, ulong addr, const char *fname, + ulong size, bool fname_explicit, bool ipv6) +{ + int ret; + + bootstage_mark(BOOTSTAGE_ID_NET_START); + + /* + * For now we use the global variables as that is the only way to + * control the network stack. At some point, perhaps, the state could be + * in a struct + */ + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) + image_save_addr = addr; + else + image_load_addr = addr; + + net_boot_file_name_explicit = fname_explicit; + copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); + if (IS_ENABLED(CONFIG_IPV6)) + use_ip6 = ipv6; + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { + image_save_addr = addr; + image_save_size = size; + } else { + image_load_addr = addr; + } + + ret = net_loop(proto); + if (ret < 0) { + bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); + return ret; + } + bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); + + return 0; +} + static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { + ulong addr, save_size; + bool fname_explicit; const char *fname; - ulong addr; char *s; int rcode = 0; int size; @@ -410,22 +449,17 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } }
- if (parse_args(proto, argc, argv, &fname, &addr, &image_save_size)) { + if (parse_args(proto, argc, argv, &fname, &addr, &save_size)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } - if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) - image_save_addr = addr; - else - image_load_addr = addr;
if (fname) { - net_boot_file_name_explicit = true; + fname_explicit = true; } else { - net_boot_file_name_explicit = false; + fname_explicit = false; fname = env_get("bootfile"); } - copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name));
if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) { char *s, *e; @@ -440,14 +474,10 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } }
- bootstage_mark(BOOTSTAGE_ID_NET_START); - - size = net_loop(proto); - if (size < 0) { - bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); + size = netboot_run_(proto, addr, fname, save_size, fname_explicit, + use_ip6); + if (size < 0) return CMD_RET_FAILURE; - } - bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
/* net_loop ok, update environment */ netboot_update_env();

Use IS_ENABLED() to avoid an extra build path.
Signed-off-by: Simon Glass sjg@chromium.org Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org ---
(no changes since v1)
cmd/net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index f980448e0ef..6d1c6374f76 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -368,13 +368,13 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], } break;
-#ifdef CONFIG_CMD_TFTPPUT case 4: - if (parse_addr_size(argv, addrp, sizep)) - return 1; - *fnamep = argv[3]; - break; -#endif + if (IS_ENABLED(CONFIG_CMD_TFTPPUT)) { + if (parse_addr_size(argv, addrp, sizep)) + return 1; + *fnamep = argv[3]; + break; + } default: return 1; }

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 ---
(no changes since v1)
cmd/net.c | 40 +--------------------------------------- include/net-common.h | 30 ++++++++++++++++++++++++++++++ net/net.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 39 deletions(-)
diff --git a/cmd/net.c b/cmd/net.c index 6d1c6374f76..8f33c9f55d5 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -382,44 +382,6 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], return 0; }
-static int netboot_run_(enum proto_t proto, ulong addr, const char *fname, - ulong size, bool fname_explicit, bool ipv6) -{ - int ret; - - bootstage_mark(BOOTSTAGE_ID_NET_START); - - /* - * For now we use the global variables as that is the only way to - * control the network stack. At some point, perhaps, the state could be - * in a struct - */ - if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) - image_save_addr = addr; - else - image_load_addr = addr; - - net_boot_file_name_explicit = fname_explicit; - copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); - if (IS_ENABLED(CONFIG_IPV6)) - use_ip6 = ipv6; - if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { - image_save_addr = addr; - image_save_size = size; - } else { - image_load_addr = addr; - } - - ret = net_loop(proto); - if (ret < 0) { - bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); - return ret; - } - bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); - - return 0; -} - static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { @@ -475,7 +437,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, }
size = netboot_run_(proto, addr, fname, save_size, fname_explicit, - use_ip6); + IS_ENABLED(CONFIG_IPV6) && use_ip6); if (size < 0) return CMD_RET_FAILURE;
diff --git a/include/net-common.h b/include/net-common.h index c5e314b360d..12c50e2a41e 100644 --- a/include/net-common.h +++ b/include/net-common.h @@ -474,6 +474,36 @@ int net_init(void); enum proto_t; int net_loop(enum proto_t protocol);
+/* internal function: do not use! */ +int netboot_run_(enum proto_t proto, ulong addr, const char *fname, ulong size, + bool fname_explicit, bool ipv6); + +/** + * netboot_run() - Run a network operation + * + * The following proto values are NOT supported: + * PING, since net_ping_ip cannot be set + * NETCONS, since its parameters cannot bet set + * RS, since first_call cannot be set, along with perhaps other things + * UDP, since udp_ops cannot be set + * DNS, since net_dns_resolve and net_dns_env_var cannot be set + * WGET, since DNS must be done first and that is not supported + * DHCP6, since the required parameters cannot be passed in + * + * To support one of these, either add the required arguments or perhaps a + * separate function and a struct to hold the information. + * + * @proto: Operation to run: TFTPGET, FASTBOOT_UDP, FASTBOOT_TCP, BOOTP, + * TFTPPUT, RARP, NFS, DHCP + * @addr: Load/save address + * @fname: Filename + * @size: Save size (not used for TFTPGET) + * @ipv6: true to use IPv6, false to use IPv4 + * Return 0 on success, else -ve error code + */ +int netboot_run(enum proto_t proto, ulong addr, const char *fname, ulong size, + bool ipv6); + /** * dhcp_run() - Run DHCP on the current ethernet device * diff --git a/net/net.c b/net/net.c index ca35704f661..da98460a667 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 ---
(no changes since v1)
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 ---
(no changes since v1)
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 17c6cebd2f4..4adcaf5654a 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -175,7 +175,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; @@ -188,8 +187,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 a91372407eb..b4aa284b1ee 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -1630,16 +1630,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 ---
(no changes since v1)
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 4adcaf5654a..569f9d760bf 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -188,7 +188,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 b4aa284b1ee..f7bbc1527af 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -1632,7 +1632,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; @@ -1643,6 +1643,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 ---
(no changes since v1)
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 f7bbc1527af..3531ab1c71a 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -782,6 +782,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 */ @@ -1566,11 +1569,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; + } } }
@@ -1621,6 +1628,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 ---
(no changes since v1)
test/boot/bootm.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/test/boot/bootm.c b/test/boot/bootm.c index 9455f44884c..0dd8bc2979f 100644 --- a/test/boot/bootm.c +++ b/test/boot/bootm.c @@ -122,6 +122,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); @@ -229,6 +232,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); @@ -246,6 +251,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 ---
(no changes since v1)
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 569f9d760bf..e2050af8203 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -22,8 +22,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 { @@ -175,20 +182,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 ---
(no changes since v1)
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 e2050af8203..144f5a11425 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -27,9 +27,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; };
@@ -183,7 +185,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;
@@ -192,12 +193,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 ---
(no changes since v1)
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 144f5a11425..d0a32eb8b68 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -22,48 +22,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)) { @@ -205,38 +163,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 ---
(no changes since v1)
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 ---
(no changes since v1)
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 ---
(no changes since v1)
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 d0a32eb8b68..b29e07788b3 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -140,27 +140,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) @@ -178,7 +160,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 ---
(no changes since v1)
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 b29e07788b3..e866cf06152 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -145,6 +145,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); @@ -162,6 +169,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 f7d12765928..ef8c0c1bbaa 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -1433,3 +1433,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 ---
(no changes since v1)
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 3531ab1c71a..053fdcbb6e7 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));
@@ -678,6 +675,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);
@@ -782,11 +781,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 ef8c0c1bbaa..640a7cdb7c9 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -1459,7 +1459,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); @@ -1473,6 +1473,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 ---
(no changes since v1)
boot/pxe_utils.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 053fdcbb6e7..1468a8e8498 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -605,21 +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) || - strcmp("-", label->fdt)) - bmi.conf_fdt = env_get("fdt_addr"); - } - kernel_addr_r = genimg_get_kernel_addr(kernel_addr); buf = map_sysmem(kernel_addr_r, 0);
- if (!bmi.conf_fdt && genimg_get_format(buf) != IMAGE_FORMAT_FIT) { - if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || - strcmp("-", label->fdt)) - 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)) { @@ -786,6 +774,28 @@ 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) || + strcmp("-", label->fdt)) + 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) || + strcmp("-", label->fdt)) + 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 ---
(no changes since v1)
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 1468a8e8498..a76fa68f832 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -796,8 +796,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); @@ -1689,18 +1712,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);
@@ -1708,3 +1742,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 ---
(no changes since v1)
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 640a7cdb7c9..35580cee90c 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" @@ -1440,6 +1441,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(); @@ -1477,6 +1481,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);

Hi,
On Tue, 3 Dec 2024 at 16:46, Simon Glass sjg@chromium.org 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.
Changes in v2:
- Split out strlcpy() change into new patch
- Move strlcpy() change into an earlier patch
- Fix 'initaddr' typo'
- Rebase on earlier change
- Add new patch to simplify the code reading fdtcontroladdr and fdt_addr
Simon Glass (41): 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: Use strlcpy() in label_boot() 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 pxe_utils: Simplify default fdt in label_run_boot() 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, 957 insertions(+), 506 deletions(-) create mode 100644 boot/ext_pxe_common.c
-- 2.34.1
Unfortunately it seems there is a bug in here somewhere, in that it prepends the extlinux file's path to any files which are read, at least with pxe. So I am going to need to take another look...
We don't have sandbox tests for this case, unfortunately. At some point we should try to add some.
Regards, Simon

On Tue, Dec 03, 2024 at 05:03:26PM -0700, Simon Glass wrote:
Hi,
On Tue, 3 Dec 2024 at 16:46, Simon Glass sjg@chromium.org 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.
Changes in v2:
- Split out strlcpy() change into new patch
- Move strlcpy() change into an earlier patch
- Fix 'initaddr' typo'
- Rebase on earlier change
- Add new patch to simplify the code reading fdtcontroladdr and fdt_addr
Simon Glass (41): 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: Use strlcpy() in label_boot() 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 pxe_utils: Simplify default fdt in label_run_boot() 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, 957 insertions(+), 506 deletions(-) create mode 100644 boot/ext_pxe_common.c
-- 2.34.1
Unfortunately it seems there is a bug in here somewhere, in that it prepends the extlinux file's path to any files which are read, at least with pxe. So I am going to need to take another look...
We don't have sandbox tests for this case, unfortunately. At some point we should try to add some.
Does the pxelinux test not catch the problem? If not, that would be where to start expanding perhaps.

Hi Tom,
On Tue, 3 Dec 2024 at 17:12, Tom Rini trini@konsulko.com wrote:
On Tue, Dec 03, 2024 at 05:03:26PM -0700, Simon Glass wrote:
Hi,
On Tue, 3 Dec 2024 at 16:46, Simon Glass sjg@chromium.org 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.
Changes in v2:
- Split out strlcpy() change into new patch
- Move strlcpy() change into an earlier patch
- Fix 'initaddr' typo'
- Rebase on earlier change
- Add new patch to simplify the code reading fdtcontroladdr and fdt_addr
Simon Glass (41): 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: Use strlcpy() in label_boot() 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 pxe_utils: Simplify default fdt in label_run_boot() 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, 957 insertions(+), 506 deletions(-) create mode 100644 boot/ext_pxe_common.c
-- 2.34.1
Unfortunately it seems there is a bug in here somewhere, in that it prepends the extlinux file's path to any files which are read, at least with pxe. So I am going to need to take another look...
We don't have sandbox tests for this case, unfortunately. At some point we should try to add some.
Does the pxelinux test not catch the problem? If not, that would be where to start expanding perhaps.
Right...it needs a little more work, but for now I'll have to fix the bug, as it's already 41 patches. I might be able to add a smaller test, will see.
Regards, Simon

Hi Tom,
On Tue, 3 Dec 2024 at 17:37, Simon Glass sjg@chromium.org wrote:
Hi Tom,
On Tue, 3 Dec 2024 at 17:12, Tom Rini trini@konsulko.com wrote:
On Tue, Dec 03, 2024 at 05:03:26PM -0700, Simon Glass wrote:
Hi,
On Tue, 3 Dec 2024 at 16:46, Simon Glass sjg@chromium.org 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.
Changes in v2:
- Split out strlcpy() change into new patch
- Move strlcpy() change into an earlier patch
- Fix 'initaddr' typo'
- Rebase on earlier change
- Add new patch to simplify the code reading fdtcontroladdr and fdt_addr
Simon Glass (41): 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: Use strlcpy() in label_boot() 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 pxe_utils: Simplify default fdt in label_run_boot() 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, 957 insertions(+), 506 deletions(-) create mode 100644 boot/ext_pxe_common.c
-- 2.34.1
Unfortunately it seems there is a bug in here somewhere, in that it prepends the extlinux file's path to any files which are read, at least with pxe. So I am going to need to take another look...
We don't have sandbox tests for this case, unfortunately. At some point we should try to add some.
Does the pxelinux test not catch the problem? If not, that would be where to start expanding perhaps.
Right...it needs a little more work, but for now I'll have to fix the bug, as it's already 41 patches. I might be able to add a smaller test, will see.
It turned out to be a boolean which needs a different value between extlinux and PXE. I didn't notice it at first. So I'll send this series once it passes CI
Regards, Simon
participants (2)
-
Simon Glass
-
Tom Rini