From: Simon Glass <sjg@chromium.org> Replace the single struct pxe_context in extlinux_priv with an alist of contexts, one per extlinux.conf file. Use bflow->bootmeth_id so that boot and read_all can locate the correct context from the alist. Add extlinux_get_ctx() in ext_pxe_common.c which returns an existing context by bootmeth_id or allocates a new one. This ensures read_all and boot share the same context, preserving the label state set up by pxe_probe(). Add extlinux_bootmeth_probe() and update extlinux_bootmeth_remove() for alist lifecycle management, used by both extlinux and PXE drivers. The VBE driver uses its own priv struct and continues with local contexts. Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/bootmeth_extlinux.c | 34 +++++++++++++++++++++++++++++----- boot/bootmeth_pxe.c | 15 +++++++++++++-- boot/ext_pxe_common.c | 22 ++++++++++++++++++++++ boot/vbe_abrec_os.c | 2 +- include/extlinux.h | 32 +++++++++++++++++++++++++++++--- 5 files changed, 94 insertions(+), 11 deletions(-) diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c index ca9120c3f99..286d176ae20 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -218,8 +218,13 @@ static int extlinux_read_bootflow(struct udevice *dev, struct bootflow *bflow) static int extlinux_local_boot(struct udevice *dev, struct bootflow *bflow) { struct extlinux_priv *priv = dev_get_priv(dev); + struct pxe_context *ctx; - return extlinux_boot(dev, bflow, &priv->ctx, extlinux_getfile, true, + ctx = extlinux_get_ctx(priv, bflow); + if (!ctx) + return log_msg_ret("ctx", -ENOMEM); + + return extlinux_boot(dev, bflow, ctx, extlinux_getfile, true, bflow->fname, false); } @@ -227,19 +232,37 @@ static int extlinux_local_boot(struct udevice *dev, struct bootflow *bflow) static int extlinux_local_read_all(struct udevice *dev, struct bootflow *bflow) { struct extlinux_priv *priv = dev_get_priv(dev); + struct pxe_context *ctx; + + ctx = extlinux_get_ctx(priv, bflow); + if (!ctx) + return log_msg_ret("ctx", -ENOMEM); - return extlinux_read_all(dev, bflow, &priv->ctx, extlinux_getfile, + return extlinux_read_all(dev, bflow, ctx, extlinux_getfile, true, bflow->fname); } #endif +int extlinux_bootmeth_probe(struct udevice *dev) +{ + struct extlinux_priv *priv = dev_get_priv(dev); + + alist_init_struct(&priv->ctxs, struct pxe_context); + + return 0; +} + int extlinux_bootmeth_remove(struct udevice *dev) { struct extlinux_priv *priv = dev_get_priv(dev); + struct pxe_context *ctx; - if (priv->ctx.cfg) - pxe_menu_uninit(priv->ctx.cfg); - pxe_destroy_ctx(&priv->ctx); + alist_for_each(ctx, &priv->ctxs) { + if (ctx->cfg) + pxe_menu_uninit(ctx->cfg); + pxe_destroy_ctx(ctx); + } + alist_uninit(&priv->ctxs); return 0; } @@ -278,6 +301,7 @@ U_BOOT_DRIVER(bootmeth_1extlinux) = { .of_match = extlinux_bootmeth_ids, .ops = &extlinux_bootmeth_ops, .bind = extlinux_bootmeth_bind, + .probe = extlinux_bootmeth_probe, .remove = extlinux_bootmeth_remove, .plat_auto = sizeof(struct extlinux_plat), .priv_auto = sizeof(struct extlinux_priv), diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 772acc9107d..cc2a415f3c4 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -146,8 +146,13 @@ 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_priv *priv = dev_get_priv(dev); + struct pxe_context *ctx; - return extlinux_boot(dev, bflow, &priv->ctx, extlinux_pxe_getfile, + ctx = extlinux_get_ctx(priv, bflow); + if (!ctx) + return log_msg_ret("ctx", -ENOMEM); + + return extlinux_boot(dev, bflow, ctx, extlinux_pxe_getfile, false, bflow->subdir, false); } @@ -155,8 +160,13 @@ static int extlinux_pxe_boot(struct udevice *dev, struct bootflow *bflow) static int extlinux_pxe_read_all(struct udevice *dev, struct bootflow *bflow) { struct extlinux_priv *priv = dev_get_priv(dev); + struct pxe_context *ctx; + + ctx = extlinux_get_ctx(priv, bflow); + if (!ctx) + return log_msg_ret("ctx", -ENOMEM); - return extlinux_read_all(dev, bflow, &priv->ctx, + return extlinux_read_all(dev, bflow, ctx, extlinux_pxe_getfile, false, bflow->subdir); } #endif @@ -193,6 +203,7 @@ U_BOOT_DRIVER(bootmeth_zpxe) = { .of_match = extlinux_bootmeth_pxe_ids, .ops = &extlinux_bootmeth_pxe_ops, .bind = extlinux_bootmeth_pxe_bind, + .probe = extlinux_bootmeth_probe, .remove = extlinux_bootmeth_remove, .plat_auto = sizeof(struct extlinux_plat), .priv_auto = sizeof(struct extlinux_priv), diff --git a/boot/ext_pxe_common.c b/boot/ext_pxe_common.c index 5a4b6455a53..8a59b29ead8 100644 --- a/boot/ext_pxe_common.c +++ b/boot/ext_pxe_common.c @@ -75,6 +75,28 @@ int extlinux_set_property(struct udevice *dev, const char *property, return 0; } +struct pxe_context *extlinux_get_ctx(struct extlinux_priv *priv, + struct bootflow *bflow) +{ + struct pxe_context *ctx; + + /* Return existing context if one was already allocated */ + if (bflow->bootmeth_id >= 0) { + ctx = alist_getw(&priv->ctxs, bflow->bootmeth_id, + struct pxe_context); + if (ctx) + return ctx; + } + + /* Allocate a new one */ + ctx = alist_add_placeholder(&priv->ctxs); + if (!ctx) + return NULL; + bflow->bootmeth_id = priv->ctxs.count - 1; + + return ctx; +} + static int extlinux_setup(struct udevice *dev, struct bootflow *bflow, pxe_getfile_func getfile, bool allow_abs_path, const char *bootfile, struct pxe_context *ctx) diff --git a/boot/vbe_abrec_os.c b/boot/vbe_abrec_os.c index 9d0136b059b..9b41dcbf303 100644 --- a/boot/vbe_abrec_os.c +++ b/boot/vbe_abrec_os.c @@ -288,5 +288,5 @@ U_BOOT_DRIVER(vbe_abrec_os) = { .bind = bootmeth_vbe_abrec_os_bind, .probe = bootmeth_vbe_abrec_os_probe, .priv_auto = sizeof(struct abrec_priv), - .plat_auto = sizeof(struct extlinux_plat) + .plat_auto = sizeof(struct extlinux_plat), }; diff --git a/include/extlinux.h b/include/extlinux.h index 8630a8e3dc7..bad901cc3e6 100644 --- a/include/extlinux.h +++ b/include/extlinux.h @@ -36,22 +36,48 @@ struct extlinux_plat { /** * struct extlinux_priv - private runtime data for this bootmeth * - * @ctx: holds the PXE context + * @ctxs: list of parsed PXE contexts (alist of struct pxe_context), one per + * extlinux.conf file found during scanning */ struct extlinux_priv { - struct pxe_context ctx; + struct alist ctxs; }; +/** + * extlinux_bootmeth_probe() - Probe function for extlinux-based bootmeths + * + * Initialises the context alist in extlinux_priv. Must be called from the + * probe function of any driver that uses extlinux_priv. + * + * @dev: Bootmethod device + * Return: 0 if OK + */ +int extlinux_bootmeth_probe(struct udevice *dev); + /** * extlinux_bootmeth_remove() - Remove function for extlinux-based bootmeths * - * Frees the PXE context. Shared by extlinux and PXE drivers. + * Frees all cached PXE contexts in the alist. * * @dev: Bootmethod device * Return: 0 if OK */ int extlinux_bootmeth_remove(struct udevice *dev); +/** + * extlinux_get_ctx() - Get or allocate a PXE context for a bootflow + * + * If bflow->bootmeth_id already points to a valid context (e.g. from a + * prior read_all), return it. Otherwise allocate a new context in the + * alist and store its index in bflow->bootmeth_id. + * + * @priv: Private data for this bootmeth + * @bflow: Bootflow to get context for + * Return: Context, or NULL on allocation failure + */ +struct pxe_context *extlinux_get_ctx(struct extlinux_priv *priv, + struct bootflow *bflow); + /** * extlinux_set_property() - set an extlinux property * -- 2.43.0