]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
efi_loader: net: set EFI bootdevice device path to HTTP when loaded from wget
authorAdriano Cordova <adrianox@gmail.com>
Wed, 4 Dec 2024 03:05:23 +0000 (00:05 -0300)
committerHeinrich Schuchardt <heinrich.schuchardt@canonical.com>
Wed, 4 Dec 2024 11:24:37 +0000 (12:24 +0100)
Set the device path of the efi boot device to an HTTP device path
(as formed by efi_dp_from_http) when the next boot stage is loaded
using wget (i.e., when wget is used with wget_info.set_bootdev=1).

When loaded from HTTP, the device path should account for it so that
the next boot stage is aware (e.g. grub only loads its http stack if
it itself was loaded from http, and it checks this from its device path).

Signed-off-by: Adriano Cordova <adrianox@gmail.com>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
include/efi_loader.h
lib/efi_loader/efi_bootbin.c
lib/efi_loader/efi_device_path.c
lib/efi_loader/efi_net.c
net/lwip/wget.c
net/wget.c

index 96b204dfc31636a6bd801fa15521002bf5d00b72..0da0248db46d5813cfdc78df2c9a5d740c47a12a 100644 (file)
@@ -126,6 +126,10 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr,
 #endif
 
 #if CONFIG_IS_ENABLED(NETDEVICES) && CONFIG_IS_ENABLED(EFI_LOADER)
+/* Call this to update the current device path of the efi net device */
+efi_status_t efi_net_set_dp(const char *dev, const char *server);
+/* Call this to get the current device path of the efi net device */
+void efi_net_get_dp(struct efi_device_path **dp);
 void efi_net_get_addr(struct efi_ipv4_address *ip,
                      struct efi_ipv4_address *mask,
                      struct efi_ipv4_address *gw);
@@ -133,6 +137,7 @@ void efi_net_set_addr(struct efi_ipv4_address *ip,
                      struct efi_ipv4_address *mask,
                      struct efi_ipv4_address *gw);
 #else
+static inline void efi_net_get_dp(struct efi_device_path **dp) { }
 static inline void efi_net_get_addr(struct efi_ipv4_address *ip,
                                     struct efi_ipv4_address *mask,
                                     struct efi_ipv4_address *gw) { }
index a87006b3c0ede5d33be16790cedfb183e1126491..b677bbc312447e9f39004cdf28ef3c8021110bc0 100644 (file)
@@ -93,24 +93,34 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
        image_addr = buffer;
        image_size = buffer_size;
 
+#if IS_ENABLED(CONFIG_NETDEVICES)
+       if (!strcmp(dev, "Net") || !strcmp(dev, "Http")) {
+               ret = efi_net_set_dp(dev, devnr);
+               if (ret != EFI_SUCCESS)
+                       goto error;
+       }
+#endif
+
        ret = efi_dp_from_name(dev, devnr, path, &device, &image);
