1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-09-01 08:42:12 +02:00

bootstd: Allow reading an EFI file from the network

At present this bootmeth only supports reading from a filesystem. Add
support for reading from a network also, using DHCP with autoload.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2023-01-17 10:47:55 -07:00
committed by Tom Rini
parent 865328c314
commit 3e18860e3f

View File

@@ -19,6 +19,7 @@
#include <malloc.h>
#include <mapmem.h>
#include <mmc.h>
#include <net.h>
#include <pxe_utils.h>
#define EFI_DIRNAME "efi/boot/"
@@ -59,6 +60,40 @@ static int get_efi_leafname(char *str, int max_len)
return 0;
}
static int get_efi_pxe_arch(void)
{
/* http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml */
if (IS_ENABLED(CONFIG_ARM64))
return 0xb;
else if (IS_ENABLED(CONFIG_ARM))
return 0xa;
else if (IS_ENABLED(CONFIG_X86_64))
return 0x6;
else if (IS_ENABLED(CONFIG_X86))
return 0x7;
else if (IS_ENABLED(CONFIG_ARCH_RV32I))
return 0x19;
else if (IS_ENABLED(CONFIG_ARCH_RV64I))
return 0x1b;
else if (IS_ENABLED(CONFIG_SANDBOX))
return 0; /* not used */
return -EINVAL;
}
static int get_efi_pxe_vci(char *str, int max_len)
{
int ret;
ret = get_efi_pxe_arch();
if (ret < 0)
return ret;
snprintf(str, max_len, "PXEClient:Arch:%05x:UNDI:003000", ret);
return 0;
}
static int efiload_read_file(struct blk_desc *desc, struct bootflow *bflow)
{
const struct udevice *media_dev;
@@ -101,20 +136,18 @@ static int efiload_read_file(struct blk_desc *desc, struct bootflow *bflow)
static int distro_efi_check(struct udevice *dev, struct bootflow_iter *iter)
{
int ret;
/* This only works on block devices */
ret = bootflow_iter_check_blk(iter);
if (ret)
return log_msg_ret("blk", ret);
/* This only works on block and network devices */
if (bootflow_iter_check_blk(iter) && bootflow_iter_check_net(iter))
return log_msg_ret("blk", -ENOTSUPP);
return 0;
}
static int distro_efi_read_bootflow(struct udevice *dev, struct bootflow *bflow)
static int distro_efi_read_bootflow_file(struct udevice *dev,
struct bootflow *bflow)
{
struct blk_desc *desc = NULL;
char fname[sizeof(EFI_DIRNAME) + 16];
char fname[256];
int ret;
/* We require a partition table */
@@ -140,6 +173,74 @@ static int distro_efi_read_bootflow(struct udevice *dev, struct bootflow *bflow)
return 0;
}
static int distro_efi_read_bootflow_net(struct bootflow *bflow)
{
const char *addr_str;
int ret, arch, size;
char str[36];
ulong addr;
ret = get_efi_pxe_vci(str, sizeof(str));
if (ret)
return log_msg_ret("vci", ret);
ret = get_efi_pxe_arch();
if (ret < 0)
return log_msg_ret("arc", ret);
arch = ret;
ret = env_set("bootp_vci", str);
if (ret)
return log_msg_ret("vcs", ret);
ret = env_set_ulong("bootp_arch", arch);
if (ret)
return log_msg_ret("ars", ret);
/* figure out the load address */
addr_str = env_get("kernel_addr_r");
addr = addr_str ? hextoul(addr_str, NULL) : image_load_addr;
/* clear any previous bootfile */
env_set("bootfile", NULL);
/* read the kernel */
ret = dhcp_run(addr, NULL, true);
if (ret)
return log_msg_ret("dhc", ret);
size = env_get_hex("filesize", -1);
if (size <= 0)
return log_msg_ret("sz", -EINVAL);
bflow->size = size;
/* do the hideous EFI hack */
efi_set_bootdev("Net", "", bflow->fname, map_sysmem(addr, 0),
bflow->size);
bflow->state = BOOTFLOWST_READY;
return 0;
}
static int distro_efi_read_bootflow(struct udevice *dev, struct bootflow *bflow)
{
const struct udevice *media = dev_get_parent(bflow->dev);
int ret;
if (IS_ENABLED(CONFIG_CMD_DHCP) &&
device_get_uclass_id(media) == UCLASS_ETH) {
/* we only support reading from one device, so ignore 'dev' */
ret = distro_efi_read_bootflow_net(bflow);
if (ret)
return log_msg_ret("net", ret);
} else {
ret = distro_efi_read_bootflow_file(dev, bflow);
if (ret)
return log_msg_ret("blk", ret);
}
return 0;
}
int distro_efi_boot(struct udevice *dev, struct bootflow *bflow)
{
char cmd[50];