efi_loader: efi_net: Add device path cache

In preparation to support mutiple efi net udevices. Add a device path
cache to support device paths from multiple ethernet udevices.
The device paths can be added to the cache before EFI gets initialized and
the protocols get installed.

Signed-off-by: Adriano Cordova <adriano.cordova@canonical.com>
This commit is contained in:
Adriano Cordova
2025-03-03 11:13:15 -03:00
committed by Heinrich Schuchardt
parent 267b0a7ddf
commit dd5d82a599
7 changed files with 255 additions and 62 deletions

View File

@@ -129,15 +129,17 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr,
#if CONFIG_IS_ENABLED(NETDEVICES) && CONFIG_IS_ENABLED(EFI_LOADER) #if CONFIG_IS_ENABLED(NETDEVICES) && CONFIG_IS_ENABLED(EFI_LOADER)
/* Call this to update the current device path of the efi net device */ /* 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); efi_status_t efi_net_new_dp(const char *dev, const char *server, struct udevice *udev);
/* Call this to get the current device path of the efi net device */ /* 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_dp_from_dev(struct efi_device_path **dp, struct udevice *udev, bool cache_only);
void efi_net_get_addr(struct efi_ipv4_address *ip, void efi_net_get_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask, struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw); struct efi_ipv4_address *gw,
struct udevice *dev);
void efi_net_set_addr(struct efi_ipv4_address *ip, void efi_net_set_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask, struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw); struct efi_ipv4_address *gw,
struct udevice *dev);
efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buffer, efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buffer,
u32 *status_code, ulong *file_size, char *headers_buffer); u32 *status_code, ulong *file_size, char *headers_buffer);
#define MAX_HTTP_HEADERS_SIZE SZ_64K #define MAX_HTTP_HEADERS_SIZE SZ_64K
@@ -151,13 +153,16 @@ struct http_header {
void efi_net_parse_headers(ulong *num_headers, struct http_header *headers); void efi_net_parse_headers(ulong *num_headers, struct http_header *headers);
#else #else
static inline void efi_net_get_dp(struct efi_device_path **dp) { } static inline void efi_net_dp_from_dev(struct efi_device_path **dp,
struct udevice *udev, bool cache_only) { }
static inline void efi_net_get_addr(struct efi_ipv4_address *ip, static inline void efi_net_get_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask, struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw) { } struct efi_ipv4_address *gw,
struct udevice *dev) { }
static inline void efi_net_set_addr(struct efi_ipv4_address *ip, static inline void efi_net_set_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask, struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw) { } struct efi_ipv4_address *gw,
struct udevice *dev) { }
#endif #endif
/* Maximum number of configuration tables */ /* Maximum number of configuration tables */
@@ -649,8 +654,8 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
/* Called by bootefi to make GOP (graphical) interface available */ /* Called by bootefi to make GOP (graphical) interface available */
efi_status_t efi_gop_register(void); efi_status_t efi_gop_register(void);
/* Called by bootefi to make the network interface available */ /* Called by bootefi to make the network interface available */
efi_status_t efi_net_register(void); efi_status_t efi_net_register(struct udevice *dev);
efi_status_t efi_net_do_start(void); efi_status_t efi_net_do_start(struct udevice *dev);
/* Called by efi_net_register to make the ip4 config2 protocol available */ /* Called by efi_net_register to make the ip4 config2 protocol available */
efi_status_t efi_ipconfig_register(const efi_handle_t handle, efi_status_t efi_ipconfig_register(const efi_handle_t handle,
struct efi_ip4_config2_protocol *ip4config); struct efi_ip4_config2_protocol *ip4config);

View File