-       if (ret == EFI_SUCCESS) {
-               bootefi_device_path = device;
-               if (image) {
-                       /* FIXME: image should not contain device */
-                       struct efi_device_path *image_tmp = image;
-
-                       efi_dp_split_file_path(image, &device, &image);
-                       efi_free_pool(image_tmp);
-               }
-               bootefi_image_path = image;
-               log_debug("- boot device %pD\n", device);
-               if (image)
-                       log_debug("- image %pD\n", image);
-       } else {
-               log_debug("- efi_dp_from_name() failed, err=%lx\n", ret);
-               efi_clear_bootdev();
+       if (ret != EFI_SUCCESS)
+               goto error;
+
+       bootefi_device_path = device;
+       if (image) {
+               /* FIXME: image should not contain device */
+               struct efi_device_path *image_tmp = image;
+
+               efi_dp_split_file_path(image, &device, &image);
+               efi_free_pool(image_tmp);
        }
+       bootefi_image_path = image;
+       log_debug("- boot device %pD\n", device);
+       if (image)
+               log_debug("- image %pD\n", image);
+       return;
+error:
+       log_debug("- efi_dp_from_name() failed, err=%lx\n", ret);
+       efi_clear_bootdev();
 }
 
 /**
index a6d4300686999c132f638eb7ed5920617f29de56..5eae6fd39ccc1eb6b3b1642fb828ca47fc6b39e4 100644 (file)
@@ -1185,8 +1185,9 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
 
                dp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
                                     (uintptr_t)image_addr, image_size);
-       } else if (IS_ENABLED(CONFIG_NETDEVICES) && !strcmp(dev, "Net")) {
-               dp = efi_dp_from_eth();
+       } else if (IS_ENABLED(CONFIG_NETDEVICES) &&
+                  (!strcmp(dev, "Net") || !strcmp(dev, "Http"))) {
+               efi_net_get_dp(&dp);
        } else if (!strcmp(dev, "Uart")) {
                dp = efi_dp_from_uart();
        } else {
index 3491d4c4818814960acdc264a7efb5b2074e4edd..e8af2e3d95e02af37215630fcd3277ef74dd82ef 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <efi_loader.h>
+#include <dm.h>
 #include <malloc.h>
 #include <vsprintf.h>
 #include <net.h>
@@ -32,6 +33,13 @@ static int rx_packet_idx;
 static int rx_packet_num;
 static struct efi_net_obj *netobj;
 
+/*
+ * The current network device path. This device path is updated when a new
+ * bootfile is downloaded from the network. If then the bootfile is loaded
+ * as an efi image, net_dp is passed as the device path of the loaded image.
+ */
+static struct efi_device_path *net_dp;
+
 /*
  * The notification function of this event is called in every timer cycle
  * to check if a new network packet has been received.
@@ -902,8 +910,10 @@ efi_status_t efi_net_register(void)
                             &netobj->net);
        if (r != EFI_SUCCESS)
                goto failure_to_add_protocol;
+       if (!net_dp)
+               efi_net_set_dp("Net", NULL);
        r = efi_add_protocol(&netobj->header, &efi_guid_device_path,
-                            efi_dp_from_eth());
+                            net_dp);
        if (r != EFI_SUCCESS)
                goto failure_to_add_protocol;
        r = efi_add_protocol(&netobj->header, &efi_pxe_base_code_protocol_guid,
@@ -999,6 +1009,49 @@ out_of_resources:
        return EFI_OUT_OF_RESOURCES;
 }
 
+/**
+ * efi_net_set_dp() - set device path of efi net device
+ *
+ * This gets called to update the device path when a new boot
+ * file is downloaded
+ *
+ * @dev:       dev to set the device path from
+ * @server:    remote server address
+ * Return:     status code
+ */
+efi_status_t efi_net_set_dp(const char *dev, const char *server)
+{
+       efi_free_pool(net_dp);
+
+       net_dp = NULL;
+       if (!strcmp(dev, "Net"))
+               net_dp = efi_dp_from_eth();
+       else if (!strcmp(dev, "Http"))
+               net_dp = efi_dp_from_http(server);
+
+       if (!net_dp)
+               return EFI_OUT_OF_RESOURCES;
+
+       return EFI_SUCCESS;
+}
+
+/**
+ * efi_net_get_dp() - get device path of efi net device
+ *
+ * Produce a copy of the current device path
+ *
+ * @dp:                copy of the current device path, or NULL on error
+ */
+void efi_net_get_dp(struct efi_device_path **dp)
+{
+       if (!dp)
+               return;
+       if (!net_dp)
+               efi_net_set_dp("Net", NULL);
+       if (net_dp)
+               *dp = efi_dp_dup(net_dp);
+}
+
 /**
  * efi_net_get_addr() - get IP address information
  *
index 669eded0f38c05ab24fecaec291f937790cab191..c23f0640ec66c409e29061c6a96828abbcb44061 100644 (file)
@@ -260,10 +260,9 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result,
        printf("%u bytes transferred in %lu ms (", rx_content_len, elapsed);
        print_size(rx_content_len / elapsed * 1000, "/s)\n");
        printf("Bytes transferred = %lu (%lx hex)\n", ctx->size, ctx->size);
-       if (wget_info->set_bootdev) {
-               efi_set_bootdev("Net", "", ctx->path, map_sysmem(ctx->saved_daddr, 0),
+       if (wget_info->set_bootdev)
+               efi_set_bootdev("Http", ctx->server_name, ctx->path, map_sysmem(ctx->saved_daddr, 0),
                                rx_content_len);
-       }
        wget_lwip_set_file_size(rx_content_len);
        if (env_set_hex("filesize", rx_content_len) ||
            env_set_hex("fileaddr", ctx->saved_daddr)) {
index f3b43b06b8b53f03f9bda091147185dcc23ad085..d338eaf4ef38fe253ea3b3ef122d283350a34588 100644 (file)
@@ -447,7 +447,7 @@ static void wget_handler(uchar *pkt, u16 dport,
                net_set_state(wget_loop_state);
                wget_info->file_size = net_boot_file_size;
                if (wget_info->method == WGET_HTTP_METHOD_GET && wget_info->set_bootdev) {
-                       efi_set_bootdev("Net", "", image_url,
+                       efi_set_bootdev("Http", NULL, image_url,
                                        map_sysmem(image_load_addr, 0),
                                        net_boot_file_size);
                        env_set_hex("filesize", net_boot_file_size);