// SPDX-License-Identifier: GPL-2.0+ /* * Common functions for extlinux and PXE * * Copyright 2024 Collabora * Written by Martyn Welch */ #define LOG_CATEGORY UCLASS_BOOTSTD #include #include #include #include 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; } 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) { struct extlinux_plat *plat = dev_get_plat(dev); int ret; plat->info.dev = dev; plat->info.bflow = bflow; ret = pxe_setup_ctx(ctx, getfile, &plat->info, allow_abs_path, bootfile, false, plat->use_fallback, bflow); if (ret) return log_msg_ret("ctx", ret); log_debug("bootfl flags %x\n", bflow->flags); if (bflow->flags & BOOTFLOWF_FAKE_GO) ctx->fake_go = true; return 0; } int extlinux_boot(struct udevice *dev, struct bootflow *bflow, pxe_getfile_func getfile, bool allow_abs_path, const char *bootfile, bool restart) { 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) { plat->ctx.fake_go = bflow->flags & BOOTFLOWF_FAKE_GO; ret = pxe_do_boot(&plat->ctx); } else { ret = extlinux_setup(dev, bflow, getfile, allow_abs_path, bootfile, &plat->ctx); if (ret) return log_msg_ret("elb", ret); plat->ctx.restart = restart; 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, bool allow_abs_path, const char *bootfile) { struct extlinux_plat *plat = dev_get_plat(dev); ulong addr; int ret; ret = extlinux_setup(dev, bflow, getfile, allow_abs_path, bootfile, &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("elb", -EFAULT); return 0; }