@@ -16,6 +16,7 @@
#include <log.h> #include <log.h>
#include <malloc.h> #include <malloc.h>
#include <mapmem.h> #include <mapmem.h>
#include <net.h>
static struct efi_device_path *bootefi_image_path; static struct efi_device_path *bootefi_image_path;
static struct efi_device_path *bootefi_device_path; static struct efi_device_path *bootefi_device_path;
@@ -67,7 +68,7 @@ static efi_status_t calculate_paths(const char *dev, const char *devnr,
#if IS_ENABLED(CONFIG_NETDEVICES) #if IS_ENABLED(CONFIG_NETDEVICES)
if (!strcmp(dev, "Net") || !strcmp(dev, "Http")) { if (!strcmp(dev, "Net") || !strcmp(dev, "Http")) {
ret = efi_net_set_dp(dev, devnr); ret = efi_net_new_dp(dev, devnr, eth_get_dev());
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
return ret; return ret;
} }

View File

@@ -1048,7 +1048,7 @@ struct efi_device_path *efi_dp_from_http(const char *server, struct udevice *dev
(!server && IS_ENABLED(CONFIG_NET_LWIP))) (!server && IS_ENABLED(CONFIG_NET_LWIP)))
return NULL; return NULL;
efi_net_get_addr(&ip, &mask, NULL); efi_net_get_addr(&ip, &mask, NULL, dev);
dp1 = efi_dp_from_ipv4(&ip, &mask, NULL, dev); dp1 = efi_dp_from_ipv4(&ip, &mask, NULL, dev);
if (!dp1) if (!dp1)
@@ -1190,7 +1190,7 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
(uintptr_t)image_addr, image_size); (uintptr_t)image_addr, image_size);
} else if (IS_ENABLED(CONFIG_NETDEVICES) && } else if (IS_ENABLED(CONFIG_NETDEVICES) &&
(!strcmp(dev, "Net") || !strcmp(dev, "Http"))) { (!strcmp(dev, "Net") || !strcmp(dev, "Http"))) {
efi_net_get_dp(&dp); efi_net_dp_from_dev(&dp, eth_get_dev(), false);
} else if (!strcmp(dev, "Uart")) { } else if (!strcmp(dev, "Uart")) {
dp = efi_dp_from_uart(); dp = efi_dp_from_uart();
} else { } else {

View File

@@ -188,7 +188,7 @@ static efi_status_t EFIAPI efi_http_configure(struct efi_http_protocol *this,
if (!ipv4_node->use_default_address) { if (!ipv4_node->use_default_address) {
efi_net_set_addr((struct efi_ipv4_address *)&ipv4_node->local_address, efi_net_set_addr((struct efi_ipv4_address *)&ipv4_node->local_address,
(struct efi_ipv4_address *)&ipv4_node->local_subnet, NULL); (struct efi_ipv4_address *)&ipv4_node->local_subnet, NULL, NULL);
} }
http_instance->current_offset = 0; http_instance->current_offset = 0;

View File

@@ -60,7 +60,7 @@ static efi_status_t EFIAPI efi_ip4_config2_set_data(struct efi_ip4_config2_proto
memcpy((void *)&current_http_ip, data, memcpy((void *)&current_http_ip, data,
sizeof(struct efi_ip4_config2_manual_address)); sizeof(struct efi_ip4_config2_manual_address));
efi_net_set_addr(&current_http_ip.address, efi_net_set_addr(&current_http_ip.address,
&current_http_ip.subnet_mask, NULL); &current_http_ip.subnet_mask, NULL, NULL);
return EFI_EXIT(EFI_SUCCESS); return EFI_EXIT(EFI_SUCCESS);
} }
return EFI_EXIT(EFI_BAD_BUFFER_SIZE); return EFI_EXIT(EFI_BAD_BUFFER_SIZE);
@@ -133,7 +133,7 @@ static efi_status_t EFIAPI efi_ip4_config2_get_data(struct efi_ip4_config2_proto
return EFI_EXIT(EFI_BUFFER_TOO_SMALL); return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
} }
efi_net_get_addr(&current_http_ip.address, &current_http_ip.subnet_mask, NULL); efi_net_get_addr(&current_http_ip.address, &current_http_ip.subnet_mask, NULL, NULL);
memcpy(data, (void *)&current_http_ip, memcpy(data, (void *)&current_http_ip,
sizeof(struct efi_ip4_config2_manual_address)); sizeof(struct efi_ip4_config2_manual_address));

View File

@@ -24,6 +24,8 @@
#include <vsprintf.h> #include <vsprintf.h>
#include <net.h> #include <net.h>
#define MAX_NUM_DP_ENTRIES 10
const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
static const efi_guid_t efi_pxe_base_code_protocol_guid = static const efi_guid_t efi_pxe_base_code_protocol_guid =
EFI_PXE_BASE_CODE_PROTOCOL_GUID; EFI_PXE_BASE_CODE_PROTOCOL_GUID;
@@ -36,18 +38,28 @@ static int rx_packet_idx;
static int rx_packet_num; static int rx_packet_num;
static struct efi_net_obj *netobj; static struct efi_net_obj *netobj;
/* struct dp_entry {
* The current network device path. This device path is updated when a new struct efi_device_path *net_dp;
* bootfile is downloaded from the network. If then the bootfile is loaded struct udevice *dev;
* as an efi image, net_dp is passed as the device path of the loaded image. bool is_valid;
*/ };
static struct efi_device_path *net_dp;
/*
* The network device path cache. An entry is added when a new bootfile
* is downloaded from the network. If the bootfile is then loaded as an
* efi image, the most recent entry corresponding to the device is passed
* as the device path of the loaded image.
*/
static struct dp_entry dp_cache[MAX_NUM_DP_ENTRIES];
static int next_dp_entry;
#if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL)
static struct wget_http_info efi_wget_info = { static struct wget_http_info efi_wget_info = {
.set_bootdev = false, .set_bootdev = false,
.check_buffer_size = true, .check_buffer_size = true,
}; };
#endif
/* /*
* The notification function of this event is called in every timer cycle * The notification function of this event is called in every timer cycle
@@ -63,6 +75,7 @@ static struct efi_event *wait_for_packet;
* struct efi_net_obj - EFI object representing a network interface * struct efi_net_obj - EFI object representing a network interface
* *
* @header: EFI object header * @header: EFI object header
* @dev: net udevice
* @net: simple network protocol interface * @net: simple network protocol interface
* @net_mode: status of the network interface * @net_mode: status of the network interface
* @pxe: PXE base code protocol interface * @pxe: PXE base code protocol interface
@@ -72,6 +85,7 @@ static struct efi_event *wait_for_packet;
*/ */
struct efi_net_obj { struct efi_net_obj {
struct efi_object header; struct efi_object header;
struct udevice *dev;
struct efi_simple_network net; struct efi_simple_network net;
struct efi_simple_network_mode net_mode; struct efi_simple_network_mode net_mode;
struct efi_pxe_base_code_protocol pxe; struct efi_pxe_base_code_protocol pxe;
@@ -84,6 +98,21 @@ struct efi_net_obj {
#endif #endif
}; };
/*
* efi_netobj_is_active() - checks if a netobj is active in the efi subsystem
*
* @netobj: pointer to efi_net_obj
* Return: true if active
*/
static bool efi_netobj_is_active(struct efi_net_obj *netobj)
{
if (!netobj || !efi_search_obj(&netobj->header))
return false;
return true;
}
/* /*
* efi_net_start() - start the network interface * efi_net_start() - start the network interface
* *
@@ -99,7 +128,6 @@ static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
efi_status_t ret = EFI_SUCCESS; efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p", this); EFI_ENTRY("%p", this);
/* Check parameters */ /* Check parameters */
if (!this) { if (!this) {
ret = EFI_INVALID_PARAMETER; ret = EFI_INVALID_PARAMETER;
@@ -143,6 +171,8 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
ret = EFI_NOT_STARTED; ret = EFI_NOT_STARTED;
} else { } else {
/* Disable hardware and put it into the reset state */ /* Disable hardware and put it into the reset state */
eth_set_dev(netobj->dev);
env_set("ethact", eth_get_name());
eth_halt(); eth_halt();
/* Clear cache of packets */ /* Clear cache of packets */
rx_packet_num = 0; rx_packet_num = 0;
@@ -189,14 +219,13 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
/* Setup packet buffers */ /* Setup packet buffers */
net_init(); net_init();
/* Disable hardware and put it into the reset state */
eth_halt();
/* Clear cache of packets */ /* Clear cache of packets */
rx_packet_num = 0; rx_packet_num = 0;
/* Set current device according to environment variables */ /* Set the net device corresponding to the efi net object */
eth_set_current(); eth_set_dev(netobj->dev);
env_set("ethact", eth_get_name());
/* Get hardware ready for send and receive operations */ /* Get hardware ready for send and receive operations */
ret = eth_init(); ret = eth_start_udev(netobj->dev);
if (ret < 0) { if (ret < 0) {
eth_halt(); eth_halt();
this->mode->state = EFI_NETWORK_STOPPED; this->mode->state = EFI_NETWORK_STOPPED;
@@ -285,6 +314,8 @@ static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
goto out; goto out;
} }
eth_set_dev(netobj->dev);
env_set("ethact", eth_get_name());
eth_halt(); eth_halt();
this->int_status = 0; this->int_status = 0;
wait_for_packet->is_signaled = false; wait_for_packet->is_signaled = false;
@@ -576,6 +607,9 @@ static efi_status_t EFIAPI efi_net_transmit
break; break;
} }
eth_set_dev(netobj->dev);
env_set("ethact", eth_get_name());
/* Ethernet packets always fit, just bounce */ /* Ethernet packets always fit, just bounce */
memcpy(transmit_buffer, buffer, buffer_size); memcpy(transmit_buffer, buffer, buffer_size);
net_send_packet(transmit_buffer, buffer_size); net_send_packet(transmit_buffer, buffer_size);
@@ -753,6 +787,8 @@ static void EFIAPI efi_network_timer_notify(struct efi_event *event,
goto out; goto out;
if (!rx_packet_num) { if (!rx_packet_num) {
eth_set_dev(netobj->dev);
env_set("ethact", eth_get_name());
push_packet = efi_net_push; push_packet = efi_net_push;
eth_rx(); eth_rx();
push_packet = NULL; push_packet = NULL;
@@ -878,17 +914,106 @@ static efi_status_t EFIAPI efi_pxe_base_code_set_packets(
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
/**
* efi_netobj_set_dp() - set device path of a netobj
*
* @netobj: pointer to efi_net_obj
* @dp: device path to set, allocated by caller
* Return: status code
*/
efi_status_t efi_netobj_set_dp(struct efi_net_obj *netobj, struct efi_device_path *dp)
{
efi_status_t ret;
struct efi_handler *phandler;
struct efi_device_path *new_net_dp;
if (!efi_netobj_is_active(netobj))
return EFI_SUCCESS;
// Create a device path for the netobj
new_net_dp = dp;
if (!new_net_dp)
return EFI_OUT_OF_RESOURCES;
phandler = NULL;
efi_search_protocol(&netobj->header, &efi_guid_device_path, &phandler);
// If the device path protocol is not yet installed, install it
if (!phandler)
goto add;
// If it is already installed, try to update it
ret = efi_reinstall_protocol_interface(&netobj->header, &efi_guid_device_path,
phandler->protocol_interface, new_net_dp);
if (ret != EFI_SUCCESS)
return ret;
return EFI_SUCCESS;
add:
ret = efi_add_protocol(&netobj->header, &efi_guid_device_path,
new_net_dp);
if (ret != EFI_SUCCESS)
return ret;
return EFI_SUCCESS;
}
/**
* efi_netobj_get_dp() - get device path of a netobj
*
* @netobj: pointer to efi_net_obj
* Return: device path, NULL on error
*/
static struct efi_device_path *efi_netobj_get_dp(struct efi_net_obj *netobj)
{
struct efi_handler *phandler;
if (!efi_netobj_is_active(netobj))
return NULL;
phandler = NULL;
efi_search_protocol(&netobj->header, &efi_guid_device_path, &phandler);
if (phandler && phandler->protocol_interface)
return efi_dp_dup(phandler->protocol_interface);
return NULL;
}
/** /**
* efi_net_do_start() - start the efi network stack * efi_net_do_start() - start the efi network stack
* *
* This gets called from do_bootefi_exec() each time a payload gets executed. * This gets called from do_bootefi_exec() each time a payload gets executed.
* *
* @dev: net udevice
* Return: status code * Return: status code
*/ */
efi_status_t efi_net_do_start(void) efi_status_t efi_net_do_start(struct udevice *dev)
{ {
efi_status_t r = EFI_SUCCESS; efi_status_t r = EFI_SUCCESS;
struct efi_device_path *net_dp;
if (dev != netobj->dev )
return r;
efi_net_dp_from_dev(&net_dp, netobj->dev, true);
// If no dp cache entry applies and there already
// is a device path installed, continue
if (!net_dp) {
if (efi_netobj_get_dp(netobj))
goto set_addr;
else
net_dp = efi_dp_from_eth(netobj->dev);
}
if (!net_dp)
return EFI_OUT_OF_RESOURCES;
r = efi_netobj_set_dp(netobj, net_dp);
if (r != EFI_SUCCESS)
return r;
set_addr:
#ifdef CONFIG_EFI_HTTP_PROTOCOL #ifdef CONFIG_EFI_HTTP_PROTOCOL
/* /*
* No harm on doing the following. If the PXE handle is present, the client could * No harm on doing the following. If the PXE handle is present, the client could
@@ -896,7 +1021,7 @@ efi_status_t efi_net_do_start(void)
* but the PXE protocol is not yet implmenented, so we add this in the meantime. * but the PXE protocol is not yet implmenented, so we add this in the meantime.
*/ */
efi_net_get_addr((struct efi_ipv4_address *)&netobj->pxe_mode.station_ip, efi_net_get_addr((struct efi_ipv4_address *)&netobj->pxe_mode.station_ip,
(struct efi_ipv4_address *)&netobj->pxe_mode.subnet_mask, NULL); (struct efi_ipv4_address *)&netobj->pxe_mode.subnet_mask, NULL, dev);
#endif #endif
return r; return r;
@@ -906,13 +1031,14 @@ efi_status_t efi_net_do_start(void)
* efi_net_register() - register the simple network protocol * efi_net_register() - register the simple network protocol
* *
* This gets called from do_bootefi_exec(). * This gets called from do_bootefi_exec().
* @dev: net udevice
*/ */
efi_status_t efi_net_register(void) efi_status_t efi_net_register(struct udevice *dev)
{ {
efi_status_t r; efi_status_t r;
int i; int i;
if (!eth_get_dev()) { if (!dev) {
/* No network device active, don't expose any */ /* No network device active, don't expose any */
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@@ -922,6 +1048,8 @@ efi_status_t efi_net_register(void)
if (!netobj) if (!netobj)
goto out_of_resources; goto out_of_resources;
netobj->dev = dev;
/* Allocate an aligned transmit buffer */ /* Allocate an aligned transmit buffer */
transmit_buffer = calloc(1, PKTSIZE_ALIGN + PKTALIGN); transmit_buffer = calloc(1, PKTSIZE_ALIGN + PKTALIGN);
if (!transmit_buffer) if (!transmit_buffer)
@@ -938,6 +1066,7 @@ efi_status_t efi_net_register(void)
if (!receive_buffer[i]) if (!receive_buffer[i])
goto out_of_resources; goto out_of_resources;
} }
receive_lengths = calloc(ETH_PACKETS_BATCH_RECV, receive_lengths = calloc(ETH_PACKETS_BATCH_RECV,
sizeof(*receive_lengths)); sizeof(*receive_lengths));
if (!receive_lengths) if (!receive_lengths)
@@ -952,12 +1081,6 @@ efi_status_t efi_net_register(void)
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
goto failure_to_add_protocol; goto failure_to_add_protocol;
if (!net_dp)
efi_net_set_dp("Net", NULL);
r = efi_add_protocol(&netobj->header, &efi_guid_device_path,
net_dp);
if (r != EFI_SUCCESS)
goto failure_to_add_protocol;
r = efi_add_protocol(&netobj->header, &efi_pxe_base_code_protocol_guid, r = efi_add_protocol(&netobj->header, &efi_pxe_base_code_protocol_guid,
&netobj->pxe); &netobj->pxe);
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
@@ -978,7 +1101,9 @@ efi_status_t efi_net_register(void)
netobj->net.receive = efi_net_receive; netobj->net.receive = efi_net_receive;
netobj->net.mode = &netobj->net_mode; netobj->net.mode = &netobj->net_mode;
netobj->net_mode.state = EFI_NETWORK_STOPPED; netobj->net_mode.state = EFI_NETWORK_STOPPED;
memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6); if (dev_get_plat(dev))
memcpy(netobj->net_mode.current_address.mac_addr,
((struct eth_pdata *)dev_get_plat(dev))->enetaddr, 6);
netobj->net_mode.hwaddr_size = ARP_HLEN; netobj->net_mode.hwaddr_size = ARP_HLEN;
netobj->net_mode.media_header_size = ETHER_HDR_SIZE; netobj->net_mode.media_header_size = ETHER_HDR_SIZE;
netobj->net_mode.max_packet_size = PKTSIZE; netobj->net_mode.max_packet_size = PKTSIZE;
@@ -1012,6 +1137,7 @@ efi_status_t efi_net_register(void)
return r; return r;
} }
netobj->net.wait_for_packet = wait_for_packet; netobj->net.wait_for_packet = wait_for_packet;
/* /*
* Create a timer event. * Create a timer event.
* *
@@ -1045,7 +1171,6 @@ efi_status_t efi_net_register(void)
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
goto failure_to_add_protocol; goto failure_to_add_protocol;
#endif #endif
return EFI_SUCCESS; return EFI_SUCCESS;
failure_to_add_protocol: failure_to_add_protocol:
printf("ERROR: Failure to add protocol\n"); printf("ERROR: Failure to add protocol\n");
@@ -1064,46 +1189,91 @@ out_of_resources:
} }
/** /**
* efi_net_set_dp() - set device path of efi net device * efi_net_new_dp() - update device path associated to a net udevice
* *
* This gets called to update the device path when a new boot * This gets called to update the device path when a new boot
* file is downloaded * file is downloaded
* *
* @dev: dev to set the device path from * @dev: dev to set the device path from
* @server: remote server address * @server: remote server address
* @udev: net udevice
* Return: status code * Return: status code
*/ */
efi_status_t efi_net_set_dp(const char *dev, const char *server) efi_status_t efi_net_new_dp(const char *dev, const char *server, struct udevice *udev)
{ {
efi_free_pool(net_dp); efi_status_t ret;
struct efi_device_path *old_net_dp, *new_net_dp;
struct efi_device_path **dp;
net_dp = NULL; dp = &dp_cache[next_dp_entry].net_dp;
dp_cache[next_dp_entry].dev = udev;
dp_cache[next_dp_entry].is_valid = true;
next_dp_entry++;
next_dp_entry %= MAX_NUM_DP_ENTRIES;
old_net_dp = *dp;
new_net_dp = NULL;
if (!strcmp(dev, "Net")) if (!strcmp(dev, "Net"))
net_dp = efi_dp_from_eth(eth_get_dev()); new_net_dp = efi_dp_from_eth(udev);
else if (!strcmp(dev, "Http")) else if (!strcmp(dev, "Http"))
net_dp = efi_dp_from_http(server, eth_get_dev()); new_net_dp = efi_dp_from_http(server, udev);
if (!new_net_dp)
if (!net_dp)
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
*dp = new_net_dp;
// Free the old cache entry
efi_free_pool(old_net_dp);
if (!netobj || netobj->dev != udev)
return EFI_SUCCESS; return EFI_SUCCESS;
new_net_dp = efi_dp_dup(*dp);
if (!new_net_dp)
return EFI_OUT_OF_RESOURCES;
ret = efi_netobj_set_dp(netobj, new_net_dp);
if (ret != EFI_SUCCESS)
efi_free_pool(new_net_dp);
return ret;
} }
/** /**
* efi_net_get_dp() - get device path of efi net device * efi_net_dp_from_dev() - get device path associated to a net udevice
* *
* Produce a copy of the current device path * Produce a copy of the current device path
* *
* @dp: copy of the current device path, or NULL on error * @dp: copy of the current device path
* @udev: net udevice
* @cache_only: get device path from cache only
*/ */
void efi_net_get_dp(struct efi_device_path **dp) void efi_net_dp_from_dev(struct efi_device_path **dp, struct udevice *udev, bool cache_only)
{ {
int i, j;
if (!dp) if (!dp)
return; return;
if (!net_dp)
efi_net_set_dp("Net", NULL); *dp = NULL;
if (net_dp)
*dp = efi_dp_dup(net_dp); if (cache_only)
goto cache;
if (netobj && netobj->dev == udev) {
*dp = efi_netobj_get_dp(netobj);
if (*dp)
return;
}
cache:
// Search in the cache
i = (next_dp_entry + MAX_NUM_DP_ENTRIES - 1) % MAX_NUM_DP_ENTRIES;
for (j = 0; dp_cache[i].is_valid && j < MAX_NUM_DP_ENTRIES;
i = (i + MAX_NUM_DP_ENTRIES - 1) % MAX_NUM_DP_ENTRIES, j++) {
if (dp_cache[i].dev == udev) {
*dp = efi_dp_dup(dp_cache[i].net_dp);
return;
}
}
} }
/** /**
@@ -1119,11 +1289,15 @@ void efi_net_get_dp(struct efi_device_path **dp)
* be filled with the current network mask * be filled with the current network mask
* @gw: pointer to an efi_ipv4_address struct to be * @gw: pointer to an efi_ipv4_address struct to be
* filled with the current network gateway * filled with the current network gateway
* @dev: udevice
*/ */
void efi_net_get_addr(struct efi_ipv4_address *ip, void efi_net_get_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask, struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw) struct efi_ipv4_address *gw,
struct udevice *dev)
{ {
if (!dev)
dev = eth_get_dev();
#ifdef CONFIG_NET_LWIP #ifdef CONFIG_NET_LWIP
char ipstr[] = "ipaddr\0\0"; char ipstr[] = "ipaddr\0\0";
char maskstr[] = "netmask\0\0"; char maskstr[] = "netmask\0\0";
@@ -1132,7 +1306,7 @@ void efi_net_get_addr(struct efi_ipv4_address *ip,
struct in_addr tmp; struct in_addr tmp;
char *env; char *env;
idx = dev_seq(eth_get_dev()); idx = dev_seq(dev);
if (idx < 0 || idx > 99) { if (idx < 0 || idx > 99) {
log_err("unexpected idx %d\n", idx); log_err("unexpected idx %d\n", idx);
@@ -1179,11 +1353,15 @@ void efi_net_get_addr(struct efi_ipv4_address *ip,
* @ip: pointer to new IP address * @ip: pointer to new IP address
* @mask: pointer to new network mask to set * @mask: pointer to new network mask to set
* @gw: pointer to new network gateway * @gw: pointer to new network gateway
* @dev: udevice
*/ */
void efi_net_set_addr(struct efi_ipv4_address *ip, void efi_net_set_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask, struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw) struct efi_ipv4_address *gw,
struct udevice *dev)
{ {
if (!dev)
dev = eth_get_dev();
#ifdef CONFIG_NET_LWIP #ifdef CONFIG_NET_LWIP
char ipstr[] = "ipaddr\0\0"; char ipstr[] = "ipaddr\0\0";
char maskstr[] = "netmask\0\0"; char maskstr[] = "netmask\0\0";
@@ -1192,7 +1370,7 @@ void efi_net_set_addr(struct efi_ipv4_address *ip,
struct in_addr *addr; struct in_addr *addr;
char tmp[46]; char tmp[46];
idx = dev_seq(eth_get_dev()); idx = dev_seq(dev);
if (idx < 0 || idx > 99) { if (idx < 0 || idx > 99) {
log_err("unexpected idx %d\n", idx); log_err("unexpected idx %d\n", idx);
@@ -1230,6 +1408,7 @@ void efi_net_set_addr(struct efi_ipv4_address *ip,
#endif #endif
} }
#if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL)
/** /**
* efi_net_set_buffer() - allocate a buffer of min 64K * efi_net_set_buffer() - allocate a buffer of min 64K
* *
@@ -1337,6 +1516,8 @@ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buf
ret = efi_net_set_buffer(buffer, last_head ? (size_t)efi_wget_info.hdr_cont_len : 0); ret = efi_net_set_buffer(buffer, last_head ? (size_t)efi_wget_info.hdr_cont_len : 0);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
goto out; goto out;
eth_set_dev(netobj->dev);
env_set("ethact", eth_get_name());
wget_ret = wget_request((ulong)*buffer, url, &efi_wget_info); wget_ret = wget_request((ulong)*buffer, url, &efi_wget_info);
if ((ulong)efi_wget_info.hdr_cont_len > efi_wget_info.buffer_size) { if ((ulong)efi_wget_info.hdr_cont_len > efi_wget_info.buffer_size) {
// Try again with updated buffer size // Try again with updated buffer size
@@ -1344,6 +1525,8 @@ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buf
ret = efi_net_set_buffer(buffer, (size_t)efi_wget_info.hdr_cont_len); ret = efi_net_set_buffer(buffer, (size_t)efi_wget_info.hdr_cont_len);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
goto out; goto out;
eth_set_dev(netobj->dev);
env_set("ethact", eth_get_name());
if (wget_request((ulong)*buffer, url, &efi_wget_info)) { if (wget_request((ulong)*buffer, url, &efi_wget_info)) {
efi_free_pool(*buffer); efi_free_pool(*buffer);
ret = EFI_DEVICE_ERROR; ret = EFI_DEVICE_ERROR;
@@ -1363,6 +1546,8 @@ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buf
ret = efi_net_set_buffer(buffer, 0); ret = efi_net_set_buffer(buffer, 0);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
goto out; goto out;
eth_set_dev(netobj->dev);
env_set("ethact", eth_get_name());
wget_request((ulong)*buffer, url, &efi_wget_info); wget_request((ulong)*buffer, url, &efi_wget_info);
*file_size = 0; *file_size = 0;
*status_code = efi_wget_info.status_code; *status_code = efi_wget_info.status_code;
@@ -1376,3 +1561,4 @@ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buf
out: out:
return ret; return ret;
} }
#endif

View File

@@ -11,6 +11,7 @@
#include <efi_variable.h> #include <efi_variable.h>
#include <log.h> #include <log.h>
#include <asm-generic/unaligned.h> #include <asm-generic/unaligned.h>
#include <net.h>
#define OBJ_LIST_INITIALIZED 0 #define OBJ_LIST_INITIALIZED 0
#define OBJ_LIST_NOT_INITIALIZED 1 #define OBJ_LIST_NOT_INITIALIZED 1
@@ -219,7 +220,7 @@ static efi_status_t efi_start_obj_list(void)
efi_status_t ret = EFI_SUCCESS; efi_status_t ret = EFI_SUCCESS;
if (IS_ENABLED(CONFIG_NETDEVICES)) if (IS_ENABLED(CONFIG_NETDEVICES))
ret = efi_net_do_start(); ret = efi_net_do_start(eth_get_dev());
return ret; return ret;
} }
@@ -336,7 +337,7 @@ efi_status_t efi_init_obj_list(void)
goto out; goto out;
} }
if (IS_ENABLED(CONFIG_NETDEVICES)) { if (IS_ENABLED(CONFIG_NETDEVICES)) {
ret = efi_net_register(); ret = efi_net_register(eth_get_dev());
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
goto out; goto out;
} }