* [U-Boot] [PATCH v2 0/7] efi_loader: PXE boot support
@ 2016-05-06 19:01 Alexander Graf
2016-05-06 19:01 ` [U-Boot] [PATCH v2 1/7] efi_loader: Add network access support Alexander Graf
` (6 more replies)
0 siblings, 7 replies; 30+ messages in thread
From: Alexander Graf @ 2016-05-06 19:01 UTC (permalink / raw)
To: u-boot
One of the most common boot cases with EFI on arm64 is to boot from the
network using PXE boot. While TianoCore implements that just fine, we
were lacking support for it in U-Boot so far.
But no longer! Here is a patch set, enabling PXE booting of EFI payloads.
With this patch set, I was successfully able to automatically boot our
normal (usually used with TianoCore based systems) environment to boot
and run grub2 and a kernel from there with U-Boot.
Changes from v1 -> v2:
- Only set client id to 0 on x86
- new patch: net: Fix client identifiers for ARM
- new patch: net: Move CONFIG_SPL_NET_VCI_STRING into Kconfig
- new patch: net: Optionally use pxe client arch from variable
- Error out for unknown arch
- Also set client arch variable
Alexander Graf (7):
efi_loader: Add network access support
bootp: Move vendor class identifier set to function
net: Move the VCI and client arch values to Kconfig
net: Fix client identifiers for ARM
net: Move CONFIG_SPL_NET_VCI_STRING into Kconfig
net: Optionally use pxe client arch from variable
distro: Add efi pxe boot code
cmd/bootefi.c | 7 +
configs/am335x_evm_defconfig | 1 +
configs/am335x_evm_nor_defconfig | 1 +
configs/am335x_evm_norboot_defconfig | 1 +
configs/am335x_evm_spiboot_defconfig | 1 +
configs/am335x_evm_usbspl_defconfig | 1 +
configs/am335x_sl50_defconfig | 1 +
configs/am437x_gp_evm_defconfig | 1 +
configs/am437x_sk_evm_defconfig | 1 +
configs/am43xx_evm_defconfig | 1 +
configs/am43xx_evm_ethboot_defconfig | 1 +
configs/am43xx_evm_qspiboot_defconfig | 1 +
configs/am43xx_evm_usbhost_boot_defconfig | 1 +
configs/birdland_bav335a_defconfig | 1 +
configs/birdland_bav335b_defconfig | 1 +
configs/ls2080a_emu_defconfig | 1 +
configs/ls2080a_simu_defconfig | 1 +
configs/pcm051_rev1_defconfig | 1 +
configs/pcm051_rev3_defconfig | 1 +
configs/thunderx_88xx_defconfig | 1 +
configs/vexpress_aemv8a_dram_defconfig | 1 +
configs/vexpress_aemv8a_juno_defconfig | 1 +
configs/vexpress_aemv8a_semi_defconfig | 1 +
configs/vexpress_ca15_tc2_defconfig | 1 +
configs/vexpress_ca5x2_defconfig | 1 +
configs/vexpress_ca9x4_defconfig | 1 +
include/config_distro_bootcmd.h | 47 ++++-
include/config_distro_defaults.h | 21 ---
include/configs/ls2080a_emu.h | 1 -
include/configs/ls2080a_simu.h | 1 -
include/configs/thunderx_88xx.h | 2 -
include/configs/vexpress_aemv8a.h | 2 -
include/configs/vexpress_ca15_tc2.h | 1 -
include/configs/vexpress_ca5x2.h | 1 -
include/configs/vexpress_ca9x4.h | 1 -
include/efi_api.h | 119 ++++++++++++
include/efi_loader.h | 7 +
include/net.h | 2 +-
lib/efi_loader/Makefile | 1 +
lib/efi_loader/efi_net.c | 291 ++++++++++++++++++++++++++++++
net/Kconfig | 16 ++
net/bootp.c | 59 +++---
net/net.c | 4 +-
net/tftp.c | 2 +
44 files changed, 554 insertions(+), 56 deletions(-)
create mode 100644 lib/efi_loader/efi_net.c
--
1.8.5.6
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 1/7] efi_loader: Add network access support
2016-05-06 19:01 [U-Boot] [PATCH v2 0/7] efi_loader: PXE boot support Alexander Graf
@ 2016-05-06 19:01 ` Alexander Graf
2016-05-10 21:25 ` [U-Boot] [PATCH v3 " Alexander Graf
2016-05-30 17:56 ` [U-Boot] [U-Boot, v2, " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 2/7] bootp: Move vendor class identifier set to function Alexander Graf
` (5 subsequent siblings)
6 siblings, 2 replies; 30+ messages in thread
From: Alexander Graf @ 2016-05-06 19:01 UTC (permalink / raw)
To: u-boot
We can now successfully boot EFI applications from disk, but users
may want to also run them from a PXE setup.
This patch implements rudimentary network support, allowing a payload
to send and receive network packets.
With this patch, I was able to successfully run grub2 with network
access inside of QEMU's -M xlnx-ep108.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
cmd/bootefi.c | 7 ++
include/efi_api.h | 119 +++++++++++++++++++
include/efi_loader.h | 7 ++
include/net.h | 2 +-
lib/efi_loader/Makefile | 1 +
lib/efi_loader/efi_net.c | 291 +++++++++++++++++++++++++++++++++++++++++++++++
net/bootp.c | 2 +
net/net.c | 4 +-
net/tftp.c | 2 +
9 files changed, 432 insertions(+), 3 deletions(-)
create mode 100644 lib/efi_loader/efi_net.c
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 7f552fc..d3a2331 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -197,6 +197,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
#ifdef CONFIG_LCD
efi_gop_register();
#endif
+#ifdef CONFIG_NET
+ void *nethandle = loaded_image_info.device_handle;
+ efi_net_register(&nethandle);
+
+ if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
+ loaded_image_info.device_handle = nethandle;
+#endif
/* Call our payload! */
#ifdef DEBUG_EFI
diff --git a/include/efi_api.h b/include/efi_api.h
index 51d7586..20035d7 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -412,4 +412,123 @@ struct efi_gop
struct efi_gop_mode *mode;
};
+#define EFI_SIMPLE_NETWORK_GUID \
+ EFI_GUID(0xa19832b9, 0xac25, 0x11d3, \
+ 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
+
+struct efi_mac_address {
+ char mac_addr[32];
+};
+
+struct efi_ip_address {
+ u8 ip_addr[16];
+};
+
+enum efi_simple_network_state {
+ EFI_NETWORK_STOPPED,
+ EFI_NETWORK_STARTED,
+ EFI_NETWORK_INITIALIZED,
+};
+
+struct efi_simple_network_mode {
+ enum efi_simple_network_state state;
+ u32 hwaddr_size;
+ u32 media_header_size;
+ u32 max_packet_size;
+ u32 nvram_size;
+ u32 nvram_access_size;
+ u32 receive_filter_mask;
+ u32 receive_filter_setting;
+ u32 max_mcast_filter_count;
+ u32 mcast_filter_count;
+ struct efi_mac_address mcast_filter[16];
+ struct efi_mac_address current_address;
+ struct efi_mac_address broadcast_address;
+ struct efi_mac_address permanent_address;
+ u8 if_type;
+ u8 mac_changeable;
+ u8 multitx_supported;
+ u8 media_present_supported;
+ u8 media_present;
+};
+
+#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01,
+#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02,
+#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04,
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08,
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10,
+
+struct efi_simple_network
+{
+ u64 revision;
+ efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
+ efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
+ efi_status_t (EFIAPI *initialize)(struct efi_simple_network *this,
+ ulong extra_rx, ulong extra_tx);
+ efi_status_t (EFIAPI *reset)(struct efi_simple_network *this,
+ int extended_verification);
+ efi_status_t (EFIAPI *shutdown)(struct efi_simple_network *this);
+ efi_status_t (EFIAPI *receive_filters)(struct efi_simple_network *this,
+ u32 enable, u32 disable, int reset_mcast_filter,
+ ulong mcast_filter_count,
+ struct efi_mac_address *mcast_filter);
+ efi_status_t (EFIAPI *station_address)(struct efi_simple_network *this,
+ int reset, struct efi_mac_address *new_mac);
+ efi_status_t (EFIAPI *statistics)(struct efi_simple_network *this,
+ int reset, ulong *stat_size, void *stat_table);
+ efi_status_t (EFIAPI *mcastiptomac)(struct efi_simple_network *this,
+ int ipv6, struct efi_ip_address *ip,
+ struct efi_mac_address *mac);
+ efi_status_t (EFIAPI *nvdata)(struct efi_simple_network *this,
+ int read_write, ulong offset, ulong buffer_size,
+ char *buffer);
+ efi_status_t (EFIAPI *get_status)(struct efi_simple_network *this,
+ u32 *int_status, void **txbuf);
+ efi_status_t (EFIAPI *transmit)(struct efi_simple_network *this,
+ ulong header_size, ulong buffer_size, void *buffer,
+ struct efi_mac_address *src_addr,
+ struct efi_mac_address *dest_addr, u16 *protocol);
+ efi_status_t (EFIAPI *receive)(struct efi_simple_network *this,
+ ulong *header_size, ulong *buffer_size, void *buffer,
+ struct efi_mac_address *src_addr,
+ struct efi_mac_address *dest_addr, u16 *protocol);
+ void (EFIAPI *waitforpacket)(void);
+ struct efi_simple_network_mode *mode;
+};
+
+#define EFI_PXE_GUID \
+ EFI_GUID(0x03c4e603, 0xac28, 0x11d3, \
+ 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
+
+struct efi_pxe_packet {
+ u8 packet[1472];
+};
+
+struct efi_pxe_mode
+{
+ u8 unused[52];
+ struct efi_pxe_packet dhcp_discover;
+ struct efi_pxe_packet dhcp_ack;
+ struct efi_pxe_packet proxy_offer;
+ struct efi_pxe_packet pxe_discover;
+ struct efi_pxe_packet pxe_reply;
+};
+
+struct efi_pxe {
+ u64 rev;
+ void (EFIAPI *start)(void);
+ void (EFIAPI *stop)(void);
+ void (EFIAPI *dhcp)(void);
+ void (EFIAPI *discover)(void);
+ void (EFIAPI *mftp)(void);
+ void (EFIAPI *udpwrite)(void);
+ void (EFIAPI *udpread)(void);
+ void (EFIAPI *setipfilter)(void);
+ void (EFIAPI *arp)(void);
+ void (EFIAPI *setparams)(void);
+ void (EFIAPI *setstationip)(void);
+ void (EFIAPI *setpackets)(void);
+ struct efi_pxe_mode *mode;
+};
+
#endif
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 88b8149..8005454 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -91,6 +91,12 @@ extern struct list_head efi_obj_list;
int efi_disk_register(void);
/* Called by bootefi to make GOP (graphical) interface available */
int efi_gop_register(void);
+/* Called by bootefi to make the network interface available */
+int efi_net_register(void **handle);
+
+/* Called by networking code to memorize the dhcp ack package */
+void efi_net_set_dhcp_ack(void *pkt, int len);
+
/*
* Stub implementation for a protocol opener that just returns the handle as
* interface
@@ -157,5 +163,6 @@ static inline void ascii2unicode(u16 *unicode, char *ascii)
static inline void efi_restore_gd(void) { }
static inline void efi_set_bootdev(const char *dev, const char *devnr,
const char *path) { }
+static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
#endif
diff --git a/include/net.h b/include/net.h
index 05800c4..5ee5929 100644
--- a/include/net.h
+++ b/include/net.h
@@ -269,7 +269,7 @@ int eth_getenv_enetaddr_by_index(const char *base_name, int index,
int eth_init(void); /* Initialize the device */
int eth_send(void *packet, int length); /* Send a packet */
-#ifdef CONFIG_API
+#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
int eth_receive(void *packet, int length); /* Receive a packet*/
extern void (*push_packet)(void *packet, int length);
#endif
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 83e31f6..2a3849e 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -11,3 +11,4 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
obj-y += efi_memory.o
obj-$(CONFIG_LCD) += efi_gop.o
obj-$(CONFIG_PARTITIONS) += efi_disk.o
+obj-$(CONFIG_NET) += efi_net.o
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
new file mode 100644
index 0000000..dd3b485
--- /dev/null
+++ b/lib/efi_loader/efi_net.c
@@ -0,0 +1,291 @@
+/*
+ * EFI application network access support
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <inttypes.h>
+#include <lcd.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
+static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
+static struct efi_pxe_packet *dhcp_ack;
+static bool new_rx_packet;
+static void *new_tx_packet;
+
+struct efi_net_obj {
+ /* Generic EFI object parent class data */
+ struct efi_object parent;
+ /* EFI Interface callback struct for network */
+ struct efi_simple_network net;
+ struct efi_simple_network_mode net_mode;
+ /* Device path to the network adapter */
+ struct efi_device_path_file_path dp[2];
+ /* PXE struct to transmit dhcp data */
+ struct efi_pxe pxe;
+ struct efi_pxe_mode pxe_mode;
+};
+
+static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
+{
+ EFI_ENTRY("%p", this);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
+{
+ EFI_ENTRY("%p", this);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
+ ulong extra_rx, ulong extra_tx)
+{
+ EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
+
+ eth_init();
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
+ int extended_verification)
+{
+ EFI_ENTRY("%p, %x", this, extended_verification);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
+{
+ EFI_ENTRY("%p", this);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_receive_filters(
+ struct efi_simple_network *this, u32 enable, u32 disable,
+ int reset_mcast_filter, ulong mcast_filter_count,
+ struct efi_mac_address *mcast_filter)
+{
+ EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
+ reset_mcast_filter, mcast_filter_count, mcast_filter);
+
+ /* XXX Do we care? */
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_station_address(
+ struct efi_simple_network *this, int reset,
+ struct efi_mac_address *new_mac)
+{
+ EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
+
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
+ int reset, ulong *stat_size,
+ void *stat_table)
+{
+ EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
+
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
+ int ipv6,
+ struct efi_ip_address *ip,
+ struct efi_mac_address *mac)
+{
+ EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
+
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
+ int read_write, ulong offset,
+ ulong buffer_size, char *buffer)
+{
+ EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
+ buffer);
+
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
+ u32 *int_status, void **txbuf)
+{
+ EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
+
+ /* We send packets synchronously, so nothing is outstanding */
+ if (int_status)
+ *int_status = 0;
+ if (txbuf)
+ *txbuf = new_tx_packet;
+
+ new_tx_packet = NULL;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
+ ulong header_size, ulong buffer_size, void *buffer,
+ struct efi_mac_address *src_addr,
+ struct efi_mac_address *dest_addr, u16 *protocol)
+{
+ EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
+ buffer_size, buffer, src_addr, dest_addr, protocol);
+
+ if (header_size) {
+ /* We would need to create the header if header_size != 0 */
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+ }
+
+ net_send_packet(buffer, buffer_size);
+ new_tx_packet = buffer;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static void efi_net_push(void *pkt, int len)
+{
+ new_rx_packet = true;
+}
+
+static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
+ ulong *header_size, ulong *buffer_size, void *buffer,
+ struct efi_mac_address *src_addr,
+ struct efi_mac_address *dest_addr, u16 *protocol)
+{
+ EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
+ buffer_size, buffer, src_addr, dest_addr, protocol);
+
+ push_packet = efi_net_push;
+ eth_rx();
+ push_packet = NULL;
+
+ if (!new_rx_packet)
+ return EFI_EXIT(EFI_NOT_READY);
+
+ if (*buffer_size < net_rx_packet_len) {
+ /* Packet doesn't fit, try again with bigger buf */
+ *buffer_size = net_rx_packet_len;
+ return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+ }
+
+ memcpy(buffer, net_rx_packet, net_rx_packet_len);
+ *buffer_size = net_rx_packet_len;
+ new_rx_packet = false;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
+ void **protocol_interface, void *agent_handle,
+ void *controller_handle, uint32_t attributes)
+{
+ struct efi_simple_network *net = handle;
+ struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
+
+ *protocol_interface = netobj->dp;
+
+ return EFI_SUCCESS;
+}
+
+static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol,
+ void **protocol_interface, void *agent_handle,
+ void *controller_handle, uint32_t attributes)
+{
+ struct efi_simple_network *net = handle;
+ struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
+
+ *protocol_interface = &netobj->pxe;
+
+ return EFI_SUCCESS;
+}
+
+void efi_net_set_dhcp_ack(void *pkt, int len)
+{
+ int maxsize = sizeof(*dhcp_ack);
+
+ if (!dhcp_ack)
+ dhcp_ack = malloc(maxsize);
+
+ memcpy(dhcp_ack, pkt, min(len, maxsize));
+}
+
+/* This gets called from do_bootefi_exec(). */
+int efi_net_register(void **handle)
+{
+ struct efi_net_obj *netobj;
+ struct efi_device_path_file_path dp_net = {
+ .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
+ .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
+ .dp.length = sizeof(dp_net),
+ .str = { 'N', 'e', 't' },
+ };
+ struct efi_device_path_file_path dp_end = {
+ .dp.type = DEVICE_PATH_TYPE_END,
+ .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
+ .dp.length = sizeof(dp_end),
+ };
+
+ if (!eth_get_dev()) {
+ /* No eth device active, don't expose any */
+ return 0;
+ }
+
+ /* We only expose the "active" eth device, so one is enough */
+ netobj = calloc(1, sizeof(*netobj));
+
+ /* Fill in object data */
+ netobj->parent.protocols[0].guid = &efi_net_guid;
+ netobj->parent.protocols[0].open = efi_return_handle;
+ netobj->parent.protocols[1].guid = &efi_guid_device_path;
+ netobj->parent.protocols[1].open = efi_net_open_dp;
+ netobj->parent.protocols[2].guid = &efi_pxe_guid;
+ netobj->parent.protocols[2].open = efi_net_open_pxe;
+ netobj->parent.handle = &netobj->net;
+ netobj->net.start = efi_net_start;
+ netobj->net.stop = efi_net_stop;
+ netobj->net.initialize = efi_net_initialize;
+ netobj->net.reset = efi_net_reset;
+ netobj->net.shutdown = efi_net_shutdown;
+ netobj->net.receive_filters = efi_net_receive_filters;
+ netobj->net.station_address = efi_net_station_address;
+ netobj->net.statistics = efi_net_statistics;
+ netobj->net.mcastiptomac = efi_net_mcastiptomac;
+ netobj->net.nvdata = efi_net_nvdata;
+ netobj->net.get_status = efi_net_get_status;
+ netobj->net.transmit = efi_net_transmit;
+ netobj->net.receive = efi_net_receive;
+ netobj->net.mode = &netobj->net_mode;
+ netobj->net_mode.state = EFI_NETWORK_STARTED;
+ netobj->dp[0] = dp_net;
+ netobj->dp[1] = dp_end;
+ memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
+ netobj->net_mode.max_packet_size = PKTSIZE;
+
+ netobj->pxe.mode = &netobj->pxe_mode;
+ if (dhcp_ack)
+ netobj->pxe_mode.dhcp_ack = *dhcp_ack;
+
+ /* Hook net up to the device list */
+ list_add_tail(&netobj->parent.link, &efi_obj_list);
+
+ if (handle)
+ *handle = &netobj->net;
+
+ return 0;
+}
diff --git a/net/bootp.c b/net/bootp.c
index d7852db..d91b307 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <command.h>
+#include <efi_loader.h>
#include <net.h>
#include <net/tftp.h>
#include "bootp.h"
@@ -1025,6 +1026,7 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
dhcp_packet_process_options(bp);
+ efi_net_set_dhcp_ack(pkt, len);
debug("TRANSITIONING TO REQUESTING STATE\n");
dhcp_state = REQUESTING;
diff --git a/net/net.c b/net/net.c
index fba111e..1e1d23d 100644
--- a/net/net.c
+++ b/net/net.c
@@ -146,7 +146,7 @@ static unsigned net_ip_id;
/* Ethernet bcast address */
const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
const u8 net_null_ethaddr[6];
-#ifdef CONFIG_API
+#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
void (*push_packet)(void *, int len) = 0;
#endif
/* Network loop state */
@@ -1054,7 +1054,7 @@ void net_process_received_packet(uchar *in_packet, int len)
if (len < ETHER_HDR_SIZE)
return;
-#ifdef CONFIG_API
+#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
if (push_packet) {
(*push_packet)(in_packet, len);
return;
diff --git a/net/tftp.c b/net/tftp.c
index f2889fe..ced45ec 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <command.h>
+#include <efi_loader.h>
#include <mapmem.h>
#include <net.h>
#include <net/tftp.h>
@@ -804,6 +805,7 @@ void tftp_start(enum proto_t protocol)
printf("Load address: 0x%lx\n", load_addr);
puts("Loading: *\b");
tftp_state = STATE_SEND_RRQ;
+ efi_set_bootdev("Net", "", tftp_filename);
}
time_start = get_timer(0);
--
1.8.5.6
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 2/7] bootp: Move vendor class identifier set to function
2016-05-06 19:01 [U-Boot] [PATCH v2 0/7] efi_loader: PXE boot support Alexander Graf
2016-05-06 19:01 ` [U-Boot] [PATCH v2 1/7] efi_loader: Add network access support Alexander Graf
@ 2016-05-06 19:01 ` Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-30 17:56 ` [U-Boot] [U-Boot, v2, " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 3/7] net: Move the VCI and client arch values to Kconfig Alexander Graf
` (4 subsequent siblings)
6 siblings, 2 replies; 30+ messages in thread
From: Alexander Graf @ 2016-05-06 19:01 UTC (permalink / raw)
To: u-boot
Both the dhcp as well as the bootp case add vendor class identifier
parameters into their packets. Let's move that into a separate function
to make overlaying easier.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
net/bootp.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/net/bootp.c b/net/bootp.c
index d91b307..d718e35 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -411,6 +411,17 @@ static void bootp_timeout_handler(void)
e += vci_strlen; \
} while (0)
+static u8 *add_vci(u8 *e)
+{
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING)
+ put_vci(e, CONFIG_SPL_NET_VCI_STRING);
+#elif defined(CONFIG_BOOTP_VCI_STRING)
+ put_vci(e, CONFIG_BOOTP_VCI_STRING);
+#endif
+
+ return e;
+}
+
/*
* Initialize BOOTP extension fields in the request.
*/
@@ -508,11 +519,7 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
}
#endif
-#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING)
- put_vci(e, CONFIG_SPL_NET_VCI_STRING);
-#elif defined(CONFIG_BOOTP_VCI_STRING)
- put_vci(e, CONFIG_BOOTP_VCI_STRING);
-#endif
+ e = add_vci(e);
#if defined(CONFIG_BOOTP_VENDOREX)
x = dhcp_vendorex_prep(e);
@@ -598,14 +605,7 @@ static int bootp_extended(u8 *e)
*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
#endif
-#if defined(CONFIG_BOOTP_VCI_STRING) || \
- (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING))
-#ifdef CONFIG_SPL_BUILD
- put_vci(e, CONFIG_SPL_NET_VCI_STRING);
-#else
- put_vci(e, CONFIG_BOOTP_VCI_STRING);
-#endif
-#endif
+ add_vci(e);
#if defined(CONFIG_BOOTP_SUBNETMASK)
*e++ = 1; /* Subnet mask request */
--
1.8.5.6
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 3/7] net: Move the VCI and client arch values to Kconfig
2016-05-06 19:01 [U-Boot] [PATCH v2 0/7] efi_loader: PXE boot support Alexander Graf
2016-05-06 19:01 ` [U-Boot] [PATCH v2 1/7] efi_loader: Add network access support Alexander Graf
2016-05-06 19:01 ` [U-Boot] [PATCH v2 2/7] bootp: Move vendor class identifier set to function Alexander Graf
@ 2016-05-06 19:01 ` Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-30 17:56 ` [U-Boot] [U-Boot, v2, " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 4/7] net: Fix client identifiers for ARM Alexander Graf
` (3 subsequent siblings)
6 siblings, 2 replies; 30+ messages in thread
From: Alexander Graf @ 2016-05-06 19:01 UTC (permalink / raw)
To: u-boot
We have a bunch of boards that define their vendor class identifier and
client archs in the board files or in the distro config. Move everything
to the generic Kconfig options.
We're missing the distinction between i386 and x86_64, as I couldn't find
any config variable that would tell us the difference. Is that really important
to people? I guess not, so I left it out.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
v1 -> v2:
- Only set client id to 0 on x86
---
configs/ls2080a_emu_defconfig | 1 +
configs/ls2080a_simu_defconfig | 1 +
configs/thunderx_88xx_defconfig | 1 +
configs/vexpress_aemv8a_dram_defconfig | 1 +
configs/vexpress_aemv8a_juno_defconfig | 1 +
configs/vexpress_aemv8a_semi_defconfig | 1 +
configs/vexpress_ca15_tc2_defconfig | 1 +
configs/vexpress_ca5x2_defconfig | 1 +
configs/vexpress_ca9x4_defconfig | 1 +
include/config_distro_defaults.h | 21 ---------------------
include/configs/ls2080a_emu.h | 1 -
include/configs/ls2080a_simu.h | 1 -
include/configs/thunderx_88xx.h | 2 --
include/configs/vexpress_aemv8a.h | 2 --
include/configs/vexpress_ca15_tc2.h | 1 -
include/configs/vexpress_ca5x2.h | 1 -
include/configs/vexpress_ca9x4.h | 1 -
net/Kconfig | 12 ++++++++++++
18 files changed, 21 insertions(+), 30 deletions(-)
diff --git a/configs/ls2080a_emu_defconfig b/configs/ls2080a_emu_defconfig
index f9b4eac..30a6381 100644
--- a/configs/ls2080a_emu_defconfig
+++ b/configs/ls2080a_emu_defconfig
@@ -25,3 +25,4 @@ CONFIG_CMD_CACHE=y
# CONFIG_CMD_MISC is not set
CONFIG_SYS_NS16550=y
CONFIG_OF_LIBFDT=y
+CONFIG_BOOTP_VCI_STRING="U-Boot.LS2080A-EMU"
diff --git a/configs/ls2080a_simu_defconfig b/configs/ls2080a_simu_defconfig
index 728fa25..a095b8a 100644
--- a/configs/ls2080a_simu_defconfig
+++ b/configs/ls2080a_simu_defconfig
@@ -28,3 +28,4 @@ CONFIG_CMD_FAT=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_SYS_NS16550=y
CONFIG_OF_LIBFDT=y
+CONFIG_BOOTP_VCI_STRING="U-Boot.LS2080A-SIMU"
diff --git a/configs/thunderx_88xx_defconfig b/configs/thunderx_88xx_defconfig
index b7078e0..cb33f60 100644
--- a/configs/thunderx_88xx_defconfig
+++ b/configs/thunderx_88xx_defconfig
@@ -22,3 +22,4 @@ CONFIG_DEBUG_UART_BASE=0x87e024000000
CONFIG_DEBUG_UART_CLOCK=24000000
CONFIG_DEBUG_UART_SKIP_INIT=y
CONFIG_REGEX=y
+CONFIG_BOOTP_VCI_STRING="Diagnostics"
diff --git a/configs/vexpress_aemv8a_dram_defconfig b/configs/vexpress_aemv8a_dram_defconfig
index 989f068..c0708b2 100644
--- a/configs/vexpress_aemv8a_dram_defconfig
+++ b/configs/vexpress_aemv8a_dram_defconfig
@@ -24,3 +24,4 @@ CONFIG_CMD_CACHE=y
CONFIG_CMD_FAT=y
CONFIG_DM=y
CONFIG_OF_LIBFDT=y
+CONFIG_BOOTP_VCI_STRING="U-Boot.armv8.vexpress_aemv8a"
diff --git a/configs/vexpress_aemv8a_juno_defconfig b/configs/vexpress_aemv8a_juno_defconfig
index c70851f..5af9f58 100644
--- a/configs/vexpress_aemv8a_juno_defconfig
+++ b/configs/vexpress_aemv8a_juno_defconfig
@@ -24,3 +24,4 @@ CONFIG_CMD_CACHE=y
CONFIG_CMD_FAT=y
CONFIG_DM=y
CONFIG_OF_LIBFDT=y
+CONFIG_BOOTP_VCI_STRING="U-Boot.armv8.vexpress_aemv8a"
diff --git a/configs/vexpress_aemv8a_semi_defconfig b/configs/vexpress_aemv8a_semi_defconfig
index b0a2f67..379dff2 100644
--- a/configs/vexpress_aemv8a_semi_defconfig
+++ b/configs/vexpress_aemv8a_semi_defconfig
@@ -24,3 +24,4 @@ CONFIG_CMD_CACHE=y
CONFIG_CMD_FAT=y
CONFIG_DM=y
CONFIG_OF_LIBFDT=y
+CONFIG_BOOTP_VCI_STRING="U-Boot.armv8.vexpress_aemv8a"
diff --git a/configs/vexpress_ca15_tc2_defconfig b/configs/vexpress_ca15_tc2_defconfig
index 2f141dd..c39faaa 100644
--- a/configs/vexpress_ca15_tc2_defconfig
+++ b/configs/vexpress_ca15_tc2_defconfig
@@ -24,3 +24,4 @@ CONFIG_CMD_EXT4=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_OF_LIBFDT=y
+CONFIG_BOOTP_VCI_STRING="U-Boot.armv7.vexpress_ca15x2_tc2"
diff --git a/configs/vexpress_ca5x2_defconfig b/configs/vexpress_ca5x2_defconfig
index c495ee5..e71d45e 100644
--- a/configs/vexpress_ca5x2_defconfig
+++ b/configs/vexpress_ca5x2_defconfig
@@ -24,3 +24,4 @@ CONFIG_CMD_EXT4=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_OF_LIBFDT=y
+CONFIG_BOOTP_VCI_STRING="U-Boot.armv7.vexpress_ca5x2"
diff --git a/configs/vexpress_ca9x4_defconfig b/configs/vexpress_ca9x4_defconfig
index fcd6e26..20100a3 100644
--- a/configs/vexpress_ca9x4_defconfig
+++ b/configs/vexpress_ca9x4_defconfig
@@ -24,3 +24,4 @@ CONFIG_CMD_EXT4=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_OF_LIBFDT=y
+CONFIG_BOOTP_VCI_STRING="U-Boot.armv7.vexpress_ca9x4"
diff --git a/include/config_distro_defaults.h b/include/config_distro_defaults.h
index 766a212..dfc2cbc 100644
--- a/include/config_distro_defaults.h
+++ b/include/config_distro_defaults.h
@@ -20,27 +20,6 @@
#define CONFIG_BOOTP_PXE
#define CONFIG_BOOTP_SUBNETMASK
-#if defined(__arm__) || defined(__aarch64__)
-#define CONFIG_BOOTP_PXE_CLIENTARCH 0x100
-#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__)
-#if !defined(CONFIG_BOOTP_VCI_STRING)
-#define CONFIG_BOOTP_VCI_STRING "U-Boot.armv7"
-#endif
-#elif defined(__aarch64__)
-#if !defined(CONFIG_BOOTP_VCI_STRING)
-#define CONFIG_BOOTP_VCI_STRING "U-Boot.armv8"
-#endif
-#else
-#if !defined(CONFIG_BOOTP_VCI_STRING)
-#define CONFIG_BOOTP_VCI_STRING "U-Boot.arm"
-#endif
-#endif
-#elif defined(__i386__)
-#define CONFIG_BOOTP_PXE_CLIENTARCH 0x0
-#elif defined(__x86_64__)
-#define CONFIG_BOOTP_PXE_CLIENTARCH 0x9
-#endif
-
#ifdef CONFIG_ARM64
#define CONFIG_CMD_BOOTI
#endif
diff --git a/include/configs/ls2080a_emu.h b/include/configs/ls2080a_emu.h
index f4ace85..16e37bf 100644
--- a/include/configs/ls2080a_emu.h
+++ b/include/configs/ls2080a_emu.h
@@ -10,7 +10,6 @@
#include "ls2080a_common.h"
#define CONFIG_IDENT_STRING " LS2080A-EMU"
-#define CONFIG_BOOTP_VCI_STRING "U-Boot.LS2080A-EMU"
#define CONFIG_SYS_CLK_FREQ 100000000
#define CONFIG_DDR_CLK_FREQ 133333333
diff --git a/include/configs/ls2080a_simu.h b/include/configs/ls2080a_simu.h
index bc0d678..7563aaf 100644
--- a/include/configs/ls2080a_simu.h
+++ b/include/configs/ls2080a_simu.h
@@ -10,7 +10,6 @@
#include "ls2080a_common.h"
#define CONFIG_IDENT_STRING " LS2080A-SIMU"
-#define CONFIG_BOOTP_VCI_STRING "U-Boot.LS2080A-SIMU"
#define CONFIG_SYS_CLK_FREQ 100000000
#define CONFIG_DDR_CLK_FREQ 133333333
diff --git a/include/configs/thunderx_88xx.h b/include/configs/thunderx_88xx.h
index 7c35d8c..e43a7fd 100644
--- a/include/configs/thunderx_88xx.h
+++ b/include/configs/thunderx_88xx.h
@@ -17,7 +17,6 @@
#define CONFIG_IDENT_STRING \
" for Cavium Thunder CN88XX ARM v8 Multi-Core"
-#define CONFIG_BOOTP_VCI_STRING "Diagnostics"
#define MEM_BASE 0x00500000
@@ -62,7 +61,6 @@
#define CONFIG_BOOTP_GATEWAY
#define CONFIG_BOOTP_HOSTNAME
#define CONFIG_BOOTP_PXE
-#define CONFIG_BOOTP_PXE_CLIENTARCH 0x100
/* Miscellaneous configurable options */
#define CONFIG_SYS_LOAD_ADDR (MEM_BASE)
diff --git a/include/configs/vexpress_aemv8a.h b/include/configs/vexpress_aemv8a.h
index 1b5fc2e..6a37582 100644
--- a/include/configs/vexpress_aemv8a.h
+++ b/include/configs/vexpress_aemv8a.h
@@ -23,7 +23,6 @@
#define CONFIG_SYS_CACHELINE_SIZE 64
#define CONFIG_IDENT_STRING " vexpress_aemv8a"
-#define CONFIG_BOOTP_VCI_STRING "U-Boot.armv8.vexpress_aemv8a"
/* Link Definitions */
#if defined(CONFIG_TARGET_VEXPRESS64_BASE_FVP) || \
@@ -146,7 +145,6 @@
#define CONFIG_BOOTP_GATEWAY
#define CONFIG_BOOTP_HOSTNAME
#define CONFIG_BOOTP_PXE
-#define CONFIG_BOOTP_PXE_CLIENTARCH 0x100
/* Miscellaneous configurable options */
#define CONFIG_SYS_LOAD_ADDR (V2M_BASE + 0x10000000)
diff --git a/include/configs/vexpress_ca15_tc2.h b/include/configs/vexpress_ca15_tc2.h
index 883e58e..b509a9c 100644
--- a/include/configs/vexpress_ca15_tc2.h
+++ b/include/configs/vexpress_ca15_tc2.h
@@ -12,7 +12,6 @@
#define __VEXPRESS_CA15X2_TC2_h
#define CONFIG_VEXPRESS_EXTENDED_MEMORY_MAP
-#define CONFIG_BOOTP_VCI_STRING "U-Boot.armv7.vexpress_ca15x2_tc2"
#include "vexpress_common.h"
#define CONFIG_SYSFLAGS_ADDR 0x1c010030
diff --git a/include/configs/vexpress_ca5x2.h b/include/configs/vexpress_ca5x2.h
index 4385027..20b92dc 100644
--- a/include/configs/vexpress_ca5x2.h
+++ b/include/configs/vexpress_ca5x2.h
@@ -12,7 +12,6 @@
#define __VEXPRESS_CA5X2_h
#define CONFIG_VEXPRESS_EXTENDED_MEMORY_MAP
-#define CONFIG_BOOTP_VCI_STRING "U-Boot.armv7.vexpress_ca5x2"
#include "vexpress_common.h"
#endif /* __VEXPRESS_CA5X2_h */
diff --git a/include/configs/vexpress_ca9x4.h b/include/configs/vexpress_ca9x4.h
index 99be50a..993398c 100644
--- a/include/configs/vexpress_ca9x4.h
+++ b/include/configs/vexpress_ca9x4.h
@@ -12,7 +12,6 @@
#define __VEXPRESS_CA9X4_H
#define CONFIG_VEXPRESS_ORIGINAL_MEMORY_MAP
-#define CONFIG_BOOTP_VCI_STRING "U-Boot.armv7.vexpress_ca9x4"
#include "vexpress_common.h"
#endif /* VEXPRESS_CA9X4_H */
diff --git a/net/Kconfig b/net/Kconfig
index a44a783..64fd0f9 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -32,4 +32,16 @@ config NET_TFTP_VARS
If unset, timeout and maximum are hard-defined as 1 second
and 10 timouts per TFTP transfer.
+config BOOTP_PXE_CLIENTARCH
+ hex
+ default 0x100 if ARM
+ default 0 if X86
+
+config BOOTP_VCI_STRING
+ string
+ default "U-Boot.armv7" if CPU_V7 || CPU_V7M
+ default "U-Boot.armv8" if ARM64
+ default "U-Boot.arm" if ARM
+ default "U-Boot"
+
endif # if NET
--
1.8.5.6
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 4/7] net: Fix client identifiers for ARM
2016-05-06 19:01 [U-Boot] [PATCH v2 0/7] efi_loader: PXE boot support Alexander Graf
` (2 preceding siblings ...)
2016-05-06 19:01 ` [U-Boot] [PATCH v2 3/7] net: Move the VCI and client arch values to Kconfig Alexander Graf
@ 2016-05-06 19:01 ` Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-30 17:56 ` [U-Boot] [U-Boot,v2,4/7] " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 5/7] net: Move CONFIG_SPL_NET_VCI_STRING into Kconfig Alexander Graf
` (2 subsequent siblings)
6 siblings, 2 replies; 30+ messages in thread
From: Alexander Graf @ 2016-05-06 19:01 UTC (permalink / raw)
To: u-boot
There are client identifiers specifically reserved for ARM U-Boot
according to http://www.ietf.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml#processor-architecture.
So let's actually make use of them rather than the bogus 0x100 that
we emitted so far.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
net/Kconfig | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/Kconfig b/net/Kconfig
index 64fd0f9..414c549 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -34,7 +34,8 @@ config NET_TFTP_VARS
config BOOTP_PXE_CLIENTARCH
hex
- default 0x100 if ARM
+ default 0x16 if ARM64
+ default 0x15 if ARM
default 0 if X86
config BOOTP_VCI_STRING
--
1.8.5.6
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 5/7] net: Move CONFIG_SPL_NET_VCI_STRING into Kconfig
2016-05-06 19:01 [U-Boot] [PATCH v2 0/7] efi_loader: PXE boot support Alexander Graf
` (3 preceding siblings ...)
2016-05-06 19:01 ` [U-Boot] [PATCH v2 4/7] net: Fix client identifiers for ARM Alexander Graf
@ 2016-05-06 19:01 ` Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-30 17:57 ` [U-Boot] [U-Boot, v2, " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 6/7] net: Optionally use pxe client arch from variable Alexander Graf
2016-05-06 19:01 ` [U-Boot] [PATCH v2 7/7] distro: Add efi pxe boot code Alexander Graf
6 siblings, 2 replies; 30+ messages in thread
From: Alexander Graf @ 2016-05-06 19:01 UTC (permalink / raw)
To: u-boot
This patch also adds the SPL time VCI string into Kconfig.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
configs/am335x_evm_defconfig | 1 +
configs/am335x_evm_nor_defconfig | 1 +
configs/am335x_evm_norboot_defconfig | 1 +
configs/am335x_evm_spiboot_defconfig | 1 +
configs/am335x_evm_usbspl_defconfig | 1 +
configs/am335x_sl50_defconfig | 1 +
configs/am437x_gp_evm_defconfig | 1 +
configs/am437x_sk_evm_defconfig | 1 +
configs/am43xx_evm_defconfig | 1 +
configs/am43xx_evm_ethboot_defconfig | 1 +
configs/am43xx_evm_qspiboot_defconfig | 1 +
configs/am43xx_evm_usbhost_boot_defconfig | 1 +
configs/birdland_bav335a_defconfig | 1 +
configs/birdland_bav335b_defconfig | 1 +
configs/pcm051_rev1_defconfig | 1 +
configs/pcm051_rev3_defconfig | 1 +
net/Kconfig | 3 +++
17 files changed, 19 insertions(+)
diff --git a/configs/am335x_evm_defconfig b/configs/am335x_evm_defconfig
index 62f26b5..2430381 100644
--- a/configs/am335x_evm_defconfig
+++ b/configs/am335x_evm_defconfig
@@ -42,3 +42,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0451
CONFIG_G_DNL_PRODUCT_NUM=0xd022
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="AM335x U-Boot SPL"
diff --git a/configs/am335x_evm_nor_defconfig b/configs/am335x_evm_nor_defconfig
index f230671..76a004e 100644
--- a/configs/am335x_evm_nor_defconfig
+++ b/configs/am335x_evm_nor_defconfig
@@ -38,3 +38,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0451
CONFIG_G_DNL_PRODUCT_NUM=0xd022
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="AM335x U-Boot SPL"
diff --git a/configs/am335x_evm_norboot_defconfig b/configs/am335x_evm_norboot_defconfig
index 3fbc07b..99fc555 100644
--- a/configs/am335x_evm_norboot_defconfig
+++ b/configs/am335x_evm_norboot_defconfig
@@ -35,3 +35,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0451
CONFIG_G_DNL_PRODUCT_NUM=0xd022
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="AM335x U-Boot SPL"
diff --git a/configs/am335x_evm_spiboot_defconfig b/configs/am335x_evm_spiboot_defconfig
index 65d88d8..d5aa3a2 100644
--- a/configs/am335x_evm_spiboot_defconfig
+++ b/configs/am335x_evm_spiboot_defconfig
@@ -38,3 +38,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0451
CONFIG_G_DNL_PRODUCT_NUM=0xd022
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="AM335x U-Boot SPL"
diff --git a/configs/am335x_evm_usbspl_defconfig b/configs/am335x_evm_usbspl_defconfig
index eee5e9b..cba5e84 100644
--- a/configs/am335x_evm_usbspl_defconfig
+++ b/configs/am335x_evm_usbspl_defconfig
@@ -38,3 +38,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0451
CONFIG_G_DNL_PRODUCT_NUM=0xd022
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="AM335x U-Boot SPL"
diff --git a/configs/am335x_sl50_defconfig b/configs/am335x_sl50_defconfig
index c227ef4..3cd40e9 100644
--- a/configs/am335x_sl50_defconfig
+++ b/configs/am335x_sl50_defconfig
@@ -25,3 +25,4 @@ CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_SYS_NS16550=y
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="AM335x U-Boot SPL"
diff --git a/configs/am437x_gp_evm_defconfig b/configs/am437x_gp_evm_defconfig
index 03b02ac..968f2f3 100644
--- a/configs/am437x_gp_evm_defconfig
+++ b/configs/am437x_gp_evm_defconfig
@@ -47,3 +47,4 @@ CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0403
CONFIG_G_DNL_PRODUCT_NUM=0xbd00
+CONFIG_SPL_NET_VCI_STRING="AM43xx U-Boot SPL"
diff --git a/configs/am437x_sk_evm_defconfig b/configs/am437x_sk_evm_defconfig
index 48ec91f..1d50c0b 100644
--- a/configs/am437x_sk_evm_defconfig
+++ b/configs/am437x_sk_evm_defconfig
@@ -51,3 +51,4 @@ CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0403
CONFIG_G_DNL_PRODUCT_NUM=0xbd00
+CONFIG_SPL_NET_VCI_STRING="AM43xx U-Boot SPL"
diff --git a/configs/am43xx_evm_defconfig b/configs/am43xx_evm_defconfig
index a6ae011..4911b61 100644
--- a/configs/am43xx_evm_defconfig
+++ b/configs/am43xx_evm_defconfig
@@ -39,3 +39,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0403
CONFIG_G_DNL_PRODUCT_NUM=0xbd00
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="AM43xx U-Boot SPL"
diff --git a/configs/am43xx_evm_ethboot_defconfig b/configs/am43xx_evm_ethboot_defconfig
index 662556a..ee4716d 100644
--- a/configs/am43xx_evm_ethboot_defconfig
+++ b/configs/am43xx_evm_ethboot_defconfig
@@ -38,3 +38,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0403
CONFIG_G_DNL_PRODUCT_NUM=0xbd00
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="AM43xx U-Boot SPL"
diff --git a/configs/am43xx_evm_qspiboot_defconfig b/configs/am43xx_evm_qspiboot_defconfig
index 00fa6be..4d18231 100644
--- a/configs/am43xx_evm_qspiboot_defconfig
+++ b/configs/am43xx_evm_qspiboot_defconfig
@@ -37,3 +37,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0403
CONFIG_G_DNL_PRODUCT_NUM=0xbd00
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="AM43xx U-Boot SPL"
diff --git a/configs/am43xx_evm_usbhost_boot_defconfig b/configs/am43xx_evm_usbhost_boot_defconfig
index e3d6b57..c336419 100644
--- a/configs/am43xx_evm_usbhost_boot_defconfig
+++ b/configs/am43xx_evm_usbhost_boot_defconfig
@@ -38,3 +38,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0403
CONFIG_G_DNL_PRODUCT_NUM=0xbd00
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="AM43xx U-Boot SPL"
diff --git a/configs/birdland_bav335a_defconfig b/configs/birdland_bav335a_defconfig
index 44ed671..bb5db5c 100644
--- a/configs/birdland_bav335a_defconfig
+++ b/configs/birdland_bav335a_defconfig
@@ -38,3 +38,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0451
CONFIG_G_DNL_PRODUCT_NUM=0xd022
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="BAV335x U-Boot SPL"
diff --git a/configs/birdland_bav335b_defconfig b/configs/birdland_bav335b_defconfig
index 861bdcf..39cc222 100644
--- a/configs/birdland_bav335b_defconfig
+++ b/configs/birdland_bav335b_defconfig
@@ -38,3 +38,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0451
CONFIG_G_DNL_PRODUCT_NUM=0xd022
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="BAV335x U-Boot SPL"
diff --git a/configs/pcm051_rev1_defconfig b/configs/pcm051_rev1_defconfig
index 7f29119..27f681f 100644
--- a/configs/pcm051_rev1_defconfig
+++ b/configs/pcm051_rev1_defconfig
@@ -30,3 +30,4 @@ CONFIG_USB_MUSB_HOST=y
CONFIG_USB_MUSB_GADGET=y
CONFIG_USB_GADGET=y
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="pcm051 U-Boot SPL"
diff --git a/configs/pcm051_rev3_defconfig b/configs/pcm051_rev3_defconfig
index eff099c..b277b3a 100644
--- a/configs/pcm051_rev3_defconfig
+++ b/configs/pcm051_rev3_defconfig
@@ -30,3 +30,4 @@ CONFIG_USB_MUSB_HOST=y
CONFIG_USB_MUSB_GADGET=y
CONFIG_USB_GADGET=y
CONFIG_OF_LIBFDT=y
+CONFIG_SPL_NET_VCI_STRING="pcm051 U-Boot SPL"
diff --git a/net/Kconfig b/net/Kconfig
index 414c549..c393269 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -45,4 +45,7 @@ config BOOTP_VCI_STRING
default "U-Boot.arm" if ARM
default "U-Boot"
+config SPL_NET_VCI_STRING
+ string
+
endif # if NET
--
1.8.5.6
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 6/7] net: Optionally use pxe client arch from variable
2016-05-06 19:01 [U-Boot] [PATCH v2 0/7] efi_loader: PXE boot support Alexander Graf
` (4 preceding siblings ...)
2016-05-06 19:01 ` [U-Boot] [PATCH v2 5/7] net: Move CONFIG_SPL_NET_VCI_STRING into Kconfig Alexander Graf
@ 2016-05-06 19:01 ` Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-12 13:51 ` [U-Boot] [PATCH v4 " Alexander Graf
2016-05-06 19:01 ` [U-Boot] [PATCH v2 7/7] distro: Add efi pxe boot code Alexander Graf
6 siblings, 2 replies; 30+ messages in thread
From: Alexander Graf @ 2016-05-06 19:01 UTC (permalink / raw)
To: u-boot
The client architecture that we pass to a dhcp server depends on the target
payload that we want to execute. An EFI binary has a different client arch
than a legacy binary or a u-boot binary.
So let's parameterize the pxe client arch field to allow an override via
the distro script, so that our efi boot path can tell the dhcp server that
it's actually an efi firmware.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
net/bootp.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/net/bootp.c b/net/bootp.c
index d718e35..1f2d0aa 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -431,10 +431,8 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
{
u8 *start = e;
u8 *cnt;
-#if defined(CONFIG_BOOTP_PXE)
char *uuid;
- u16 clientarch;
-#endif
+ int clientarch = -1;
#if defined(CONFIG_BOOTP_VENDOREX)
u8 *x;
@@ -490,12 +488,19 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
}
#endif
-#if defined(CONFIG_BOOTP_PXE)
+#ifdef CONFIG_BOOTP_PXE_CLIENTARCH
clientarch = CONFIG_BOOTP_PXE_CLIENTARCH;
- *e++ = 93; /* Client System Architecture */
- *e++ = 2;
- *e++ = (clientarch >> 8) & 0xff;
- *e++ = clientarch & 0xff;
+#endif
+
+ if (getenv("bootp_arch"))
+ clientarch = getenv_ulong("bootp_arch", 16, clientarch);
+
+ if (clientarch > 0) {
+ *e++ = 93; /* Client System Architecture */
+ *e++ = 2;
+ *e++ = (clientarch >> 8) & 0xff;
+ *e++ = clientarch & 0xff;
+ }
*e++ = 94; /* Client Network Interface Identifier */
*e++ = 3;
@@ -517,7 +522,6 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
printf("Invalid pxeuuid: %s\n", uuid);
}
}
-#endif
e = add_vci(e);
--
1.8.5.6
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 7/7] distro: Add efi pxe boot code
2016-05-06 19:01 [U-Boot] [PATCH v2 0/7] efi_loader: PXE boot support Alexander Graf
` (5 preceding siblings ...)
2016-05-06 19:01 ` [U-Boot] [PATCH v2 6/7] net: Optionally use pxe client arch from variable Alexander Graf
@ 2016-05-06 19:01 ` Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-30 17:57 ` [U-Boot] [U-Boot,v2,7/7] " Tom Rini
6 siblings, 2 replies; 30+ messages in thread
From: Alexander Graf @ 2016-05-06 19:01 UTC (permalink / raw)
To: u-boot
Now that we can expose network functionality to EFI applications,
the logical next step is to load them via pxe to execute them as
well.
This patch adds the necessary bits to the distro script to automatically
load and execute EFI payloads. It identifies the dhcp client as a uEFI
capable PXE client, hoping the server returns a tftp path to a workable
EFI binary that we can then execute.
To enable boards that don't come with a working device tree preloaded,
this patch also adds support to load a device tree from the /dtb directory
on the remote tftp server.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
v1 -> v2:
- Error out for unknown arch
- Also set client arch variable
---
include/config_distro_bootcmd.h | 47 ++++++++++++++++++++++++++++++++++++++++-
net/bootp.c | 13 ++++++++++--
2 files changed, 57 insertions(+), 3 deletions(-)
diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index 7f67344..e06c9eb 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -230,13 +230,58 @@
#endif
#if defined(CONFIG_CMD_DHCP)
+#if defined(CONFIG_EFI_LOADER)
+#if defined(CONFIG_ARM64)
+#define BOOTENV_EFI_PXE_ARCH "0xb"
+#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00011:UNDI:003000"
+#elif defined(CONFIG_ARM)
+#define BOOTENV_EFI_PXE_ARCH "0xa"
+#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00010:UNDI:003000"
+#elif defined(CONFIG_X86)
+/* Always assume we're running 64bit */
+#define BOOTENV_EFI_PXE_ARCH "0x7"
+#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00007:UNDI:003000"
+#else
+#error Please specify an EFI client identifier
+#endif
+
+/*
+ * Ask the dhcp server for an EFI binary. If we get one, check for a
+ * device tree in the same folder. Then boot everything. If the file was
+ * not an EFI binary, we just return from the bootefi command and continue.
+ */
+#define BOOTENV_EFI_RUN_DHCP \
+ "setenv efi_fdtfile ${fdtfile}; " \
+ BOOTENV_EFI_SET_FDTFILE_FALLBACK \
+ "setenv efi_old_vci ${bootp_vci};" \
+ "setenv efi_old_arch ${bootp_arch};" \
+ "setenv bootp_vci " BOOTENV_EFI_PXE_VCI ";" \
+ "setenv bootp_arch " BOOTENV_EFI_PXE_ARCH ";" \
+ "if dhcp ${kernel_addr_r}; then " \
+ "tftpboot ${fdt_addr_r} dtb/${efi_fdtfile};" \
+ "if fdt addr ${fdt_addr_r}; then " \
+ "bootefi ${kernel_addr_r} ${fdt_addr_r}; " \
+ "else " \
+ "bootefi ${kernel_addr_r} ${fdtcontroladdr};" \
+ "fi;" \
+ "fi;" \
+ "setenv bootp_vci ${efi_old_vci};" \
+ "setenv bootp_arch ${efi_old_arch};" \
+ "setenv efi_fdtfile;" \
+ "setenv efi_old_arch;" \
+ "setenv efi_old_vci;"
+#else
+#define BOOTENV_EFI_RUN_DHCP
+#endif
#define BOOTENV_DEV_DHCP(devtypeu, devtypel, instance) \
"bootcmd_dhcp=" \
BOOTENV_RUN_NET_USB_START \
BOOTENV_RUN_NET_PCI_ENUM \
"if dhcp ${scriptaddr} ${boot_script_dhcp}; then " \
"source ${scriptaddr}; " \
- "fi\0"
+ "fi;" \
+ BOOTENV_EFI_RUN_DHCP \
+ "\0"
#define BOOTENV_DEV_NAME_DHCP(devtypeu, devtypel, instance) \
"dhcp "
#else
diff --git a/net/bootp.c b/net/bootp.c
index 1f2d0aa..e36793c 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -413,12 +413,21 @@ static void bootp_timeout_handler(void)
static u8 *add_vci(u8 *e)
{
+ char *vci = NULL;
+ char *env_vci = getenv("bootp_vci");
+
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING)
- put_vci(e, CONFIG_SPL_NET_VCI_STRING);
+ vci = CONFIG_SPL_NET_VCI_STRING;
#elif defined(CONFIG_BOOTP_VCI_STRING)
- put_vci(e, CONFIG_BOOTP_VCI_STRING);
+ vci = CONFIG_BOOTP_VCI_STRING;
#endif
+ if (env_vci)
+ vci = env_vci;
+
+ if (vci)
+ put_vci(e, vci);
+
return e;
}
--
1.8.5.6
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 2/7] bootp: Move vendor class identifier set to function
2016-05-06 19:01 ` [U-Boot] [PATCH v2 2/7] bootp: Move vendor class identifier set to function Alexander Graf
@ 2016-05-06 19:28 ` Tom Rini
2016-05-30 17:56 ` [U-Boot] [U-Boot, v2, " Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-06 19:28 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:02PM +0200, Alexander Graf wrote:
> Both the dhcp as well as the bootp case add vendor class identifier
> parameters into their packets. Let's move that into a separate function
> to make overlaying easier.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Tom Rini <trini@konsulko.com>
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160506/b1d4c493/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 3/7] net: Move the VCI and client arch values to Kconfig
2016-05-06 19:01 ` [U-Boot] [PATCH v2 3/7] net: Move the VCI and client arch values to Kconfig Alexander Graf
@ 2016-05-06 19:28 ` Tom Rini
2016-05-30 17:56 ` [U-Boot] [U-Boot, v2, " Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-06 19:28 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:03PM +0200, Alexander Graf wrote:
> We have a bunch of boards that define their vendor class identifier and
> client archs in the board files or in the distro config. Move everything
> to the generic Kconfig options.
>
> We're missing the distinction between i386 and x86_64, as I couldn't find
> any config variable that would tell us the difference. Is that really important
> to people? I guess not, so I left it out.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
>
Reviewed-by: Tom Rini <trini@konsulko.com>
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160506/a9b93305/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 4/7] net: Fix client identifiers for ARM
2016-05-06 19:01 ` [U-Boot] [PATCH v2 4/7] net: Fix client identifiers for ARM Alexander Graf
@ 2016-05-06 19:28 ` Tom Rini
2016-05-30 17:56 ` [U-Boot] [U-Boot,v2,4/7] " Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-06 19:28 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:04PM +0200, Alexander Graf wrote:
> There are client identifiers specifically reserved for ARM U-Boot
> according to http://www.ietf.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml#processor-architecture.
>
> So let's actually make use of them rather than the bogus 0x100 that
> we emitted so far.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Tom Rini <trini@konsulko.com>
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160506/efe6129f/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 5/7] net: Move CONFIG_SPL_NET_VCI_STRING into Kconfig
2016-05-06 19:01 ` [U-Boot] [PATCH v2 5/7] net: Move CONFIG_SPL_NET_VCI_STRING into Kconfig Alexander Graf
@ 2016-05-06 19:28 ` Tom Rini
2016-05-30 17:57 ` [U-Boot] [U-Boot, v2, " Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-06 19:28 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:05PM +0200, Alexander Graf wrote:
> This patch also adds the SPL time VCI string into Kconfig.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Tom Rini <trini@konsulko.com>
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160506/3b571003/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 6/7] net: Optionally use pxe client arch from variable
2016-05-06 19:01 ` [U-Boot] [PATCH v2 6/7] net: Optionally use pxe client arch from variable Alexander Graf
@ 2016-05-06 19:28 ` Tom Rini
2016-05-12 13:51 ` [U-Boot] [PATCH v4 " Alexander Graf
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-06 19:28 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:06PM +0200, Alexander Graf wrote:
> The client architecture that we pass to a dhcp server depends on the target
> payload that we want to execute. An EFI binary has a different client arch
> than a legacy binary or a u-boot binary.
>
> So let's parameterize the pxe client arch field to allow an override via
> the distro script, so that our efi boot path can tell the dhcp server that
> it's actually an efi firmware.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Tom Rini <trini@konsulko.com>
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160506/4a887d23/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v2 7/7] distro: Add efi pxe boot code
2016-05-06 19:01 ` [U-Boot] [PATCH v2 7/7] distro: Add efi pxe boot code Alexander Graf
@ 2016-05-06 19:28 ` Tom Rini
2016-05-30 17:57 ` [U-Boot] [U-Boot,v2,7/7] " Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-06 19:28 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:07PM +0200, Alexander Graf wrote:
> Now that we can expose network functionality to EFI applications,
> the logical next step is to load them via pxe to execute them as
> well.
>
> This patch adds the necessary bits to the distro script to automatically
> load and execute EFI payloads. It identifies the dhcp client as a uEFI
> capable PXE client, hoping the server returns a tftp path to a workable
> EFI binary that we can then execute.
>
> To enable boards that don't come with a working device tree preloaded,
> this patch also adds support to load a device tree from the /dtb directory
> on the remote tftp server.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
>
Reviewed-by: Tom Rini <trini@konsulko.com>
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160506/cac73bae/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v3 1/7] efi_loader: Add network access support
2016-05-06 19:01 ` [U-Boot] [PATCH v2 1/7] efi_loader: Add network access support Alexander Graf
@ 2016-05-10 21:25 ` Alexander Graf
2016-05-14 19:49 ` Simon Glass
2016-05-30 17:56 ` [U-Boot] [U-Boot, v2, " Tom Rini
1 sibling, 1 reply; 30+ messages in thread
From: Alexander Graf @ 2016-05-10 21:25 UTC (permalink / raw)
To: u-boot
We can now successfully boot EFI applications from disk, but users
may want to also run them from a PXE setup.
This patch implements rudimentary network support, allowing a payload
to send and receive network packets.
With this patch, I was able to successfully run grub2 with network
access inside of QEMU's -M xlnx-ep108 and on a zcu102 system.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
v2 -> v3:
- Align initialization sequence with net code
- Set device to initialized after init call
- Align tx buffers to DMA alignment (rx gets memcpy'd)
- Add comment about eth_rx()
---
cmd/bootefi.c | 7 ++
include/efi_api.h | 119 ++++++++++++++++++
include/efi_loader.h | 7 ++
include/net.h | 2 +-
lib/efi_loader/Makefile | 1 +
lib/efi_loader/efi_net.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++
net/bootp.c | 2 +
net/net.c | 4 +-
net/tftp.c | 2 +
9 files changed, 455 insertions(+), 3 deletions(-)
create mode 100644 lib/efi_loader/efi_net.c
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 7f552fc..d3a2331 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -197,6 +197,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
#ifdef CONFIG_LCD
efi_gop_register();
#endif
+#ifdef CONFIG_NET
+ void *nethandle = loaded_image_info.device_handle;
+ efi_net_register(&nethandle);
+
+ if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
+ loaded_image_info.device_handle = nethandle;
+#endif
/* Call our payload! */
#ifdef DEBUG_EFI
diff --git a/include/efi_api.h b/include/efi_api.h
index 51d7586..20035d7 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -412,4 +412,123 @@ struct efi_gop
struct efi_gop_mode *mode;
};
+#define EFI_SIMPLE_NETWORK_GUID \
+ EFI_GUID(0xa19832b9, 0xac25, 0x11d3, \
+ 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
+
+struct efi_mac_address {
+ char mac_addr[32];
+};
+
+struct efi_ip_address {
+ u8 ip_addr[16];
+};
+
+enum efi_simple_network_state {
+ EFI_NETWORK_STOPPED,
+ EFI_NETWORK_STARTED,
+ EFI_NETWORK_INITIALIZED,
+};
+
+struct efi_simple_network_mode {
+ enum efi_simple_network_state state;
+ u32 hwaddr_size;
+ u32 media_header_size;
+ u32 max_packet_size;
+ u32 nvram_size;
+ u32 nvram_access_size;
+ u32 receive_filter_mask;
+ u32 receive_filter_setting;
+ u32 max_mcast_filter_count;
+ u32 mcast_filter_count;
+ struct efi_mac_address mcast_filter[16];
+ struct efi_mac_address current_address;
+ struct efi_mac_address broadcast_address;
+ struct efi_mac_address permanent_address;
+ u8 if_type;
+ u8 mac_changeable;
+ u8 multitx_supported;
+ u8 media_present_supported;
+ u8 media_present;
+};
+
+#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01,
+#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02,
+#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04,
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08,
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10,
+
+struct efi_simple_network
+{
+ u64 revision;
+ efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
+ efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
+ efi_status_t (EFIAPI *initialize)(struct efi_simple_network *this,
+ ulong extra_rx, ulong extra_tx);
+ efi_status_t (EFIAPI *reset)(struct efi_simple_network *this,
+ int extended_verification);
+ efi_status_t (EFIAPI *shutdown)(struct efi_simple_network *this);
+ efi_status_t (EFIAPI *receive_filters)(struct efi_simple_network *this,
+ u32 enable, u32 disable, int reset_mcast_filter,
+ ulong mcast_filter_count,
+ struct efi_mac_address *mcast_filter);
+ efi_status_t (EFIAPI *station_address)(struct efi_simple_network *this,
+ int reset, struct efi_mac_address *new_mac);
+ efi_status_t (EFIAPI *statistics)(struct efi_simple_network *this,
+ int reset, ulong *stat_size, void *stat_table);
+ efi_status_t (EFIAPI *mcastiptomac)(struct efi_simple_network *this,
+ int ipv6, struct efi_ip_address *ip,
+ struct efi_mac_address *mac);
+ efi_status_t (EFIAPI *nvdata)(struct efi_simple_network *this,
+ int read_write, ulong offset, ulong buffer_size,
+ char *buffer);
+ efi_status_t (EFIAPI *get_status)(struct efi_simple_network *this,
+ u32 *int_status, void **txbuf);
+ efi_status_t (EFIAPI *transmit)(struct efi_simple_network *this,
+ ulong header_size, ulong buffer_size, void *buffer,
+ struct efi_mac_address *src_addr,
+ struct efi_mac_address *dest_addr, u16 *protocol);
+ efi_status_t (EFIAPI *receive)(struct efi_simple_network *this,
+ ulong *header_size, ulong *buffer_size, void *buffer,
+ struct efi_mac_address *src_addr,
+ struct efi_mac_address *dest_addr, u16 *protocol);
+ void (EFIAPI *waitforpacket)(void);
+ struct efi_simple_network_mode *mode;
+};
+
+#define EFI_PXE_GUID \
+ EFI_GUID(0x03c4e603, 0xac28, 0x11d3, \
+ 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
+
+struct efi_pxe_packet {
+ u8 packet[1472];
+};
+
+struct efi_pxe_mode
+{
+ u8 unused[52];
+ struct efi_pxe_packet dhcp_discover;
+ struct efi_pxe_packet dhcp_ack;
+ struct efi_pxe_packet proxy_offer;
+ struct efi_pxe_packet pxe_discover;
+ struct efi_pxe_packet pxe_reply;
+};
+
+struct efi_pxe {
+ u64 rev;
+ void (EFIAPI *start)(void);
+ void (EFIAPI *stop)(void);
+ void (EFIAPI *dhcp)(void);
+ void (EFIAPI *discover)(void);
+ void (EFIAPI *mftp)(void);
+ void (EFIAPI *udpwrite)(void);
+ void (EFIAPI *udpread)(void);
+ void (EFIAPI *setipfilter)(void);
+ void (EFIAPI *arp)(void);
+ void (EFIAPI *setparams)(void);
+ void (EFIAPI *setstationip)(void);
+ void (EFIAPI *setpackets)(void);
+ struct efi_pxe_mode *mode;
+};
+
#endif
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 88b8149..8005454 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -91,6 +91,12 @@ extern struct list_head efi_obj_list;
int efi_disk_register(void);
/* Called by bootefi to make GOP (graphical) interface available */
int efi_gop_register(void);
+/* Called by bootefi to make the network interface available */
+int efi_net_register(void **handle);
+
+/* Called by networking code to memorize the dhcp ack package */
+void efi_net_set_dhcp_ack(void *pkt, int len);
+
/*
* Stub implementation for a protocol opener that just returns the handle as
* interface
@@ -157,5 +163,6 @@ static inline void ascii2unicode(u16 *unicode, char *ascii)
static inline void efi_restore_gd(void) { }
static inline void efi_set_bootdev(const char *dev, const char *devnr,
const char *path) { }
+static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
#endif
diff --git a/include/net.h b/include/net.h
index 05800c4..5ee5929 100644
--- a/include/net.h
+++ b/include/net.h
@@ -269,7 +269,7 @@ int eth_getenv_enetaddr_by_index(const char *base_name, int index,
int eth_init(void); /* Initialize the device */
int eth_send(void *packet, int length); /* Send a packet */
-#ifdef CONFIG_API
+#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
int eth_receive(void *packet, int length); /* Receive a packet*/
extern void (*push_packet)(void *packet, int length);
#endif
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 83e31f6..2a3849e 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -11,3 +11,4 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
obj-y += efi_memory.o
obj-$(CONFIG_LCD) += efi_gop.o
obj-$(CONFIG_PARTITIONS) += efi_disk.o
+obj-$(CONFIG_NET) += efi_net.o
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
new file mode 100644
index 0000000..a95ff3c
--- /dev/null
+++ b/lib/efi_loader/efi_net.c
@@ -0,0 +1,314 @@
+/*
+ * EFI application network access support
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <inttypes.h>
+#include <lcd.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
+static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
+static struct efi_pxe_packet *dhcp_ack;
+static bool new_rx_packet;
+static void *new_tx_packet;
+
+struct efi_net_obj {
+ /* Generic EFI object parent class data */
+ struct efi_object parent;
+ /* EFI Interface callback struct for network */
+ struct efi_simple_network net;
+ struct efi_simple_network_mode net_mode;
+ /* Device path to the network adapter */
+ struct efi_device_path_file_path dp[2];
+ /* PXE struct to transmit dhcp data */
+ struct efi_pxe pxe;
+ struct efi_pxe_mode pxe_mode;
+};
+
+static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
+{
+ EFI_ENTRY("%p", this);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
+{
+ EFI_ENTRY("%p", this);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
+ ulong extra_rx, ulong extra_tx)
+{
+ struct efi_net_obj *netobj = container_of(this, struct efi_net_obj, net);
+ int ret;
+ EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
+
+ eth_halt();
+ eth_set_current();
+ ret = eth_init();
+ if (ret < 0) {
+ eth_halt();
+ return EFI_EXIT(EFI_DEVICE_ERROR);
+ }
+
+ netobj->net_mode.state = EFI_NETWORK_INITIALIZED;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
+ int extended_verification)
+{
+ EFI_ENTRY("%p, %x", this, extended_verification);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
+{
+ EFI_ENTRY("%p", this);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_receive_filters(
+ struct efi_simple_network *this, u32 enable, u32 disable,
+ int reset_mcast_filter, ulong mcast_filter_count,
+ struct efi_mac_address *mcast_filter)
+{
+ EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
+ reset_mcast_filter, mcast_filter_count, mcast_filter);
+
+ /* XXX Do we care? */
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_station_address(
+ struct efi_simple_network *this, int reset,
+ struct efi_mac_address *new_mac)
+{
+ EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
+
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
+ int reset, ulong *stat_size,
+ void *stat_table)
+{
+ EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
+
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
+ int ipv6,
+ struct efi_ip_address *ip,
+ struct efi_mac_address *mac)
+{
+ EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
+
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
+ int read_write, ulong offset,
+ ulong buffer_size, char *buffer)
+{
+ EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
+ buffer);
+
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
+ u32 *int_status, void **txbuf)
+{
+ EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
+
+ /* We send packets synchronously, so nothing is outstanding */
+ if (int_status)
+ *int_status = 0;
+ if (txbuf)
+ *txbuf = new_tx_packet;
+
+ new_tx_packet = NULL;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
+ ulong header_size, ulong buffer_size, void *buffer,
+ struct efi_mac_address *src_addr,
+ struct efi_mac_address *dest_addr, u16 *protocol)
+{
+ EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
+ buffer_size, buffer, src_addr, dest_addr, protocol);
+
+ if (header_size) {
+ /* We would need to create the header if header_size != 0 */
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+ }
+
+ /*
+ * Some drivers need to have DMA aligned buffers, so if
+ * it's misaligned, let's use our own.
+ */
+ if ((ulong)buffer & (ARCH_DMA_MINALIGN - 1)) {
+ void *packet = memalign(ARCH_DMA_MINALIGN, buffer_size);
+ memcpy(packet, buffer, buffer_size);
+ net_send_packet(packet, buffer_size);
+ free(packet);
+ } else {
+ net_send_packet(buffer, buffer_size);
+ }
+
+ new_tx_packet = buffer;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static void efi_net_push(void *pkt, int len)
+{
+ new_rx_packet = true;
+}
+
+static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
+ ulong *header_size, ulong *buffer_size, void *buffer,
+ struct efi_mac_address *src_addr,
+ struct efi_mac_address *dest_addr, u16 *protocol)
+{
+ EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
+ buffer_size, buffer, src_addr, dest_addr, protocol);
+
+ push_packet = efi_net_push;
+ /* XXX With device model this reads multiple packets, we only want 1 */
+ eth_rx();
+ push_packet = NULL;
+
+ if (!new_rx_packet)
+ return EFI_EXIT(EFI_NOT_READY);
+
+ if (*buffer_size < net_rx_packet_len) {
+ /* Packet doesn't fit, try again with bigger buf */
+ *buffer_size = net_rx_packet_len;
+ return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+ }
+
+ memcpy(buffer, net_rx_packet, net_rx_packet_len);
+ *buffer_size = net_rx_packet_len;
+ new_rx_packet = false;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
+ void **protocol_interface, void *agent_handle,
+ void *controller_handle, uint32_t attributes)
+{
+ struct efi_simple_network *net = handle;
+ struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
+
+ *protocol_interface = netobj->dp;
+
+ return EFI_SUCCESS;
+}
+
+static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol,
+ void **protocol_interface, void *agent_handle,
+ void *controller_handle, uint32_t attributes)
+{
+ struct efi_simple_network *net = handle;
+ struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
+
+ *protocol_interface = &netobj->pxe;
+
+ return EFI_SUCCESS;
+}
+
+void efi_net_set_dhcp_ack(void *pkt, int len)
+{
+ int maxsize = sizeof(*dhcp_ack);
+
+ if (!dhcp_ack)
+ dhcp_ack = malloc(maxsize);
+
+ memcpy(dhcp_ack, pkt, min(len, maxsize));
+}
+
+/* This gets called from do_bootefi_exec(). */
+int efi_net_register(void **handle)
+{
+ struct efi_net_obj *netobj;
+ struct efi_device_path_file_path dp_net = {
+ .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
+ .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
+ .dp.length = sizeof(dp_net),
+ .str = { 'N', 'e', 't' },
+ };
+ struct efi_device_path_file_path dp_end = {
+ .dp.type = DEVICE_PATH_TYPE_END,
+ .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
+ .dp.length = sizeof(dp_end),
+ };
+
+ if (!eth_get_dev()) {
+ /* No eth device active, don't expose any */
+ return 0;
+ }
+
+ /* We only expose the "active" eth device, so one is enough */
+ netobj = calloc(1, sizeof(*netobj));
+
+ /* Fill in object data */
+ netobj->parent.protocols[0].guid = &efi_net_guid;
+ netobj->parent.protocols[0].open = efi_return_handle;
+ netobj->parent.protocols[1].guid = &efi_guid_device_path;
+ netobj->parent.protocols[1].open = efi_net_open_dp;
+ netobj->parent.protocols[2].guid = &efi_pxe_guid;
+ netobj->parent.protocols[2].open = efi_net_open_pxe;
+ netobj->parent.handle = &netobj->net;
+ netobj->net.start = efi_net_start;
+ netobj->net.stop = efi_net_stop;
+ netobj->net.initialize = efi_net_initialize;
+ netobj->net.reset = efi_net_reset;
+ netobj->net.shutdown = efi_net_shutdown;
+ netobj->net.receive_filters = efi_net_receive_filters;
+ netobj->net.station_address = efi_net_station_address;
+ netobj->net.statistics = efi_net_statistics;
+ netobj->net.mcastiptomac = efi_net_mcastiptomac;
+ netobj->net.nvdata = efi_net_nvdata;
+ netobj->net.get_status = efi_net_get_status;
+ netobj->net.transmit = efi_net_transmit;
+ netobj->net.receive = efi_net_receive;
+ netobj->net.mode = &netobj->net_mode;
+ netobj->net_mode.state = EFI_NETWORK_STARTED;
+ netobj->dp[0] = dp_net;
+ netobj->dp[1] = dp_end;
+ memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
+ netobj->net_mode.max_packet_size = PKTSIZE;
+
+ netobj->pxe.mode = &netobj->pxe_mode;
+ if (dhcp_ack)
+ netobj->pxe_mode.dhcp_ack = *dhcp_ack;
+
+ /* Hook net up to the device list */
+ list_add_tail(&netobj->parent.link, &efi_obj_list);
+
+ if (handle)
+ *handle = &netobj->net;
+
+ return 0;
+}
diff --git a/net/bootp.c b/net/bootp.c
index d7852db..d91b307 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <command.h>
+#include <efi_loader.h>
#include <net.h>
#include <net/tftp.h>
#include "bootp.h"
@@ -1025,6 +1026,7 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
dhcp_packet_process_options(bp);
+ efi_net_set_dhcp_ack(pkt, len);
debug("TRANSITIONING TO REQUESTING STATE\n");
dhcp_state = REQUESTING;
diff --git a/net/net.c b/net/net.c
index fba111e..1e1d23d 100644
--- a/net/net.c
+++ b/net/net.c
@@ -146,7 +146,7 @@ static unsigned net_ip_id;
/* Ethernet bcast address */
const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
const u8 net_null_ethaddr[6];
-#ifdef CONFIG_API
+#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
void (*push_packet)(void *, int len) = 0;
#endif
/* Network loop state */
@@ -1054,7 +1054,7 @@ void net_process_received_packet(uchar *in_packet, int len)
if (len < ETHER_HDR_SIZE)
return;
-#ifdef CONFIG_API
+#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
if (push_packet) {
(*push_packet)(in_packet, len);
return;
diff --git a/net/tftp.c b/net/tftp.c
index f2889fe..ced45ec 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <command.h>
+#include <efi_loader.h>
#include <mapmem.h>
#include <net.h>
#include <net/tftp.h>
@@ -804,6 +805,7 @@ void tftp_start(enum proto_t protocol)
printf("Load address: 0x%lx\n", load_addr);
puts("Loading: *\b");
tftp_state = STATE_SEND_RRQ;
+ efi_set_bootdev("Net", "", tftp_filename);
}
time_start = get_timer(0);
--
1.8.5.6
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v4 6/7] net: Optionally use pxe client arch from variable
2016-05-06 19:01 ` [U-Boot] [PATCH v2 6/7] net: Optionally use pxe client arch from variable Alexander Graf
2016-05-06 19:28 ` Tom Rini
@ 2016-05-12 13:51 ` Alexander Graf
2016-05-30 17:57 ` [U-Boot] [U-Boot, v4, " Tom Rini
1 sibling, 1 reply; 30+ messages in thread
From: Alexander Graf @ 2016-05-12 13:51 UTC (permalink / raw)
To: u-boot
The client architecture that we pass to a dhcp server depends on the target
payload that we want to execute. An EFI binary has a different client arch
than a legacy binary or a u-boot binary.
So let's parameterize the pxe client arch field to allow an override via
the distro script, so that our efi boot path can tell the dhcp server that
it's actually an efi firmware.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
v3 -> v4:
- Fix compile build for !CONFIG_LIB_UUID
---
net/bootp.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/net/bootp.c b/net/bootp.c
index d718e35..c1c32a1 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -431,10 +431,10 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
{
u8 *start = e;
u8 *cnt;
-#if defined(CONFIG_BOOTP_PXE)
+#ifdef CONFIG_LIB_UUID
char *uuid;
- u16 clientarch;
#endif
+ int clientarch = -1;
#if defined(CONFIG_BOOTP_VENDOREX)
u8 *x;
@@ -490,12 +490,19 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
}
#endif
-#if defined(CONFIG_BOOTP_PXE)
+#ifdef CONFIG_BOOTP_PXE_CLIENTARCH
clientarch = CONFIG_BOOTP_PXE_CLIENTARCH;
- *e++ = 93; /* Client System Architecture */
- *e++ = 2;
- *e++ = (clientarch >> 8) & 0xff;
- *e++ = clientarch & 0xff;
+#endif
+
+ if (getenv("bootp_arch"))
+ clientarch = getenv_ulong("bootp_arch", 16, clientarch);
+
+ if (clientarch > 0) {
+ *e++ = 93; /* Client System Architecture */
+ *e++ = 2;
+ *e++ = (clientarch >> 8) & 0xff;
+ *e++ = clientarch & 0xff;
+ }
*e++ = 94; /* Client Network Interface Identifier */
*e++ = 3;
@@ -503,6 +510,7 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
*e++ = 0; /* major revision */
*e++ = 0; /* minor revision */
+#ifdef CONFIG_LIB_UUID
uuid = getenv("pxeuuid");
if (uuid) {
--
1.8.5.6
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v3 1/7] efi_loader: Add network access support
2016-05-10 21:25 ` [U-Boot] [PATCH v3 " Alexander Graf
@ 2016-05-14 19:49 ` Simon Glass
2016-05-14 20:34 ` Alexander Graf
0 siblings, 1 reply; 30+ messages in thread
From: Simon Glass @ 2016-05-14 19:49 UTC (permalink / raw)
To: u-boot
Hi Alexander,
On 10 May 2016 at 15:25, Alexander Graf <agraf@suse.de> wrote:
> We can now successfully boot EFI applications from disk, but users
> may want to also run them from a PXE setup.
>
> This patch implements rudimentary network support, allowing a payload
> to send and receive network packets.
>
> With this patch, I was able to successfully run grub2 with network
> access inside of QEMU's -M xlnx-ep108 and on a zcu102 system.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
>
> ---
>
> v2 -> v3:
>
> - Align initialization sequence with net code
> - Set device to initialized after init call
> - Align tx buffers to DMA alignment (rx gets memcpy'd)
> - Add comment about eth_rx()
> ---
> cmd/bootefi.c | 7 ++
> include/efi_api.h | 119 ++++++++++++++++++
> include/efi_loader.h | 7 ++
> include/net.h | 2 +-
> lib/efi_loader/Makefile | 1 +
> lib/efi_loader/efi_net.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++
> net/bootp.c | 2 +
> net/net.c | 4 +-
> net/tftp.c | 2 +
> 9 files changed, 455 insertions(+), 3 deletions(-)
> create mode 100644 lib/efi_loader/efi_net.c
>
> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
> index 7f552fc..d3a2331 100644
> --- a/cmd/bootefi.c
> +++ b/cmd/bootefi.c
> @@ -197,6 +197,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
> #ifdef CONFIG_LCD
> efi_gop_register();
> #endif
> +#ifdef CONFIG_NET
> + void *nethandle = loaded_image_info.device_handle;
> + efi_net_register(&nethandle);
> +
> + if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
> + loaded_image_info.device_handle = nethandle;
> +#endif
>
> /* Call our payload! */
> #ifdef DEBUG_EFI
> diff --git a/include/efi_api.h b/include/efi_api.h
> index 51d7586..20035d7 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -412,4 +412,123 @@ struct efi_gop
> struct efi_gop_mode *mode;
> };
>
> +#define EFI_SIMPLE_NETWORK_GUID \
> + EFI_GUID(0xa19832b9, 0xac25, 0x11d3, \
> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
> +
> +struct efi_mac_address {
> + char mac_addr[32];
> +};
> +
> +struct efi_ip_address {
> + u8 ip_addr[16];
> +};
> +
> +enum efi_simple_network_state {
> + EFI_NETWORK_STOPPED,
> + EFI_NETWORK_STARTED,
> + EFI_NETWORK_INITIALIZED,
> +};
> +
> +struct efi_simple_network_mode {
> + enum efi_simple_network_state state;
> + u32 hwaddr_size;
> + u32 media_header_size;
> + u32 max_packet_size;
> + u32 nvram_size;
> + u32 nvram_access_size;
> + u32 receive_filter_mask;
> + u32 receive_filter_setting;
> + u32 max_mcast_filter_count;
> + u32 mcast_filter_count;
> + struct efi_mac_address mcast_filter[16];
> + struct efi_mac_address current_address;
> + struct efi_mac_address broadcast_address;
> + struct efi_mac_address permanent_address;
> + u8 if_type;
> + u8 mac_changeable;
> + u8 multitx_supported;
> + u8 media_present_supported;
> + u8 media_present;
> +};
> +
> +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01,
> +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02,
> +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04,
> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08,
> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10,
> +
> +struct efi_simple_network
> +{
> + u64 revision;
> + efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
> + efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
> + efi_status_t (EFIAPI *initialize)(struct efi_simple_network *this,
> + ulong extra_rx, ulong extra_tx);
> + efi_status_t (EFIAPI *reset)(struct efi_simple_network *this,
> + int extended_verification);
> + efi_status_t (EFIAPI *shutdown)(struct efi_simple_network *this);
> + efi_status_t (EFIAPI *receive_filters)(struct efi_simple_network *this,
> + u32 enable, u32 disable, int reset_mcast_filter,
> + ulong mcast_filter_count,
> + struct efi_mac_address *mcast_filter);
> + efi_status_t (EFIAPI *station_address)(struct efi_simple_network *this,
> + int reset, struct efi_mac_address *new_mac);
> + efi_status_t (EFIAPI *statistics)(struct efi_simple_network *this,
> + int reset, ulong *stat_size, void *stat_table);
> + efi_status_t (EFIAPI *mcastiptomac)(struct efi_simple_network *this,
> + int ipv6, struct efi_ip_address *ip,
> + struct efi_mac_address *mac);
> + efi_status_t (EFIAPI *nvdata)(struct efi_simple_network *this,
> + int read_write, ulong offset, ulong buffer_size,
> + char *buffer);
> + efi_status_t (EFIAPI *get_status)(struct efi_simple_network *this,
> + u32 *int_status, void **txbuf);
> + efi_status_t (EFIAPI *transmit)(struct efi_simple_network *this,
> + ulong header_size, ulong buffer_size, void *buffer,
> + struct efi_mac_address *src_addr,
> + struct efi_mac_address *dest_addr, u16 *protocol);
> + efi_status_t (EFIAPI *receive)(struct efi_simple_network *this,
> + ulong *header_size, ulong *buffer_size, void *buffer,
> + struct efi_mac_address *src_addr,
> + struct efi_mac_address *dest_addr, u16 *protocol);
> + void (EFIAPI *waitforpacket)(void);
> + struct efi_simple_network_mode *mode;
> +};
> +
> +#define EFI_PXE_GUID \
> + EFI_GUID(0x03c4e603, 0xac28, 0x11d3, \
> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
> +
> +struct efi_pxe_packet {
> + u8 packet[1472];
> +};
> +
> +struct efi_pxe_mode
> +{
> + u8 unused[52];
> + struct efi_pxe_packet dhcp_discover;
> + struct efi_pxe_packet dhcp_ack;
> + struct efi_pxe_packet proxy_offer;
> + struct efi_pxe_packet pxe_discover;
> + struct efi_pxe_packet pxe_reply;
> +};
> +
> +struct efi_pxe {
> + u64 rev;
> + void (EFIAPI *start)(void);
> + void (EFIAPI *stop)(void);
> + void (EFIAPI *dhcp)(void);
> + void (EFIAPI *discover)(void);
> + void (EFIAPI *mftp)(void);
> + void (EFIAPI *udpwrite)(void);
> + void (EFIAPI *udpread)(void);
> + void (EFIAPI *setipfilter)(void);
> + void (EFIAPI *arp)(void);
> + void (EFIAPI *setparams)(void);
> + void (EFIAPI *setstationip)(void);
> + void (EFIAPI *setpackets)(void);
> + struct efi_pxe_mode *mode;
> +};
> +
> #endif
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 88b8149..8005454 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -91,6 +91,12 @@ extern struct list_head efi_obj_list;
> int efi_disk_register(void);
> /* Called by bootefi to make GOP (graphical) interface available */
> int efi_gop_register(void);
> +/* Called by bootefi to make the network interface available */
> +int efi_net_register(void **handle);
> +
> +/* Called by networking code to memorize the dhcp ack package */
> +void efi_net_set_dhcp_ack(void *pkt, int len);
> +
> /*
> * Stub implementation for a protocol opener that just returns the handle as
> * interface
> @@ -157,5 +163,6 @@ static inline void ascii2unicode(u16 *unicode, char *ascii)
> static inline void efi_restore_gd(void) { }
> static inline void efi_set_bootdev(const char *dev, const char *devnr,
> const char *path) { }
> +static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
>
> #endif
> diff --git a/include/net.h b/include/net.h
> index 05800c4..5ee5929 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -269,7 +269,7 @@ int eth_getenv_enetaddr_by_index(const char *base_name, int index,
> int eth_init(void); /* Initialize the device */
> int eth_send(void *packet, int length); /* Send a packet */
>
> -#ifdef CONFIG_API
> +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
> int eth_receive(void *packet, int length); /* Receive a packet*/
> extern void (*push_packet)(void *packet, int length);
> #endif
> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> index 83e31f6..2a3849e 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -11,3 +11,4 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
> obj-y += efi_memory.o
> obj-$(CONFIG_LCD) += efi_gop.o
> obj-$(CONFIG_PARTITIONS) += efi_disk.o
> +obj-$(CONFIG_NET) += efi_net.o
> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
> new file mode 100644
> index 0000000..a95ff3c
> --- /dev/null
> +++ b/lib/efi_loader/efi_net.c
> @@ -0,0 +1,314 @@
> +/*
> + * EFI application network access support
> + *
> + * Copyright (c) 2016 Alexander Graf
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <efi_loader.h>
> +#include <inttypes.h>
> +#include <lcd.h>
> +#include <malloc.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
> +static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
> +static struct efi_pxe_packet *dhcp_ack;
> +static bool new_rx_packet;
> +static void *new_tx_packet;
> +
> +struct efi_net_obj {
> + /* Generic EFI object parent class data */
> + struct efi_object parent;
> + /* EFI Interface callback struct for network */
> + struct efi_simple_network net;
> + struct efi_simple_network_mode net_mode;
> + /* Device path to the network adapter */
> + struct efi_device_path_file_path dp[2];
> + /* PXE struct to transmit dhcp data */
> + struct efi_pxe pxe;
> + struct efi_pxe_mode pxe_mode;
> +};
> +
> +static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
> +{
> + EFI_ENTRY("%p", this);
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
> +{
> + EFI_ENTRY("%p", this);
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
> + ulong extra_rx, ulong extra_tx)
> +{
> + struct efi_net_obj *netobj = container_of(this, struct efi_net_obj, net);
> + int ret;
> + EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
> +
> + eth_halt();
> + eth_set_current();
> + ret = eth_init();
> + if (ret < 0) {
> + eth_halt();
> + return EFI_EXIT(EFI_DEVICE_ERROR);
> + }
> +
> + netobj->net_mode.state = EFI_NETWORK_INITIALIZED;
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
> + int extended_verification)
> +{
> + EFI_ENTRY("%p, %x", this, extended_verification);
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
> +{
> + EFI_ENTRY("%p", this);
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t EFIAPI efi_net_receive_filters(
> + struct efi_simple_network *this, u32 enable, u32 disable,
> + int reset_mcast_filter, ulong mcast_filter_count,
> + struct efi_mac_address *mcast_filter)
> +{
> + EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
> + reset_mcast_filter, mcast_filter_count, mcast_filter);
> +
> + /* XXX Do we care? */
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t EFIAPI efi_net_station_address(
> + struct efi_simple_network *this, int reset,
> + struct efi_mac_address *new_mac)
> +{
> + EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
> +
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> +}
> +
> +static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
> + int reset, ulong *stat_size,
> + void *stat_table)
> +{
> + EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
> +
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> +}
> +
> +static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
> + int ipv6,
> + struct efi_ip_address *ip,
> + struct efi_mac_address *mac)
> +{
> + EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
> +
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> +}
> +
> +static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
> + int read_write, ulong offset,
> + ulong buffer_size, char *buffer)
> +{
> + EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
> + buffer);
> +
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> +}
> +
> +static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
> + u32 *int_status, void **txbuf)
> +{
> + EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
> +
> + /* We send packets synchronously, so nothing is outstanding */
> + if (int_status)
> + *int_status = 0;
> + if (txbuf)
> + *txbuf = new_tx_packet;
> +
> + new_tx_packet = NULL;
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
> + ulong header_size, ulong buffer_size, void *buffer,
> + struct efi_mac_address *src_addr,
> + struct efi_mac_address *dest_addr, u16 *protocol)
> +{
> + EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
> + buffer_size, buffer, src_addr, dest_addr, protocol);
> +
> + if (header_size) {
> + /* We would need to create the header if header_size != 0 */
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> + }
> +
> + /*
> + * Some drivers need to have DMA aligned buffers, so if
> + * it's misaligned, let's use our own.
> + */
> + if ((ulong)buffer & (ARCH_DMA_MINALIGN - 1)) {
> + void *packet = memalign(ARCH_DMA_MINALIGN, buffer_size);
> + memcpy(packet, buffer, buffer_size);
> + net_send_packet(packet, buffer_size);
> + free(packet);
> + } else {
> + net_send_packet(buffer, buffer_size);
> + }
> +
> + new_tx_packet = buffer;
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static void efi_net_push(void *pkt, int len)
> +{
> + new_rx_packet = true;
> +}
> +
> +static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
> + ulong *header_size, ulong *buffer_size, void *buffer,
> + struct efi_mac_address *src_addr,
> + struct efi_mac_address *dest_addr, u16 *protocol)
> +{
> + EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
> + buffer_size, buffer, src_addr, dest_addr, protocol);
> +
> + push_packet = efi_net_push;
> + /* XXX With device model this reads multiple packets, we only want 1 */
> + eth_rx();
> + push_packet = NULL;
> +
> + if (!new_rx_packet)
> + return EFI_EXIT(EFI_NOT_READY);
> +
> + if (*buffer_size < net_rx_packet_len) {
> + /* Packet doesn't fit, try again with bigger buf */
> + *buffer_size = net_rx_packet_len;
> + return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
> + }
> +
> + memcpy(buffer, net_rx_packet, net_rx_packet_len);
> + *buffer_size = net_rx_packet_len;
> + new_rx_packet = false;
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
> + void **protocol_interface, void *agent_handle,
> + void *controller_handle, uint32_t attributes)
> +{
> + struct efi_simple_network *net = handle;
> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
> +
> + *protocol_interface = netobj->dp;
> +
> + return EFI_SUCCESS;
> +}
> +
> +static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol,
> + void **protocol_interface, void *agent_handle,
> + void *controller_handle, uint32_t attributes)
> +{
> + struct efi_simple_network *net = handle;
> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
> +
> + *protocol_interface = &netobj->pxe;
> +
> + return EFI_SUCCESS;
> +}
> +
> +void efi_net_set_dhcp_ack(void *pkt, int len)
> +{
> + int maxsize = sizeof(*dhcp_ack);
> +
> + if (!dhcp_ack)
> + dhcp_ack = malloc(maxsize);
> +
> + memcpy(dhcp_ack, pkt, min(len, maxsize));
> +}
> +
> +/* This gets called from do_bootefi_exec(). */
> +int efi_net_register(void **handle)
> +{
> + struct efi_net_obj *netobj;
> + struct efi_device_path_file_path dp_net = {
> + .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
> + .dp.length = sizeof(dp_net),
> + .str = { 'N', 'e', 't' },
> + };
> + struct efi_device_path_file_path dp_end = {
> + .dp.type = DEVICE_PATH_TYPE_END,
> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
> + .dp.length = sizeof(dp_end),
> + };
> +
> + if (!eth_get_dev()) {
> + /* No eth device active, don't expose any */
> + return 0;
> + }
> +
> + /* We only expose the "active" eth device, so one is enough */
> + netobj = calloc(1, sizeof(*netobj));
> +
> + /* Fill in object data */
> + netobj->parent.protocols[0].guid = &efi_net_guid;
> + netobj->parent.protocols[0].open = efi_return_handle;
> + netobj->parent.protocols[1].guid = &efi_guid_device_path;
> + netobj->parent.protocols[1].open = efi_net_open_dp;
> + netobj->parent.protocols[2].guid = &efi_pxe_guid;
> + netobj->parent.protocols[2].open = efi_net_open_pxe;
> + netobj->parent.handle = &netobj->net;
> + netobj->net.start = efi_net_start;
> + netobj->net.stop = efi_net_stop;
> + netobj->net.initialize = efi_net_initialize;
> + netobj->net.reset = efi_net_reset;
> + netobj->net.shutdown = efi_net_shutdown;
> + netobj->net.receive_filters = efi_net_receive_filters;
> + netobj->net.station_address = efi_net_station_address;
> + netobj->net.statistics = efi_net_statistics;
> + netobj->net.mcastiptomac = efi_net_mcastiptomac;
> + netobj->net.nvdata = efi_net_nvdata;
> + netobj->net.get_status = efi_net_get_status;
> + netobj->net.transmit = efi_net_transmit;
> + netobj->net.receive = efi_net_receive;
> + netobj->net.mode = &netobj->net_mode;
> + netobj->net_mode.state = EFI_NETWORK_STARTED;
> + netobj->dp[0] = dp_net;
> + netobj->dp[1] = dp_end;
> + memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
> + netobj->net_mode.max_packet_size = PKTSIZE;
Why is this statically created? Shouldn't it come from the U-Boot
ethernet tables dynamically when it is needed?
> +
> + netobj->pxe.mode = &netobj->pxe_mode;
> + if (dhcp_ack)
> + netobj->pxe_mode.dhcp_ack = *dhcp_ack;
> +
> + /* Hook net up to the device list */
> + list_add_tail(&netobj->parent.link, &efi_obj_list);
> +
> + if (handle)
> + *handle = &netobj->net;
> +
> + return 0;
> +}
> diff --git a/net/bootp.c b/net/bootp.c
> index d7852db..d91b307 100644
> --- a/net/bootp.c
> +++ b/net/bootp.c
> @@ -10,6 +10,7 @@
>
> #include <common.h>
> #include <command.h>
> +#include <efi_loader.h>
> #include <net.h>
> #include <net/tftp.h>
> #include "bootp.h"
> @@ -1025,6 +1026,7 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
> strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
> #endif /* CONFIG_SYS_BOOTFILE_PREFIX */
> dhcp_packet_process_options(bp);
> + efi_net_set_dhcp_ack(pkt, len);
>
> debug("TRANSITIONING TO REQUESTING STATE\n");
> dhcp_state = REQUESTING;
> diff --git a/net/net.c b/net/net.c
> index fba111e..1e1d23d 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -146,7 +146,7 @@ static unsigned net_ip_id;
> /* Ethernet bcast address */
> const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
> const u8 net_null_ethaddr[6];
> -#ifdef CONFIG_API
> +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
> void (*push_packet)(void *, int len) = 0;
> #endif
> /* Network loop state */
> @@ -1054,7 +1054,7 @@ void net_process_received_packet(uchar *in_packet, int len)
> if (len < ETHER_HDR_SIZE)
> return;
>
> -#ifdef CONFIG_API
> +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
> if (push_packet) {
> (*push_packet)(in_packet, len);
> return;
> diff --git a/net/tftp.c b/net/tftp.c
> index f2889fe..ced45ec 100644
> --- a/net/tftp.c
> +++ b/net/tftp.c
> @@ -8,6 +8,7 @@
>
> #include <common.h>
> #include <command.h>
> +#include <efi_loader.h>
> #include <mapmem.h>
> #include <net.h>
> #include <net/tftp.h>
> @@ -804,6 +805,7 @@ void tftp_start(enum proto_t protocol)
> printf("Load address: 0x%lx\n", load_addr);
> puts("Loading: *\b");
> tftp_state = STATE_SEND_RRQ;
> + efi_set_bootdev("Net", "", tftp_filename);
> }
>
> time_start = get_timer(0);
> --
> 1.8.5.6
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v3 1/7] efi_loader: Add network access support
2016-05-14 19:49 ` Simon Glass
@ 2016-05-14 20:34 ` Alexander Graf
2016-05-16 13:24 ` Simon Glass
0 siblings, 1 reply; 30+ messages in thread
From: Alexander Graf @ 2016-05-14 20:34 UTC (permalink / raw)
To: u-boot
> Am 14.05.2016 um 21:49 schrieb Simon Glass <sjg@chromium.org>:
>
> Hi Alexander,
>
>> On 10 May 2016 at 15:25, Alexander Graf <agraf@suse.de> wrote:
>> We can now successfully boot EFI applications from disk, but users
>> may want to also run them from a PXE setup.
>>
>> This patch implements rudimentary network support, allowing a payload
>> to send and receive network packets.
>>
>> With this patch, I was able to successfully run grub2 with network
>> access inside of QEMU's -M xlnx-ep108 and on a zcu102 system.
>>
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>
>> ---
>>
>> v2 -> v3:
>>
>> - Align initialization sequence with net code
>> - Set device to initialized after init call
>> - Align tx buffers to DMA alignment (rx gets memcpy'd)
>> - Add comment about eth_rx()
>> ---
>> cmd/bootefi.c | 7 ++
>> include/efi_api.h | 119 ++++++++++++++++++
>> include/efi_loader.h | 7 ++
>> include/net.h | 2 +-
>> lib/efi_loader/Makefile | 1 +
>> lib/efi_loader/efi_net.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++
>> net/bootp.c | 2 +
>> net/net.c | 4 +-
>> net/tftp.c | 2 +
>> 9 files changed, 455 insertions(+), 3 deletions(-)
>> create mode 100644 lib/efi_loader/efi_net.c
>>
>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>> index 7f552fc..d3a2331 100644
>> --- a/cmd/bootefi.c
>> +++ b/cmd/bootefi.c
>> @@ -197,6 +197,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
>> #ifdef CONFIG_LCD
>> efi_gop_register();
>> #endif
>> +#ifdef CONFIG_NET
>> + void *nethandle = loaded_image_info.device_handle;
>> + efi_net_register(&nethandle);
>> +
>> + if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
>> + loaded_image_info.device_handle = nethandle;
>> +#endif
>>
>> /* Call our payload! */
>> #ifdef DEBUG_EFI
>> diff --git a/include/efi_api.h b/include/efi_api.h
>> index 51d7586..20035d7 100644
>> --- a/include/efi_api.h
>> +++ b/include/efi_api.h
>> @@ -412,4 +412,123 @@ struct efi_gop
>> struct efi_gop_mode *mode;
>> };
>>
>> +#define EFI_SIMPLE_NETWORK_GUID \
>> + EFI_GUID(0xa19832b9, 0xac25, 0x11d3, \
>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>> +
>> +struct efi_mac_address {
>> + char mac_addr[32];
>> +};
>> +
>> +struct efi_ip_address {
>> + u8 ip_addr[16];
>> +};
>> +
>> +enum efi_simple_network_state {
>> + EFI_NETWORK_STOPPED,
>> + EFI_NETWORK_STARTED,
>> + EFI_NETWORK_INITIALIZED,
>> +};
>> +
>> +struct efi_simple_network_mode {
>> + enum efi_simple_network_state state;
>> + u32 hwaddr_size;
>> + u32 media_header_size;
>> + u32 max_packet_size;
>> + u32 nvram_size;
>> + u32 nvram_access_size;
>> + u32 receive_filter_mask;
>> + u32 receive_filter_setting;
>> + u32 max_mcast_filter_count;
>> + u32 mcast_filter_count;
>> + struct efi_mac_address mcast_filter[16];
>> + struct efi_mac_address current_address;
>> + struct efi_mac_address broadcast_address;
>> + struct efi_mac_address permanent_address;
>> + u8 if_type;
>> + u8 mac_changeable;
>> + u8 multitx_supported;
>> + u8 media_present_supported;
>> + u8 media_present;
>> +};
>> +
>> +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01,
>> +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02,
>> +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04,
>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08,
>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10,
>> +
>> +struct efi_simple_network
>> +{
>> + u64 revision;
>> + efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
>> + efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
>> + efi_status_t (EFIAPI *initialize)(struct efi_simple_network *this,
>> + ulong extra_rx, ulong extra_tx);
>> + efi_status_t (EFIAPI *reset)(struct efi_simple_network *this,
>> + int extended_verification);
>> + efi_status_t (EFIAPI *shutdown)(struct efi_simple_network *this);
>> + efi_status_t (EFIAPI *receive_filters)(struct efi_simple_network *this,
>> + u32 enable, u32 disable, int reset_mcast_filter,
>> + ulong mcast_filter_count,
>> + struct efi_mac_address *mcast_filter);
>> + efi_status_t (EFIAPI *station_address)(struct efi_simple_network *this,
>> + int reset, struct efi_mac_address *new_mac);
>> + efi_status_t (EFIAPI *statistics)(struct efi_simple_network *this,
>> + int reset, ulong *stat_size, void *stat_table);
>> + efi_status_t (EFIAPI *mcastiptomac)(struct efi_simple_network *this,
>> + int ipv6, struct efi_ip_address *ip,
>> + struct efi_mac_address *mac);
>> + efi_status_t (EFIAPI *nvdata)(struct efi_simple_network *this,
>> + int read_write, ulong offset, ulong buffer_size,
>> + char *buffer);
>> + efi_status_t (EFIAPI *get_status)(struct efi_simple_network *this,
>> + u32 *int_status, void **txbuf);
>> + efi_status_t (EFIAPI *transmit)(struct efi_simple_network *this,
>> + ulong header_size, ulong buffer_size, void *buffer,
>> + struct efi_mac_address *src_addr,
>> + struct efi_mac_address *dest_addr, u16 *protocol);
>> + efi_status_t (EFIAPI *receive)(struct efi_simple_network *this,
>> + ulong *header_size, ulong *buffer_size, void *buffer,
>> + struct efi_mac_address *src_addr,
>> + struct efi_mac_address *dest_addr, u16 *protocol);
>> + void (EFIAPI *waitforpacket)(void);
>> + struct efi_simple_network_mode *mode;
>> +};
>> +
>> +#define EFI_PXE_GUID \
>> + EFI_GUID(0x03c4e603, 0xac28, 0x11d3, \
>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>> +
>> +struct efi_pxe_packet {
>> + u8 packet[1472];
>> +};
>> +
>> +struct efi_pxe_mode
>> +{
>> + u8 unused[52];
>> + struct efi_pxe_packet dhcp_discover;
>> + struct efi_pxe_packet dhcp_ack;
>> + struct efi_pxe_packet proxy_offer;
>> + struct efi_pxe_packet pxe_discover;
>> + struct efi_pxe_packet pxe_reply;
>> +};
>> +
>> +struct efi_pxe {
>> + u64 rev;
>> + void (EFIAPI *start)(void);
>> + void (EFIAPI *stop)(void);
>> + void (EFIAPI *dhcp)(void);
>> + void (EFIAPI *discover)(void);
>> + void (EFIAPI *mftp)(void);
>> + void (EFIAPI *udpwrite)(void);
>> + void (EFIAPI *udpread)(void);
>> + void (EFIAPI *setipfilter)(void);
>> + void (EFIAPI *arp)(void);
>> + void (EFIAPI *setparams)(void);
>> + void (EFIAPI *setstationip)(void);
>> + void (EFIAPI *setpackets)(void);
>> + struct efi_pxe_mode *mode;
>> +};
>> +
>> #endif
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index 88b8149..8005454 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -91,6 +91,12 @@ extern struct list_head efi_obj_list;
>> int efi_disk_register(void);
>> /* Called by bootefi to make GOP (graphical) interface available */
>> int efi_gop_register(void);
>> +/* Called by bootefi to make the network interface available */
>> +int efi_net_register(void **handle);
>> +
>> +/* Called by networking code to memorize the dhcp ack package */
>> +void efi_net_set_dhcp_ack(void *pkt, int len);
>> +
>> /*
>> * Stub implementation for a protocol opener that just returns the handle as
>> * interface
>> @@ -157,5 +163,6 @@ static inline void ascii2unicode(u16 *unicode, char *ascii)
>> static inline void efi_restore_gd(void) { }
>> static inline void efi_set_bootdev(const char *dev, const char *devnr,
>> const char *path) { }
>> +static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
>>
>> #endif
>> diff --git a/include/net.h b/include/net.h
>> index 05800c4..5ee5929 100644
>> --- a/include/net.h
>> +++ b/include/net.h
>> @@ -269,7 +269,7 @@ int eth_getenv_enetaddr_by_index(const char *base_name, int index,
>> int eth_init(void); /* Initialize the device */
>> int eth_send(void *packet, int length); /* Send a packet */
>>
>> -#ifdef CONFIG_API
>> +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
>> int eth_receive(void *packet, int length); /* Receive a packet*/
>> extern void (*push_packet)(void *packet, int length);
>> #endif
>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>> index 83e31f6..2a3849e 100644
>> --- a/lib/efi_loader/Makefile
>> +++ b/lib/efi_loader/Makefile
>> @@ -11,3 +11,4 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>> obj-y += efi_memory.o
>> obj-$(CONFIG_LCD) += efi_gop.o
>> obj-$(CONFIG_PARTITIONS) += efi_disk.o
>> +obj-$(CONFIG_NET) += efi_net.o
>> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
>> new file mode 100644
>> index 0000000..a95ff3c
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_net.c
>> @@ -0,0 +1,314 @@
>> +/*
>> + * EFI application network access support
>> + *
>> + * Copyright (c) 2016 Alexander Graf
>> + *
>> + * SPDX-License-Identifier: GPL-2.0+
>> + */
>> +
>> +#include <common.h>
>> +#include <efi_loader.h>
>> +#include <inttypes.h>
>> +#include <lcd.h>
>> +#include <malloc.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
>> +static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
>> +static struct efi_pxe_packet *dhcp_ack;
>> +static bool new_rx_packet;
>> +static void *new_tx_packet;
>> +
>> +struct efi_net_obj {
>> + /* Generic EFI object parent class data */
>> + struct efi_object parent;
>> + /* EFI Interface callback struct for network */
>> + struct efi_simple_network net;
>> + struct efi_simple_network_mode net_mode;
>> + /* Device path to the network adapter */
>> + struct efi_device_path_file_path dp[2];
>> + /* PXE struct to transmit dhcp data */
>> + struct efi_pxe pxe;
>> + struct efi_pxe_mode pxe_mode;
>> +};
>> +
>> +static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
>> +{
>> + EFI_ENTRY("%p", this);
>> +
>> + return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
>> +{
>> + EFI_ENTRY("%p", this);
>> +
>> + return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
>> + ulong extra_rx, ulong extra_tx)
>> +{
>> + struct efi_net_obj *netobj = container_of(this, struct efi_net_obj, net);
>> + int ret;
>> + EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
>> +
>> + eth_halt();
>> + eth_set_current();
>> + ret = eth_init();
>> + if (ret < 0) {
>> + eth_halt();
>> + return EFI_EXIT(EFI_DEVICE_ERROR);
>> + }
>> +
>> + netobj->net_mode.state = EFI_NETWORK_INITIALIZED;
>> +
>> + return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
>> + int extended_verification)
>> +{
>> + EFI_ENTRY("%p, %x", this, extended_verification);
>> +
>> + return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
>> +{
>> + EFI_ENTRY("%p", this);
>> +
>> + return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_receive_filters(
>> + struct efi_simple_network *this, u32 enable, u32 disable,
>> + int reset_mcast_filter, ulong mcast_filter_count,
>> + struct efi_mac_address *mcast_filter)
>> +{
>> + EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
>> + reset_mcast_filter, mcast_filter_count, mcast_filter);
>> +
>> + /* XXX Do we care? */
>> +
>> + return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_station_address(
>> + struct efi_simple_network *this, int reset,
>> + struct efi_mac_address *new_mac)
>> +{
>> + EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
>> +
>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
>> + int reset, ulong *stat_size,
>> + void *stat_table)
>> +{
>> + EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
>> +
>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
>> + int ipv6,
>> + struct efi_ip_address *ip,
>> + struct efi_mac_address *mac)
>> +{
>> + EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
>> +
>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
>> + int read_write, ulong offset,
>> + ulong buffer_size, char *buffer)
>> +{
>> + EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
>> + buffer);
>> +
>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
>> + u32 *int_status, void **txbuf)
>> +{
>> + EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
>> +
>> + /* We send packets synchronously, so nothing is outstanding */
>> + if (int_status)
>> + *int_status = 0;
>> + if (txbuf)
>> + *txbuf = new_tx_packet;
>> +
>> + new_tx_packet = NULL;
>> +
>> + return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
>> + ulong header_size, ulong buffer_size, void *buffer,
>> + struct efi_mac_address *src_addr,
>> + struct efi_mac_address *dest_addr, u16 *protocol)
>> +{
>> + EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>> +
>> + if (header_size) {
>> + /* We would need to create the header if header_size != 0 */
>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>> + }
>> +
>> + /*
>> + * Some drivers need to have DMA aligned buffers, so if
>> + * it's misaligned, let's use our own.
>> + */
>> + if ((ulong)buffer & (ARCH_DMA_MINALIGN - 1)) {
>> + void *packet = memalign(ARCH_DMA_MINALIGN, buffer_size);
>> + memcpy(packet, buffer, buffer_size);
>> + net_send_packet(packet, buffer_size);
>> + free(packet);
>> + } else {
>> + net_send_packet(buffer, buffer_size);
>> + }
>> +
>> + new_tx_packet = buffer;
>> +
>> + return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static void efi_net_push(void *pkt, int len)
>> +{
>> + new_rx_packet = true;
>> +}
>> +
>> +static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
>> + ulong *header_size, ulong *buffer_size, void *buffer,
>> + struct efi_mac_address *src_addr,
>> + struct efi_mac_address *dest_addr, u16 *protocol)
>> +{
>> + EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>> +
>> + push_packet = efi_net_push;
>> + /* XXX With device model this reads multiple packets, we only want 1 */
>> + eth_rx();
>> + push_packet = NULL;
>> +
>> + if (!new_rx_packet)
>> + return EFI_EXIT(EFI_NOT_READY);
>> +
>> + if (*buffer_size < net_rx_packet_len) {
>> + /* Packet doesn't fit, try again with bigger buf */
>> + *buffer_size = net_rx_packet_len;
>> + return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
>> + }
>> +
>> + memcpy(buffer, net_rx_packet, net_rx_packet_len);
>> + *buffer_size = net_rx_packet_len;
>> + new_rx_packet = false;
>> +
>> + return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
>> + void **protocol_interface, void *agent_handle,
>> + void *controller_handle, uint32_t attributes)
>> +{
>> + struct efi_simple_network *net = handle;
>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>> +
>> + *protocol_interface = netobj->dp;
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol,
>> + void **protocol_interface, void *agent_handle,
>> + void *controller_handle, uint32_t attributes)
>> +{
>> + struct efi_simple_network *net = handle;
>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>> +
>> + *protocol_interface = &netobj->pxe;
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +void efi_net_set_dhcp_ack(void *pkt, int len)
>> +{
>> + int maxsize = sizeof(*dhcp_ack);
>> +
>> + if (!dhcp_ack)
>> + dhcp_ack = malloc(maxsize);
>> +
>> + memcpy(dhcp_ack, pkt, min(len, maxsize));
>> +}
>> +
>> +/* This gets called from do_bootefi_exec(). */
>> +int efi_net_register(void **handle)
>> +{
>> + struct efi_net_obj *netobj;
>> + struct efi_device_path_file_path dp_net = {
>> + .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
>> + .dp.length = sizeof(dp_net),
>> + .str = { 'N', 'e', 't' },
>> + };
>> + struct efi_device_path_file_path dp_end = {
>> + .dp.type = DEVICE_PATH_TYPE_END,
>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
>> + .dp.length = sizeof(dp_end),
>> + };
>> +
>> + if (!eth_get_dev()) {
>> + /* No eth device active, don't expose any */
>> + return 0;
>> + }
>> +
>> + /* We only expose the "active" eth device, so one is enough */
>> + netobj = calloc(1, sizeof(*netobj));
>> +
>> + /* Fill in object data */
>> + netobj->parent.protocols[0].guid = &efi_net_guid;
>> + netobj->parent.protocols[0].open = efi_return_handle;
>> + netobj->parent.protocols[1].guid = &efi_guid_device_path;
>> + netobj->parent.protocols[1].open = efi_net_open_dp;
>> + netobj->parent.protocols[2].guid = &efi_pxe_guid;
>> + netobj->parent.protocols[2].open = efi_net_open_pxe;
>> + netobj->parent.handle = &netobj->net;
>> + netobj->net.start = efi_net_start;
>> + netobj->net.stop = efi_net_stop;
>> + netobj->net.initialize = efi_net_initialize;
>> + netobj->net.reset = efi_net_reset;
>> + netobj->net.shutdown = efi_net_shutdown;
>> + netobj->net.receive_filters = efi_net_receive_filters;
>> + netobj->net.station_address = efi_net_station_address;
>> + netobj->net.statistics = efi_net_statistics;
>> + netobj->net.mcastiptomac = efi_net_mcastiptomac;
>> + netobj->net.nvdata = efi_net_nvdata;
>> + netobj->net.get_status = efi_net_get_status;
>> + netobj->net.transmit = efi_net_transmit;
>> + netobj->net.receive = efi_net_receive;
>> + netobj->net.mode = &netobj->net_mode;
>> + netobj->net_mode.state = EFI_NETWORK_STARTED;
>> + netobj->dp[0] = dp_net;
>> + netobj->dp[1] = dp_end;
>> + memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
>> + netobj->net_mode.max_packet_size = PKTSIZE;
>
> Why is this statically created? Shouldn't it come from the U-Boot
> ethernet tables dynamically when it is needed?
The driver as is only exposes a single interface for the currently selected network device. My main goal behind this was pxe boot - where you usually load the payload from tftp and continue acting on the same interface later on.
I guess we could create devices for all network devices as well. I remember that I wanted to only expose network if it's really necessary because of resource usage. But I don't remember exactly what resource the peoblem was otoh ;).
Alex
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v3 1/7] efi_loader: Add network access support
2016-05-14 20:34 ` Alexander Graf
@ 2016-05-16 13:24 ` Simon Glass
2016-05-16 18:06 ` Alexander Graf
0 siblings, 1 reply; 30+ messages in thread
From: Simon Glass @ 2016-05-16 13:24 UTC (permalink / raw)
To: u-boot
Hi Alexander,
On 14 May 2016 at 14:34, Alexander Graf <agraf@suse.de> wrote:
>
>
>> Am 14.05.2016 um 21:49 schrieb Simon Glass <sjg@chromium.org>:
>>
>> Hi Alexander,
>>
>>> On 10 May 2016 at 15:25, Alexander Graf <agraf@suse.de> wrote:
>>> We can now successfully boot EFI applications from disk, but users
>>> may want to also run them from a PXE setup.
>>>
>>> This patch implements rudimentary network support, allowing a payload
>>> to send and receive network packets.
>>>
>>> With this patch, I was able to successfully run grub2 with network
>>> access inside of QEMU's -M xlnx-ep108 and on a zcu102 system.
>>>
>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>
>>> ---
>>>
>>> v2 -> v3:
>>>
>>> - Align initialization sequence with net code
>>> - Set device to initialized after init call
>>> - Align tx buffers to DMA alignment (rx gets memcpy'd)
>>> - Add comment about eth_rx()
>>> ---
>>> cmd/bootefi.c | 7 ++
>>> include/efi_api.h | 119 ++++++++++++++++++
>>> include/efi_loader.h | 7 ++
>>> include/net.h | 2 +-
>>> lib/efi_loader/Makefile | 1 +
>>> lib/efi_loader/efi_net.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++
>>> net/bootp.c | 2 +
>>> net/net.c | 4 +-
>>> net/tftp.c | 2 +
>>> 9 files changed, 455 insertions(+), 3 deletions(-)
>>> create mode 100644 lib/efi_loader/efi_net.c
>>>
>>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>>> index 7f552fc..d3a2331 100644
>>> --- a/cmd/bootefi.c
>>> +++ b/cmd/bootefi.c
>>> @@ -197,6 +197,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
>>> #ifdef CONFIG_LCD
>>> efi_gop_register();
>>> #endif
>>> +#ifdef CONFIG_NET
>>> + void *nethandle = loaded_image_info.device_handle;
>>> + efi_net_register(&nethandle);
>>> +
>>> + if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
>>> + loaded_image_info.device_handle = nethandle;
>>> +#endif
>>>
>>> /* Call our payload! */
>>> #ifdef DEBUG_EFI
>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>> index 51d7586..20035d7 100644
>>> --- a/include/efi_api.h
>>> +++ b/include/efi_api.h
>>> @@ -412,4 +412,123 @@ struct efi_gop
>>> struct efi_gop_mode *mode;
>>> };
>>>
>>> +#define EFI_SIMPLE_NETWORK_GUID \
>>> + EFI_GUID(0xa19832b9, 0xac25, 0x11d3, \
>>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>> +
>>> +struct efi_mac_address {
>>> + char mac_addr[32];
>>> +};
>>> +
>>> +struct efi_ip_address {
>>> + u8 ip_addr[16];
>>> +};
>>> +
>>> +enum efi_simple_network_state {
>>> + EFI_NETWORK_STOPPED,
>>> + EFI_NETWORK_STARTED,
>>> + EFI_NETWORK_INITIALIZED,
>>> +};
>>> +
>>> +struct efi_simple_network_mode {
>>> + enum efi_simple_network_state state;
>>> + u32 hwaddr_size;
>>> + u32 media_header_size;
>>> + u32 max_packet_size;
>>> + u32 nvram_size;
>>> + u32 nvram_access_size;
>>> + u32 receive_filter_mask;
>>> + u32 receive_filter_setting;
>>> + u32 max_mcast_filter_count;
>>> + u32 mcast_filter_count;
>>> + struct efi_mac_address mcast_filter[16];
>>> + struct efi_mac_address current_address;
>>> + struct efi_mac_address broadcast_address;
>>> + struct efi_mac_address permanent_address;
>>> + u8 if_type;
>>> + u8 mac_changeable;
>>> + u8 multitx_supported;
>>> + u8 media_present_supported;
>>> + u8 media_present;
>>> +};
>>> +
>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01,
>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02,
>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04,
>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08,
>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10,
>>> +
>>> +struct efi_simple_network
>>> +{
>>> + u64 revision;
>>> + efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
>>> + efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
>>> + efi_status_t (EFIAPI *initialize)(struct efi_simple_network *this,
>>> + ulong extra_rx, ulong extra_tx);
>>> + efi_status_t (EFIAPI *reset)(struct efi_simple_network *this,
>>> + int extended_verification);
>>> + efi_status_t (EFIAPI *shutdown)(struct efi_simple_network *this);
>>> + efi_status_t (EFIAPI *receive_filters)(struct efi_simple_network *this,
>>> + u32 enable, u32 disable, int reset_mcast_filter,
>>> + ulong mcast_filter_count,
>>> + struct efi_mac_address *mcast_filter);
>>> + efi_status_t (EFIAPI *station_address)(struct efi_simple_network *this,
>>> + int reset, struct efi_mac_address *new_mac);
>>> + efi_status_t (EFIAPI *statistics)(struct efi_simple_network *this,
>>> + int reset, ulong *stat_size, void *stat_table);
>>> + efi_status_t (EFIAPI *mcastiptomac)(struct efi_simple_network *this,
>>> + int ipv6, struct efi_ip_address *ip,
>>> + struct efi_mac_address *mac);
>>> + efi_status_t (EFIAPI *nvdata)(struct efi_simple_network *this,
>>> + int read_write, ulong offset, ulong buffer_size,
>>> + char *buffer);
>>> + efi_status_t (EFIAPI *get_status)(struct efi_simple_network *this,
>>> + u32 *int_status, void **txbuf);
>>> + efi_status_t (EFIAPI *transmit)(struct efi_simple_network *this,
>>> + ulong header_size, ulong buffer_size, void *buffer,
>>> + struct efi_mac_address *src_addr,
>>> + struct efi_mac_address *dest_addr, u16 *protocol);
>>> + efi_status_t (EFIAPI *receive)(struct efi_simple_network *this,
>>> + ulong *header_size, ulong *buffer_size, void *buffer,
>>> + struct efi_mac_address *src_addr,
>>> + struct efi_mac_address *dest_addr, u16 *protocol);
>>> + void (EFIAPI *waitforpacket)(void);
>>> + struct efi_simple_network_mode *mode;
>>> +};
>>> +
>>> +#define EFI_PXE_GUID \
>>> + EFI_GUID(0x03c4e603, 0xac28, 0x11d3, \
>>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>> +
>>> +struct efi_pxe_packet {
>>> + u8 packet[1472];
>>> +};
>>> +
>>> +struct efi_pxe_mode
>>> +{
>>> + u8 unused[52];
>>> + struct efi_pxe_packet dhcp_discover;
>>> + struct efi_pxe_packet dhcp_ack;
>>> + struct efi_pxe_packet proxy_offer;
>>> + struct efi_pxe_packet pxe_discover;
>>> + struct efi_pxe_packet pxe_reply;
>>> +};
>>> +
>>> +struct efi_pxe {
>>> + u64 rev;
>>> + void (EFIAPI *start)(void);
>>> + void (EFIAPI *stop)(void);
>>> + void (EFIAPI *dhcp)(void);
>>> + void (EFIAPI *discover)(void);
>>> + void (EFIAPI *mftp)(void);
>>> + void (EFIAPI *udpwrite)(void);
>>> + void (EFIAPI *udpread)(void);
>>> + void (EFIAPI *setipfilter)(void);
>>> + void (EFIAPI *arp)(void);
>>> + void (EFIAPI *setparams)(void);
>>> + void (EFIAPI *setstationip)(void);
>>> + void (EFIAPI *setpackets)(void);
>>> + struct efi_pxe_mode *mode;
>>> +};
>>> +
>>> #endif
>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>> index 88b8149..8005454 100644
>>> --- a/include/efi_loader.h
>>> +++ b/include/efi_loader.h
>>> @@ -91,6 +91,12 @@ extern struct list_head efi_obj_list;
>>> int efi_disk_register(void);
>>> /* Called by bootefi to make GOP (graphical) interface available */
>>> int efi_gop_register(void);
>>> +/* Called by bootefi to make the network interface available */
>>> +int efi_net_register(void **handle);
>>> +
>>> +/* Called by networking code to memorize the dhcp ack package */
>>> +void efi_net_set_dhcp_ack(void *pkt, int len);
>>> +
>>> /*
>>> * Stub implementation for a protocol opener that just returns the handle as
>>> * interface
>>> @@ -157,5 +163,6 @@ static inline void ascii2unicode(u16 *unicode, char *ascii)
>>> static inline void efi_restore_gd(void) { }
>>> static inline void efi_set_bootdev(const char *dev, const char *devnr,
>>> const char *path) { }
>>> +static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
>>>
>>> #endif
>>> diff --git a/include/net.h b/include/net.h
>>> index 05800c4..5ee5929 100644
>>> --- a/include/net.h
>>> +++ b/include/net.h
>>> @@ -269,7 +269,7 @@ int eth_getenv_enetaddr_by_index(const char *base_name, int index,
>>> int eth_init(void); /* Initialize the device */
>>> int eth_send(void *packet, int length); /* Send a packet */
>>>
>>> -#ifdef CONFIG_API
>>> +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
>>> int eth_receive(void *packet, int length); /* Receive a packet*/
>>> extern void (*push_packet)(void *packet, int length);
>>> #endif
>>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>>> index 83e31f6..2a3849e 100644
>>> --- a/lib/efi_loader/Makefile
>>> +++ b/lib/efi_loader/Makefile
>>> @@ -11,3 +11,4 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>> obj-y += efi_memory.o
>>> obj-$(CONFIG_LCD) += efi_gop.o
>>> obj-$(CONFIG_PARTITIONS) += efi_disk.o
>>> +obj-$(CONFIG_NET) += efi_net.o
>>> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
>>> new file mode 100644
>>> index 0000000..a95ff3c
>>> --- /dev/null
>>> +++ b/lib/efi_loader/efi_net.c
>>> @@ -0,0 +1,314 @@
>>> +/*
>>> + * EFI application network access support
>>> + *
>>> + * Copyright (c) 2016 Alexander Graf
>>> + *
>>> + * SPDX-License-Identifier: GPL-2.0+
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <efi_loader.h>
>>> +#include <inttypes.h>
>>> +#include <lcd.h>
>>> +#include <malloc.h>
>>> +
>>> +DECLARE_GLOBAL_DATA_PTR;
>>> +
>>> +static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
>>> +static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
>>> +static struct efi_pxe_packet *dhcp_ack;
>>> +static bool new_rx_packet;
>>> +static void *new_tx_packet;
>>> +
>>> +struct efi_net_obj {
>>> + /* Generic EFI object parent class data */
>>> + struct efi_object parent;
>>> + /* EFI Interface callback struct for network */
>>> + struct efi_simple_network net;
>>> + struct efi_simple_network_mode net_mode;
>>> + /* Device path to the network adapter */
>>> + struct efi_device_path_file_path dp[2];
>>> + /* PXE struct to transmit dhcp data */
>>> + struct efi_pxe pxe;
>>> + struct efi_pxe_mode pxe_mode;
>>> +};
>>> +
>>> +static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
>>> +{
>>> + EFI_ENTRY("%p", this);
>>> +
>>> + return EFI_EXIT(EFI_SUCCESS);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
>>> +{
>>> + EFI_ENTRY("%p", this);
>>> +
>>> + return EFI_EXIT(EFI_SUCCESS);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
>>> + ulong extra_rx, ulong extra_tx)
>>> +{
>>> + struct efi_net_obj *netobj = container_of(this, struct efi_net_obj, net);
>>> + int ret;
>>> + EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
>>> +
>>> + eth_halt();
>>> + eth_set_current();
>>> + ret = eth_init();
>>> + if (ret < 0) {
>>> + eth_halt();
>>> + return EFI_EXIT(EFI_DEVICE_ERROR);
>>> + }
>>> +
>>> + netobj->net_mode.state = EFI_NETWORK_INITIALIZED;
>>> +
>>> + return EFI_EXIT(EFI_SUCCESS);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
>>> + int extended_verification)
>>> +{
>>> + EFI_ENTRY("%p, %x", this, extended_verification);
>>> +
>>> + return EFI_EXIT(EFI_SUCCESS);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
>>> +{
>>> + EFI_ENTRY("%p", this);
>>> +
>>> + return EFI_EXIT(EFI_SUCCESS);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_receive_filters(
>>> + struct efi_simple_network *this, u32 enable, u32 disable,
>>> + int reset_mcast_filter, ulong mcast_filter_count,
>>> + struct efi_mac_address *mcast_filter)
>>> +{
>>> + EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
>>> + reset_mcast_filter, mcast_filter_count, mcast_filter);
>>> +
>>> + /* XXX Do we care? */
>>> +
>>> + return EFI_EXIT(EFI_SUCCESS);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_station_address(
>>> + struct efi_simple_network *this, int reset,
>>> + struct efi_mac_address *new_mac)
>>> +{
>>> + EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
>>> +
>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
>>> + int reset, ulong *stat_size,
>>> + void *stat_table)
>>> +{
>>> + EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
>>> +
>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
>>> + int ipv6,
>>> + struct efi_ip_address *ip,
>>> + struct efi_mac_address *mac)
>>> +{
>>> + EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
>>> +
>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
>>> + int read_write, ulong offset,
>>> + ulong buffer_size, char *buffer)
>>> +{
>>> + EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
>>> + buffer);
>>> +
>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
>>> + u32 *int_status, void **txbuf)
>>> +{
>>> + EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
>>> +
>>> + /* We send packets synchronously, so nothing is outstanding */
>>> + if (int_status)
>>> + *int_status = 0;
>>> + if (txbuf)
>>> + *txbuf = new_tx_packet;
>>> +
>>> + new_tx_packet = NULL;
>>> +
>>> + return EFI_EXIT(EFI_SUCCESS);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
>>> + ulong header_size, ulong buffer_size, void *buffer,
>>> + struct efi_mac_address *src_addr,
>>> + struct efi_mac_address *dest_addr, u16 *protocol)
>>> +{
>>> + EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
>>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>>> +
>>> + if (header_size) {
>>> + /* We would need to create the header if header_size != 0 */
>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>> + }
>>> +
>>> + /*
>>> + * Some drivers need to have DMA aligned buffers, so if
>>> + * it's misaligned, let's use our own.
>>> + */
>>> + if ((ulong)buffer & (ARCH_DMA_MINALIGN - 1)) {
>>> + void *packet = memalign(ARCH_DMA_MINALIGN, buffer_size);
>>> + memcpy(packet, buffer, buffer_size);
>>> + net_send_packet(packet, buffer_size);
>>> + free(packet);
>>> + } else {
>>> + net_send_packet(buffer, buffer_size);
>>> + }
>>> +
>>> + new_tx_packet = buffer;
>>> +
>>> + return EFI_EXIT(EFI_SUCCESS);
>>> +}
>>> +
>>> +static void efi_net_push(void *pkt, int len)
>>> +{
>>> + new_rx_packet = true;
>>> +}
>>> +
>>> +static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
>>> + ulong *header_size, ulong *buffer_size, void *buffer,
>>> + struct efi_mac_address *src_addr,
>>> + struct efi_mac_address *dest_addr, u16 *protocol)
>>> +{
>>> + EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
>>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>>> +
>>> + push_packet = efi_net_push;
>>> + /* XXX With device model this reads multiple packets, we only want 1 */
>>> + eth_rx();
>>> + push_packet = NULL;
>>> +
>>> + if (!new_rx_packet)
>>> + return EFI_EXIT(EFI_NOT_READY);
>>> +
>>> + if (*buffer_size < net_rx_packet_len) {
>>> + /* Packet doesn't fit, try again with bigger buf */
>>> + *buffer_size = net_rx_packet_len;
>>> + return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
>>> + }
>>> +
>>> + memcpy(buffer, net_rx_packet, net_rx_packet_len);
>>> + *buffer_size = net_rx_packet_len;
>>> + new_rx_packet = false;
>>> +
>>> + return EFI_EXIT(EFI_SUCCESS);
>>> +}
>>> +
>>> +static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
>>> + void **protocol_interface, void *agent_handle,
>>> + void *controller_handle, uint32_t attributes)
>>> +{
>>> + struct efi_simple_network *net = handle;
>>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>>> +
>>> + *protocol_interface = netobj->dp;
>>> +
>>> + return EFI_SUCCESS;
>>> +}
>>> +
>>> +static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol,
>>> + void **protocol_interface, void *agent_handle,
>>> + void *controller_handle, uint32_t attributes)
>>> +{
>>> + struct efi_simple_network *net = handle;
>>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>>> +
>>> + *protocol_interface = &netobj->pxe;
>>> +
>>> + return EFI_SUCCESS;
>>> +}
>>> +
>>> +void efi_net_set_dhcp_ack(void *pkt, int len)
>>> +{
>>> + int maxsize = sizeof(*dhcp_ack);
>>> +
>>> + if (!dhcp_ack)
>>> + dhcp_ack = malloc(maxsize);
>>> +
>>> + memcpy(dhcp_ack, pkt, min(len, maxsize));
>>> +}
>>> +
>>> +/* This gets called from do_bootefi_exec(). */
>>> +int efi_net_register(void **handle)
>>> +{
>>> + struct efi_net_obj *netobj;
>>> + struct efi_device_path_file_path dp_net = {
>>> + .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
>>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
>>> + .dp.length = sizeof(dp_net),
>>> + .str = { 'N', 'e', 't' },
>>> + };
>>> + struct efi_device_path_file_path dp_end = {
>>> + .dp.type = DEVICE_PATH_TYPE_END,
>>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
>>> + .dp.length = sizeof(dp_end),
>>> + };
>>> +
>>> + if (!eth_get_dev()) {
>>> + /* No eth device active, don't expose any */
>>> + return 0;
>>> + }
>>> +
>>> + /* We only expose the "active" eth device, so one is enough */
>>> + netobj = calloc(1, sizeof(*netobj));
>>> +
>>> + /* Fill in object data */
>>> + netobj->parent.protocols[0].guid = &efi_net_guid;
>>> + netobj->parent.protocols[0].open = efi_return_handle;
>>> + netobj->parent.protocols[1].guid = &efi_guid_device_path;
>>> + netobj->parent.protocols[1].open = efi_net_open_dp;
>>> + netobj->parent.protocols[2].guid = &efi_pxe_guid;
>>> + netobj->parent.protocols[2].open = efi_net_open_pxe;
>>> + netobj->parent.handle = &netobj->net;
>>> + netobj->net.start = efi_net_start;
>>> + netobj->net.stop = efi_net_stop;
>>> + netobj->net.initialize = efi_net_initialize;
>>> + netobj->net.reset = efi_net_reset;
>>> + netobj->net.shutdown = efi_net_shutdown;
>>> + netobj->net.receive_filters = efi_net_receive_filters;
>>> + netobj->net.station_address = efi_net_station_address;
>>> + netobj->net.statistics = efi_net_statistics;
>>> + netobj->net.mcastiptomac = efi_net_mcastiptomac;
>>> + netobj->net.nvdata = efi_net_nvdata;
>>> + netobj->net.get_status = efi_net_get_status;
>>> + netobj->net.transmit = efi_net_transmit;
>>> + netobj->net.receive = efi_net_receive;
>>> + netobj->net.mode = &netobj->net_mode;
>>> + netobj->net_mode.state = EFI_NETWORK_STARTED;
>>> + netobj->dp[0] = dp_net;
>>> + netobj->dp[1] = dp_end;
>>> + memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
>>> + netobj->net_mode.max_packet_size = PKTSIZE;
>>
>> Why is this statically created? Shouldn't it come from the U-Boot
>> ethernet tables dynamically when it is needed?
>
> The driver as is only exposes a single interface for the currently selected network device. My main goal behind this was pxe boot - where you usually load the payload from tftp and continue acting on the same interface later on.
>
> I guess we could create devices for all network devices as well. I remember that I wanted to only expose network if it's really necessary because of resource usage. But I don't remember exactly what resource the peoblem was otoh ;).
I think in general (given that you are writing this code and this is
the best opportunity to get the design right) that things like this
should look up U-Boot tables rather than creating their own. So a
model where the device is scanned as needed seems better. Then if we
want to change the constraints later, e.g. devices appear that were
not previously present, then we can deal with that.
I understand with block devices your point that there is no single
table of block devices. However, this support will be applied soon
(see u-boot-dm/master), even without driver model. I think we should
fix these things rather than work around them, as the code will be
more maintainable that way.
In this case I wonder if we should have an EFI device uclass, and
allow devices to have this as a child? It would allow for easy
enumeration and avoid another system-specific device table (something
that driver model is trying to reduce).
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v3 1/7] efi_loader: Add network access support
2016-05-16 13:24 ` Simon Glass
@ 2016-05-16 18:06 ` Alexander Graf
2016-05-18 17:21 ` Simon Glass
0 siblings, 1 reply; 30+ messages in thread
From: Alexander Graf @ 2016-05-16 18:06 UTC (permalink / raw)
To: u-boot
On 16.05.16 15:24, Simon Glass wrote:
> Hi Alexander,
>
> On 14 May 2016 at 14:34, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>>> Am 14.05.2016 um 21:49 schrieb Simon Glass <sjg@chromium.org>:
>>>
>>> Hi Alexander,
>>>
>>>> On 10 May 2016 at 15:25, Alexander Graf <agraf@suse.de> wrote:
>>>> We can now successfully boot EFI applications from disk, but users
>>>> may want to also run them from a PXE setup.
>>>>
>>>> This patch implements rudimentary network support, allowing a payload
>>>> to send and receive network packets.
>>>>
>>>> With this patch, I was able to successfully run grub2 with network
>>>> access inside of QEMU's -M xlnx-ep108 and on a zcu102 system.
>>>>
>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>>
>>>> ---
>>>>
>>>> v2 -> v3:
>>>>
>>>> - Align initialization sequence with net code
>>>> - Set device to initialized after init call
>>>> - Align tx buffers to DMA alignment (rx gets memcpy'd)
>>>> - Add comment about eth_rx()
>>>> ---
>>>> cmd/bootefi.c | 7 ++
>>>> include/efi_api.h | 119 ++++++++++++++++++
>>>> include/efi_loader.h | 7 ++
>>>> include/net.h | 2 +-
>>>> lib/efi_loader/Makefile | 1 +
>>>> lib/efi_loader/efi_net.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++
>>>> net/bootp.c | 2 +
>>>> net/net.c | 4 +-
>>>> net/tftp.c | 2 +
>>>> 9 files changed, 455 insertions(+), 3 deletions(-)
>>>> create mode 100644 lib/efi_loader/efi_net.c
>>>>
>>>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>>>> index 7f552fc..d3a2331 100644
>>>> --- a/cmd/bootefi.c
>>>> +++ b/cmd/bootefi.c
>>>> @@ -197,6 +197,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
>>>> #ifdef CONFIG_LCD
>>>> efi_gop_register();
>>>> #endif
>>>> +#ifdef CONFIG_NET
>>>> + void *nethandle = loaded_image_info.device_handle;
>>>> + efi_net_register(&nethandle);
>>>> +
>>>> + if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
>>>> + loaded_image_info.device_handle = nethandle;
>>>> +#endif
>>>>
>>>> /* Call our payload! */
>>>> #ifdef DEBUG_EFI
>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>> index 51d7586..20035d7 100644
>>>> --- a/include/efi_api.h
>>>> +++ b/include/efi_api.h
>>>> @@ -412,4 +412,123 @@ struct efi_gop
>>>> struct efi_gop_mode *mode;
>>>> };
>>>>
>>>> +#define EFI_SIMPLE_NETWORK_GUID \
>>>> + EFI_GUID(0xa19832b9, 0xac25, 0x11d3, \
>>>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>>> +
>>>> +struct efi_mac_address {
>>>> + char mac_addr[32];
>>>> +};
>>>> +
>>>> +struct efi_ip_address {
>>>> + u8 ip_addr[16];
>>>> +};
>>>> +
>>>> +enum efi_simple_network_state {
>>>> + EFI_NETWORK_STOPPED,
>>>> + EFI_NETWORK_STARTED,
>>>> + EFI_NETWORK_INITIALIZED,
>>>> +};
>>>> +
>>>> +struct efi_simple_network_mode {
>>>> + enum efi_simple_network_state state;
>>>> + u32 hwaddr_size;
>>>> + u32 media_header_size;
>>>> + u32 max_packet_size;
>>>> + u32 nvram_size;
>>>> + u32 nvram_access_size;
>>>> + u32 receive_filter_mask;
>>>> + u32 receive_filter_setting;
>>>> + u32 max_mcast_filter_count;
>>>> + u32 mcast_filter_count;
>>>> + struct efi_mac_address mcast_filter[16];
>>>> + struct efi_mac_address current_address;
>>>> + struct efi_mac_address broadcast_address;
>>>> + struct efi_mac_address permanent_address;
>>>> + u8 if_type;
>>>> + u8 mac_changeable;
>>>> + u8 multitx_supported;
>>>> + u8 media_present_supported;
>>>> + u8 media_present;
>>>> +};
>>>> +
>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01,
>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02,
>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04,
>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08,
>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10,
>>>> +
>>>> +struct efi_simple_network
>>>> +{
>>>> + u64 revision;
>>>> + efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
>>>> + efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
>>>> + efi_status_t (EFIAPI *initialize)(struct efi_simple_network *this,
>>>> + ulong extra_rx, ulong extra_tx);
>>>> + efi_status_t (EFIAPI *reset)(struct efi_simple_network *this,
>>>> + int extended_verification);
>>>> + efi_status_t (EFIAPI *shutdown)(struct efi_simple_network *this);
>>>> + efi_status_t (EFIAPI *receive_filters)(struct efi_simple_network *this,
>>>> + u32 enable, u32 disable, int reset_mcast_filter,
>>>> + ulong mcast_filter_count,
>>>> + struct efi_mac_address *mcast_filter);
>>>> + efi_status_t (EFIAPI *station_address)(struct efi_simple_network *this,
>>>> + int reset, struct efi_mac_address *new_mac);
>>>> + efi_status_t (EFIAPI *statistics)(struct efi_simple_network *this,
>>>> + int reset, ulong *stat_size, void *stat_table);
>>>> + efi_status_t (EFIAPI *mcastiptomac)(struct efi_simple_network *this,
>>>> + int ipv6, struct efi_ip_address *ip,
>>>> + struct efi_mac_address *mac);
>>>> + efi_status_t (EFIAPI *nvdata)(struct efi_simple_network *this,
>>>> + int read_write, ulong offset, ulong buffer_size,
>>>> + char *buffer);
>>>> + efi_status_t (EFIAPI *get_status)(struct efi_simple_network *this,
>>>> + u32 *int_status, void **txbuf);
>>>> + efi_status_t (EFIAPI *transmit)(struct efi_simple_network *this,
>>>> + ulong header_size, ulong buffer_size, void *buffer,
>>>> + struct efi_mac_address *src_addr,
>>>> + struct efi_mac_address *dest_addr, u16 *protocol);
>>>> + efi_status_t (EFIAPI *receive)(struct efi_simple_network *this,
>>>> + ulong *header_size, ulong *buffer_size, void *buffer,
>>>> + struct efi_mac_address *src_addr,
>>>> + struct efi_mac_address *dest_addr, u16 *protocol);
>>>> + void (EFIAPI *waitforpacket)(void);
>>>> + struct efi_simple_network_mode *mode;
>>>> +};
>>>> +
>>>> +#define EFI_PXE_GUID \
>>>> + EFI_GUID(0x03c4e603, 0xac28, 0x11d3, \
>>>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>>> +
>>>> +struct efi_pxe_packet {
>>>> + u8 packet[1472];
>>>> +};
>>>> +
>>>> +struct efi_pxe_mode
>>>> +{
>>>> + u8 unused[52];
>>>> + struct efi_pxe_packet dhcp_discover;
>>>> + struct efi_pxe_packet dhcp_ack;
>>>> + struct efi_pxe_packet proxy_offer;
>>>> + struct efi_pxe_packet pxe_discover;
>>>> + struct efi_pxe_packet pxe_reply;
>>>> +};
>>>> +
>>>> +struct efi_pxe {
>>>> + u64 rev;
>>>> + void (EFIAPI *start)(void);
>>>> + void (EFIAPI *stop)(void);
>>>> + void (EFIAPI *dhcp)(void);
>>>> + void (EFIAPI *discover)(void);
>>>> + void (EFIAPI *mftp)(void);
>>>> + void (EFIAPI *udpwrite)(void);
>>>> + void (EFIAPI *udpread)(void);
>>>> + void (EFIAPI *setipfilter)(void);
>>>> + void (EFIAPI *arp)(void);
>>>> + void (EFIAPI *setparams)(void);
>>>> + void (EFIAPI *setstationip)(void);
>>>> + void (EFIAPI *setpackets)(void);
>>>> + struct efi_pxe_mode *mode;
>>>> +};
>>>> +
>>>> #endif
>>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>>> index 88b8149..8005454 100644
>>>> --- a/include/efi_loader.h
>>>> +++ b/include/efi_loader.h
>>>> @@ -91,6 +91,12 @@ extern struct list_head efi_obj_list;
>>>> int efi_disk_register(void);
>>>> /* Called by bootefi to make GOP (graphical) interface available */
>>>> int efi_gop_register(void);
>>>> +/* Called by bootefi to make the network interface available */
>>>> +int efi_net_register(void **handle);
>>>> +
>>>> +/* Called by networking code to memorize the dhcp ack package */
>>>> +void efi_net_set_dhcp_ack(void *pkt, int len);
>>>> +
>>>> /*
>>>> * Stub implementation for a protocol opener that just returns the handle as
>>>> * interface
>>>> @@ -157,5 +163,6 @@ static inline void ascii2unicode(u16 *unicode, char *ascii)
>>>> static inline void efi_restore_gd(void) { }
>>>> static inline void efi_set_bootdev(const char *dev, const char *devnr,
>>>> const char *path) { }
>>>> +static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
>>>>
>>>> #endif
>>>> diff --git a/include/net.h b/include/net.h
>>>> index 05800c4..5ee5929 100644
>>>> --- a/include/net.h
>>>> +++ b/include/net.h
>>>> @@ -269,7 +269,7 @@ int eth_getenv_enetaddr_by_index(const char *base_name, int index,
>>>> int eth_init(void); /* Initialize the device */
>>>> int eth_send(void *packet, int length); /* Send a packet */
>>>>
>>>> -#ifdef CONFIG_API
>>>> +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
>>>> int eth_receive(void *packet, int length); /* Receive a packet*/
>>>> extern void (*push_packet)(void *packet, int length);
>>>> #endif
>>>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>>>> index 83e31f6..2a3849e 100644
>>>> --- a/lib/efi_loader/Makefile
>>>> +++ b/lib/efi_loader/Makefile
>>>> @@ -11,3 +11,4 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>>> obj-y += efi_memory.o
>>>> obj-$(CONFIG_LCD) += efi_gop.o
>>>> obj-$(CONFIG_PARTITIONS) += efi_disk.o
>>>> +obj-$(CONFIG_NET) += efi_net.o
>>>> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
>>>> new file mode 100644
>>>> index 0000000..a95ff3c
>>>> --- /dev/null
>>>> +++ b/lib/efi_loader/efi_net.c
>>>> @@ -0,0 +1,314 @@
>>>> +/*
>>>> + * EFI application network access support
>>>> + *
>>>> + * Copyright (c) 2016 Alexander Graf
>>>> + *
>>>> + * SPDX-License-Identifier: GPL-2.0+
>>>> + */
>>>> +
>>>> +#include <common.h>
>>>> +#include <efi_loader.h>
>>>> +#include <inttypes.h>
>>>> +#include <lcd.h>
>>>> +#include <malloc.h>
>>>> +
>>>> +DECLARE_GLOBAL_DATA_PTR;
>>>> +
>>>> +static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
>>>> +static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
>>>> +static struct efi_pxe_packet *dhcp_ack;
>>>> +static bool new_rx_packet;
>>>> +static void *new_tx_packet;
>>>> +
>>>> +struct efi_net_obj {
>>>> + /* Generic EFI object parent class data */
>>>> + struct efi_object parent;
>>>> + /* EFI Interface callback struct for network */
>>>> + struct efi_simple_network net;
>>>> + struct efi_simple_network_mode net_mode;
>>>> + /* Device path to the network adapter */
>>>> + struct efi_device_path_file_path dp[2];
>>>> + /* PXE struct to transmit dhcp data */
>>>> + struct efi_pxe pxe;
>>>> + struct efi_pxe_mode pxe_mode;
>>>> +};
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
>>>> +{
>>>> + EFI_ENTRY("%p", this);
>>>> +
>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
>>>> +{
>>>> + EFI_ENTRY("%p", this);
>>>> +
>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
>>>> + ulong extra_rx, ulong extra_tx)
>>>> +{
>>>> + struct efi_net_obj *netobj = container_of(this, struct efi_net_obj, net);
>>>> + int ret;
>>>> + EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
>>>> +
>>>> + eth_halt();
>>>> + eth_set_current();
>>>> + ret = eth_init();
>>>> + if (ret < 0) {
>>>> + eth_halt();
>>>> + return EFI_EXIT(EFI_DEVICE_ERROR);
>>>> + }
>>>> +
>>>> + netobj->net_mode.state = EFI_NETWORK_INITIALIZED;
>>>> +
>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
>>>> + int extended_verification)
>>>> +{
>>>> + EFI_ENTRY("%p, %x", this, extended_verification);
>>>> +
>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
>>>> +{
>>>> + EFI_ENTRY("%p", this);
>>>> +
>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_receive_filters(
>>>> + struct efi_simple_network *this, u32 enable, u32 disable,
>>>> + int reset_mcast_filter, ulong mcast_filter_count,
>>>> + struct efi_mac_address *mcast_filter)
>>>> +{
>>>> + EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
>>>> + reset_mcast_filter, mcast_filter_count, mcast_filter);
>>>> +
>>>> + /* XXX Do we care? */
>>>> +
>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_station_address(
>>>> + struct efi_simple_network *this, int reset,
>>>> + struct efi_mac_address *new_mac)
>>>> +{
>>>> + EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
>>>> +
>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
>>>> + int reset, ulong *stat_size,
>>>> + void *stat_table)
>>>> +{
>>>> + EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
>>>> +
>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
>>>> + int ipv6,
>>>> + struct efi_ip_address *ip,
>>>> + struct efi_mac_address *mac)
>>>> +{
>>>> + EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
>>>> +
>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
>>>> + int read_write, ulong offset,
>>>> + ulong buffer_size, char *buffer)
>>>> +{
>>>> + EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
>>>> + buffer);
>>>> +
>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
>>>> + u32 *int_status, void **txbuf)
>>>> +{
>>>> + EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
>>>> +
>>>> + /* We send packets synchronously, so nothing is outstanding */
>>>> + if (int_status)
>>>> + *int_status = 0;
>>>> + if (txbuf)
>>>> + *txbuf = new_tx_packet;
>>>> +
>>>> + new_tx_packet = NULL;
>>>> +
>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
>>>> + ulong header_size, ulong buffer_size, void *buffer,
>>>> + struct efi_mac_address *src_addr,
>>>> + struct efi_mac_address *dest_addr, u16 *protocol)
>>>> +{
>>>> + EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
>>>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>>>> +
>>>> + if (header_size) {
>>>> + /* We would need to create the header if header_size != 0 */
>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>> + }
>>>> +
>>>> + /*
>>>> + * Some drivers need to have DMA aligned buffers, so if
>>>> + * it's misaligned, let's use our own.
>>>> + */
>>>> + if ((ulong)buffer & (ARCH_DMA_MINALIGN - 1)) {
>>>> + void *packet = memalign(ARCH_DMA_MINALIGN, buffer_size);
>>>> + memcpy(packet, buffer, buffer_size);
>>>> + net_send_packet(packet, buffer_size);
>>>> + free(packet);
>>>> + } else {
>>>> + net_send_packet(buffer, buffer_size);
>>>> + }
>>>> +
>>>> + new_tx_packet = buffer;
>>>> +
>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>> +}
>>>> +
>>>> +static void efi_net_push(void *pkt, int len)
>>>> +{
>>>> + new_rx_packet = true;
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
>>>> + ulong *header_size, ulong *buffer_size, void *buffer,
>>>> + struct efi_mac_address *src_addr,
>>>> + struct efi_mac_address *dest_addr, u16 *protocol)
>>>> +{
>>>> + EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
>>>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>>>> +
>>>> + push_packet = efi_net_push;
>>>> + /* XXX With device model this reads multiple packets, we only want 1 */
>>>> + eth_rx();
>>>> + push_packet = NULL;
>>>> +
>>>> + if (!new_rx_packet)
>>>> + return EFI_EXIT(EFI_NOT_READY);
>>>> +
>>>> + if (*buffer_size < net_rx_packet_len) {
>>>> + /* Packet doesn't fit, try again with bigger buf */
>>>> + *buffer_size = net_rx_packet_len;
>>>> + return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
>>>> + }
>>>> +
>>>> + memcpy(buffer, net_rx_packet, net_rx_packet_len);
>>>> + *buffer_size = net_rx_packet_len;
>>>> + new_rx_packet = false;
>>>> +
>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>> +}
>>>> +
>>>> +static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
>>>> + void **protocol_interface, void *agent_handle,
>>>> + void *controller_handle, uint32_t attributes)
>>>> +{
>>>> + struct efi_simple_network *net = handle;
>>>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>>>> +
>>>> + *protocol_interface = netobj->dp;
>>>> +
>>>> + return EFI_SUCCESS;
>>>> +}
>>>> +
>>>> +static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol,
>>>> + void **protocol_interface, void *agent_handle,
>>>> + void *controller_handle, uint32_t attributes)
>>>> +{
>>>> + struct efi_simple_network *net = handle;
>>>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>>>> +
>>>> + *protocol_interface = &netobj->pxe;
>>>> +
>>>> + return EFI_SUCCESS;
>>>> +}
>>>> +
>>>> +void efi_net_set_dhcp_ack(void *pkt, int len)
>>>> +{
>>>> + int maxsize = sizeof(*dhcp_ack);
>>>> +
>>>> + if (!dhcp_ack)
>>>> + dhcp_ack = malloc(maxsize);
>>>> +
>>>> + memcpy(dhcp_ack, pkt, min(len, maxsize));
>>>> +}
>>>> +
>>>> +/* This gets called from do_bootefi_exec(). */
>>>> +int efi_net_register(void **handle)
>>>> +{
>>>> + struct efi_net_obj *netobj;
>>>> + struct efi_device_path_file_path dp_net = {
>>>> + .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
>>>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
>>>> + .dp.length = sizeof(dp_net),
>>>> + .str = { 'N', 'e', 't' },
>>>> + };
>>>> + struct efi_device_path_file_path dp_end = {
>>>> + .dp.type = DEVICE_PATH_TYPE_END,
>>>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
>>>> + .dp.length = sizeof(dp_end),
>>>> + };
>>>> +
>>>> + if (!eth_get_dev()) {
>>>> + /* No eth device active, don't expose any */
>>>> + return 0;
>>>> + }
>>>> +
>>>> + /* We only expose the "active" eth device, so one is enough */
>>>> + netobj = calloc(1, sizeof(*netobj));
>>>> +
>>>> + /* Fill in object data */
>>>> + netobj->parent.protocols[0].guid = &efi_net_guid;
>>>> + netobj->parent.protocols[0].open = efi_return_handle;
>>>> + netobj->parent.protocols[1].guid = &efi_guid_device_path;
>>>> + netobj->parent.protocols[1].open = efi_net_open_dp;
>>>> + netobj->parent.protocols[2].guid = &efi_pxe_guid;
>>>> + netobj->parent.protocols[2].open = efi_net_open_pxe;
>>>> + netobj->parent.handle = &netobj->net;
>>>> + netobj->net.start = efi_net_start;
>>>> + netobj->net.stop = efi_net_stop;
>>>> + netobj->net.initialize = efi_net_initialize;
>>>> + netobj->net.reset = efi_net_reset;
>>>> + netobj->net.shutdown = efi_net_shutdown;
>>>> + netobj->net.receive_filters = efi_net_receive_filters;
>>>> + netobj->net.station_address = efi_net_station_address;
>>>> + netobj->net.statistics = efi_net_statistics;
>>>> + netobj->net.mcastiptomac = efi_net_mcastiptomac;
>>>> + netobj->net.nvdata = efi_net_nvdata;
>>>> + netobj->net.get_status = efi_net_get_status;
>>>> + netobj->net.transmit = efi_net_transmit;
>>>> + netobj->net.receive = efi_net_receive;
>>>> + netobj->net.mode = &netobj->net_mode;
>>>> + netobj->net_mode.state = EFI_NETWORK_STARTED;
>>>> + netobj->dp[0] = dp_net;
>>>> + netobj->dp[1] = dp_end;
>>>> + memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
>>>> + netobj->net_mode.max_packet_size = PKTSIZE;
>>>
>>> Why is this statically created? Shouldn't it come from the U-Boot
>>> ethernet tables dynamically when it is needed?
>>
>> The driver as is only exposes a single interface for the currently selected network device. My main goal behind this was pxe boot - where you usually load the payload from tftp and continue acting on the same interface later on.
>>
>> I guess we could create devices for all network devices as well. I remember that I wanted to only expose network if it's really necessary because of resource usage. But I don't remember exactly what resource the peoblem was otoh ;).
>
> I think in general (given that you are writing this code and this is
> the best opportunity to get the design right) that things like this
> should look up U-Boot tables rather than creating their own. So a
> model where the device is scanned as needed seems better. Then if we
> want to change the constraints later, e.g. devices appear that were
> not previously present, then we can deal with that.
>
> I understand with block devices your point that there is no single
> table of block devices. However, this support will be applied soon
> (see u-boot-dm/master), even without driver model. I think we should
> fix these things rather than work around them, as the code will be
> more maintainable that way.
I agree wholeheartedly :). The beauty of "proper" open source code is
that you can actually modify the guts of it to make the code easier at
the end of the day.
> In this case I wonder if we should have an EFI device uclass, and
> allow devices to have this as a child? It would allow for easy
> enumeration and avoid another system-specific device table (something
> that driver model is trying to reduce).
I'm not 100% sure the EFI driver exposure is actually a child-parent
relationship with the respective driver model objects. In Java speech
it's more of an "interface" definition than a subclass.
But that said, I think that it may still make sense to move it into the
respective driver cores and just have the EFI structs part of the block
device structs.
However I don't consider it as very high priority at the moment.
Functionally nothing should change from a payload point of view and the
current code allows us to iron out bugs and have non-believers gain
faith in the whole uEFI story without breaking non-uEFI code paths ;).
And all of the actual interface code shouldn't change with a move into
device objects.
So how about we start to tackle this once the non-DM code is gone? That
should simplify things for everyone.
Alex
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v3 1/7] efi_loader: Add network access support
2016-05-16 18:06 ` Alexander Graf
@ 2016-05-18 17:21 ` Simon Glass
2016-05-19 16:18 ` Alexander Graf
0 siblings, 1 reply; 30+ messages in thread
From: Simon Glass @ 2016-05-18 17:21 UTC (permalink / raw)
To: u-boot
+Tom
Hi Alex,
On 16 May 2016 at 12:06, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 16.05.16 15:24, Simon Glass wrote:
>> Hi Alexander,
>>
>> On 14 May 2016 at 14:34, Alexander Graf <agraf@suse.de> wrote:
>>>
>>>
>>>> Am 14.05.2016 um 21:49 schrieb Simon Glass <sjg@chromium.org>:
>>>>
>>>> Hi Alexander,
>>>>
>>>>> On 10 May 2016 at 15:25, Alexander Graf <agraf@suse.de> wrote:
>>>>> We can now successfully boot EFI applications from disk, but users
>>>>> may want to also run them from a PXE setup.
>>>>>
>>>>> This patch implements rudimentary network support, allowing a payload
>>>>> to send and receive network packets.
>>>>>
>>>>> With this patch, I was able to successfully run grub2 with network
>>>>> access inside of QEMU's -M xlnx-ep108 and on a zcu102 system.
>>>>>
>>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>>>
>>>>> ---
>>>>>
>>>>> v2 -> v3:
>>>>>
>>>>> - Align initialization sequence with net code
>>>>> - Set device to initialized after init call
>>>>> - Align tx buffers to DMA alignment (rx gets memcpy'd)
>>>>> - Add comment about eth_rx()
>>>>> ---
>>>>> cmd/bootefi.c | 7 ++
>>>>> include/efi_api.h | 119 ++++++++++++++++++
>>>>> include/efi_loader.h | 7 ++
>>>>> include/net.h | 2 +-
>>>>> lib/efi_loader/Makefile | 1 +
>>>>> lib/efi_loader/efi_net.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>> net/bootp.c | 2 +
>>>>> net/net.c | 4 +-
>>>>> net/tftp.c | 2 +
>>>>> 9 files changed, 455 insertions(+), 3 deletions(-)
>>>>> create mode 100644 lib/efi_loader/efi_net.c
>>>>>
>>>>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>>>>> index 7f552fc..d3a2331 100644
>>>>> --- a/cmd/bootefi.c
>>>>> +++ b/cmd/bootefi.c
>>>>> @@ -197,6 +197,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
>>>>> #ifdef CONFIG_LCD
>>>>> efi_gop_register();
>>>>> #endif
>>>>> +#ifdef CONFIG_NET
>>>>> + void *nethandle = loaded_image_info.device_handle;
>>>>> + efi_net_register(&nethandle);
>>>>> +
>>>>> + if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
>>>>> + loaded_image_info.device_handle = nethandle;
>>>>> +#endif
>>>>>
>>>>> /* Call our payload! */
>>>>> #ifdef DEBUG_EFI
>>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>>> index 51d7586..20035d7 100644
>>>>> --- a/include/efi_api.h
>>>>> +++ b/include/efi_api.h
>>>>> @@ -412,4 +412,123 @@ struct efi_gop
>>>>> struct efi_gop_mode *mode;
>>>>> };
>>>>>
>>>>> +#define EFI_SIMPLE_NETWORK_GUID \
>>>>> + EFI_GUID(0xa19832b9, 0xac25, 0x11d3, \
>>>>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>>>> +
>>>>> +struct efi_mac_address {
>>>>> + char mac_addr[32];
>>>>> +};
>>>>> +
>>>>> +struct efi_ip_address {
>>>>> + u8 ip_addr[16];
>>>>> +};
>>>>> +
>>>>> +enum efi_simple_network_state {
>>>>> + EFI_NETWORK_STOPPED,
>>>>> + EFI_NETWORK_STARTED,
>>>>> + EFI_NETWORK_INITIALIZED,
>>>>> +};
>>>>> +
>>>>> +struct efi_simple_network_mode {
>>>>> + enum efi_simple_network_state state;
>>>>> + u32 hwaddr_size;
>>>>> + u32 media_header_size;
>>>>> + u32 max_packet_size;
>>>>> + u32 nvram_size;
>>>>> + u32 nvram_access_size;
>>>>> + u32 receive_filter_mask;
>>>>> + u32 receive_filter_setting;
>>>>> + u32 max_mcast_filter_count;
>>>>> + u32 mcast_filter_count;
>>>>> + struct efi_mac_address mcast_filter[16];
>>>>> + struct efi_mac_address current_address;
>>>>> + struct efi_mac_address broadcast_address;
>>>>> + struct efi_mac_address permanent_address;
>>>>> + u8 if_type;
>>>>> + u8 mac_changeable;
>>>>> + u8 multitx_supported;
>>>>> + u8 media_present_supported;
>>>>> + u8 media_present;
>>>>> +};
>>>>> +
>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01,
>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02,
>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04,
>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08,
>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10,
>>>>> +
>>>>> +struct efi_simple_network
>>>>> +{
>>>>> + u64 revision;
>>>>> + efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
>>>>> + efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
>>>>> + efi_status_t (EFIAPI *initialize)(struct efi_simple_network *this,
>>>>> + ulong extra_rx, ulong extra_tx);
>>>>> + efi_status_t (EFIAPI *reset)(struct efi_simple_network *this,
>>>>> + int extended_verification);
>>>>> + efi_status_t (EFIAPI *shutdown)(struct efi_simple_network *this);
>>>>> + efi_status_t (EFIAPI *receive_filters)(struct efi_simple_network *this,
>>>>> + u32 enable, u32 disable, int reset_mcast_filter,
>>>>> + ulong mcast_filter_count,
>>>>> + struct efi_mac_address *mcast_filter);
>>>>> + efi_status_t (EFIAPI *station_address)(struct efi_simple_network *this,
>>>>> + int reset, struct efi_mac_address *new_mac);
>>>>> + efi_status_t (EFIAPI *statistics)(struct efi_simple_network *this,
>>>>> + int reset, ulong *stat_size, void *stat_table);
>>>>> + efi_status_t (EFIAPI *mcastiptomac)(struct efi_simple_network *this,
>>>>> + int ipv6, struct efi_ip_address *ip,
>>>>> + struct efi_mac_address *mac);
>>>>> + efi_status_t (EFIAPI *nvdata)(struct efi_simple_network *this,
>>>>> + int read_write, ulong offset, ulong buffer_size,
>>>>> + char *buffer);
>>>>> + efi_status_t (EFIAPI *get_status)(struct efi_simple_network *this,
>>>>> + u32 *int_status, void **txbuf);
>>>>> + efi_status_t (EFIAPI *transmit)(struct efi_simple_network *this,
>>>>> + ulong header_size, ulong buffer_size, void *buffer,
>>>>> + struct efi_mac_address *src_addr,
>>>>> + struct efi_mac_address *dest_addr, u16 *protocol);
>>>>> + efi_status_t (EFIAPI *receive)(struct efi_simple_network *this,
>>>>> + ulong *header_size, ulong *buffer_size, void *buffer,
>>>>> + struct efi_mac_address *src_addr,
>>>>> + struct efi_mac_address *dest_addr, u16 *protocol);
>>>>> + void (EFIAPI *waitforpacket)(void);
>>>>> + struct efi_simple_network_mode *mode;
>>>>> +};
>>>>> +
>>>>> +#define EFI_PXE_GUID \
>>>>> + EFI_GUID(0x03c4e603, 0xac28, 0x11d3, \
>>>>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>>>> +
>>>>> +struct efi_pxe_packet {
>>>>> + u8 packet[1472];
>>>>> +};
>>>>> +
>>>>> +struct efi_pxe_mode
>>>>> +{
>>>>> + u8 unused[52];
>>>>> + struct efi_pxe_packet dhcp_discover;
>>>>> + struct efi_pxe_packet dhcp_ack;
>>>>> + struct efi_pxe_packet proxy_offer;
>>>>> + struct efi_pxe_packet pxe_discover;
>>>>> + struct efi_pxe_packet pxe_reply;
>>>>> +};
>>>>> +
>>>>> +struct efi_pxe {
>>>>> + u64 rev;
>>>>> + void (EFIAPI *start)(void);
>>>>> + void (EFIAPI *stop)(void);
>>>>> + void (EFIAPI *dhcp)(void);
>>>>> + void (EFIAPI *discover)(void);
>>>>> + void (EFIAPI *mftp)(void);
>>>>> + void (EFIAPI *udpwrite)(void);
>>>>> + void (EFIAPI *udpread)(void);
>>>>> + void (EFIAPI *setipfilter)(void);
>>>>> + void (EFIAPI *arp)(void);
>>>>> + void (EFIAPI *setparams)(void);
>>>>> + void (EFIAPI *setstationip)(void);
>>>>> + void (EFIAPI *setpackets)(void);
>>>>> + struct efi_pxe_mode *mode;
>>>>> +};
>>>>> +
>>>>> #endif
>>>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>>>> index 88b8149..8005454 100644
>>>>> --- a/include/efi_loader.h
>>>>> +++ b/include/efi_loader.h
>>>>> @@ -91,6 +91,12 @@ extern struct list_head efi_obj_list;
>>>>> int efi_disk_register(void);
>>>>> /* Called by bootefi to make GOP (graphical) interface available */
>>>>> int efi_gop_register(void);
>>>>> +/* Called by bootefi to make the network interface available */
>>>>> +int efi_net_register(void **handle);
>>>>> +
>>>>> +/* Called by networking code to memorize the dhcp ack package */
>>>>> +void efi_net_set_dhcp_ack(void *pkt, int len);
>>>>> +
>>>>> /*
>>>>> * Stub implementation for a protocol opener that just returns the handle as
>>>>> * interface
>>>>> @@ -157,5 +163,6 @@ static inline void ascii2unicode(u16 *unicode, char *ascii)
>>>>> static inline void efi_restore_gd(void) { }
>>>>> static inline void efi_set_bootdev(const char *dev, const char *devnr,
>>>>> const char *path) { }
>>>>> +static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
>>>>>
>>>>> #endif
>>>>> diff --git a/include/net.h b/include/net.h
>>>>> index 05800c4..5ee5929 100644
>>>>> --- a/include/net.h
>>>>> +++ b/include/net.h
>>>>> @@ -269,7 +269,7 @@ int eth_getenv_enetaddr_by_index(const char *base_name, int index,
>>>>> int eth_init(void); /* Initialize the device */
>>>>> int eth_send(void *packet, int length); /* Send a packet */
>>>>>
>>>>> -#ifdef CONFIG_API
>>>>> +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
>>>>> int eth_receive(void *packet, int length); /* Receive a packet*/
>>>>> extern void (*push_packet)(void *packet, int length);
>>>>> #endif
>>>>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>>>>> index 83e31f6..2a3849e 100644
>>>>> --- a/lib/efi_loader/Makefile
>>>>> +++ b/lib/efi_loader/Makefile
>>>>> @@ -11,3 +11,4 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>>>> obj-y += efi_memory.o
>>>>> obj-$(CONFIG_LCD) += efi_gop.o
>>>>> obj-$(CONFIG_PARTITIONS) += efi_disk.o
>>>>> +obj-$(CONFIG_NET) += efi_net.o
>>>>> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
>>>>> new file mode 100644
>>>>> index 0000000..a95ff3c
>>>>> --- /dev/null
>>>>> +++ b/lib/efi_loader/efi_net.c
>>>>> @@ -0,0 +1,314 @@
>>>>> +/*
>>>>> + * EFI application network access support
>>>>> + *
>>>>> + * Copyright (c) 2016 Alexander Graf
>>>>> + *
>>>>> + * SPDX-License-Identifier: GPL-2.0+
>>>>> + */
>>>>> +
>>>>> +#include <common.h>
>>>>> +#include <efi_loader.h>
>>>>> +#include <inttypes.h>
>>>>> +#include <lcd.h>
>>>>> +#include <malloc.h>
>>>>> +
>>>>> +DECLARE_GLOBAL_DATA_PTR;
>>>>> +
>>>>> +static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
>>>>> +static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
>>>>> +static struct efi_pxe_packet *dhcp_ack;
>>>>> +static bool new_rx_packet;
>>>>> +static void *new_tx_packet;
>>>>> +
>>>>> +struct efi_net_obj {
>>>>> + /* Generic EFI object parent class data */
>>>>> + struct efi_object parent;
>>>>> + /* EFI Interface callback struct for network */
>>>>> + struct efi_simple_network net;
>>>>> + struct efi_simple_network_mode net_mode;
>>>>> + /* Device path to the network adapter */
>>>>> + struct efi_device_path_file_path dp[2];
>>>>> + /* PXE struct to transmit dhcp data */
>>>>> + struct efi_pxe pxe;
>>>>> + struct efi_pxe_mode pxe_mode;
>>>>> +};
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
>>>>> +{
>>>>> + EFI_ENTRY("%p", this);
>>>>> +
>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
>>>>> +{
>>>>> + EFI_ENTRY("%p", this);
>>>>> +
>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
>>>>> + ulong extra_rx, ulong extra_tx)
>>>>> +{
>>>>> + struct efi_net_obj *netobj = container_of(this, struct efi_net_obj, net);
>>>>> + int ret;
>>>>> + EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
>>>>> +
>>>>> + eth_halt();
>>>>> + eth_set_current();
>>>>> + ret = eth_init();
>>>>> + if (ret < 0) {
>>>>> + eth_halt();
>>>>> + return EFI_EXIT(EFI_DEVICE_ERROR);
>>>>> + }
>>>>> +
>>>>> + netobj->net_mode.state = EFI_NETWORK_INITIALIZED;
>>>>> +
>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
>>>>> + int extended_verification)
>>>>> +{
>>>>> + EFI_ENTRY("%p, %x", this, extended_verification);
>>>>> +
>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
>>>>> +{
>>>>> + EFI_ENTRY("%p", this);
>>>>> +
>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_receive_filters(
>>>>> + struct efi_simple_network *this, u32 enable, u32 disable,
>>>>> + int reset_mcast_filter, ulong mcast_filter_count,
>>>>> + struct efi_mac_address *mcast_filter)
>>>>> +{
>>>>> + EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
>>>>> + reset_mcast_filter, mcast_filter_count, mcast_filter);
>>>>> +
>>>>> + /* XXX Do we care? */
>>>>> +
>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_station_address(
>>>>> + struct efi_simple_network *this, int reset,
>>>>> + struct efi_mac_address *new_mac)
>>>>> +{
>>>>> + EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
>>>>> +
>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
>>>>> + int reset, ulong *stat_size,
>>>>> + void *stat_table)
>>>>> +{
>>>>> + EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
>>>>> +
>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
>>>>> + int ipv6,
>>>>> + struct efi_ip_address *ip,
>>>>> + struct efi_mac_address *mac)
>>>>> +{
>>>>> + EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
>>>>> +
>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
>>>>> + int read_write, ulong offset,
>>>>> + ulong buffer_size, char *buffer)
>>>>> +{
>>>>> + EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
>>>>> + buffer);
>>>>> +
>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
>>>>> + u32 *int_status, void **txbuf)
>>>>> +{
>>>>> + EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
>>>>> +
>>>>> + /* We send packets synchronously, so nothing is outstanding */
>>>>> + if (int_status)
>>>>> + *int_status = 0;
>>>>> + if (txbuf)
>>>>> + *txbuf = new_tx_packet;
>>>>> +
>>>>> + new_tx_packet = NULL;
>>>>> +
>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
>>>>> + ulong header_size, ulong buffer_size, void *buffer,
>>>>> + struct efi_mac_address *src_addr,
>>>>> + struct efi_mac_address *dest_addr, u16 *protocol)
>>>>> +{
>>>>> + EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
>>>>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>>>>> +
>>>>> + if (header_size) {
>>>>> + /* We would need to create the header if header_size != 0 */
>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>> + }
>>>>> +
>>>>> + /*
>>>>> + * Some drivers need to have DMA aligned buffers, so if
>>>>> + * it's misaligned, let's use our own.
>>>>> + */
>>>>> + if ((ulong)buffer & (ARCH_DMA_MINALIGN - 1)) {
>>>>> + void *packet = memalign(ARCH_DMA_MINALIGN, buffer_size);
>>>>> + memcpy(packet, buffer, buffer_size);
>>>>> + net_send_packet(packet, buffer_size);
>>>>> + free(packet);
>>>>> + } else {
>>>>> + net_send_packet(buffer, buffer_size);
>>>>> + }
>>>>> +
>>>>> + new_tx_packet = buffer;
>>>>> +
>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>> +}
>>>>> +
>>>>> +static void efi_net_push(void *pkt, int len)
>>>>> +{
>>>>> + new_rx_packet = true;
>>>>> +}
>>>>> +
>>>>> +static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
>>>>> + ulong *header_size, ulong *buffer_size, void *buffer,
>>>>> + struct efi_mac_address *src_addr,
>>>>> + struct efi_mac_address *dest_addr, u16 *protocol)
>>>>> +{
>>>>> + EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
>>>>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>>>>> +
>>>>> + push_packet = efi_net_push;
>>>>> + /* XXX With device model this reads multiple packets, we only want 1 */
>>>>> + eth_rx();
>>>>> + push_packet = NULL;
>>>>> +
>>>>> + if (!new_rx_packet)
>>>>> + return EFI_EXIT(EFI_NOT_READY);
>>>>> +
>>>>> + if (*buffer_size < net_rx_packet_len) {
>>>>> + /* Packet doesn't fit, try again with bigger buf */
>>>>> + *buffer_size = net_rx_packet_len;
>>>>> + return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
>>>>> + }
>>>>> +
>>>>> + memcpy(buffer, net_rx_packet, net_rx_packet_len);
>>>>> + *buffer_size = net_rx_packet_len;
>>>>> + new_rx_packet = false;
>>>>> +
>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>> +}
>>>>> +
>>>>> +static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
>>>>> + void **protocol_interface, void *agent_handle,
>>>>> + void *controller_handle, uint32_t attributes)
>>>>> +{
>>>>> + struct efi_simple_network *net = handle;
>>>>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>>>>> +
>>>>> + *protocol_interface = netobj->dp;
>>>>> +
>>>>> + return EFI_SUCCESS;
>>>>> +}
>>>>> +
>>>>> +static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol,
>>>>> + void **protocol_interface, void *agent_handle,
>>>>> + void *controller_handle, uint32_t attributes)
>>>>> +{
>>>>> + struct efi_simple_network *net = handle;
>>>>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>>>>> +
>>>>> + *protocol_interface = &netobj->pxe;
>>>>> +
>>>>> + return EFI_SUCCESS;
>>>>> +}
>>>>> +
>>>>> +void efi_net_set_dhcp_ack(void *pkt, int len)
>>>>> +{
>>>>> + int maxsize = sizeof(*dhcp_ack);
>>>>> +
>>>>> + if (!dhcp_ack)
>>>>> + dhcp_ack = malloc(maxsize);
>>>>> +
>>>>> + memcpy(dhcp_ack, pkt, min(len, maxsize));
>>>>> +}
>>>>> +
>>>>> +/* This gets called from do_bootefi_exec(). */
>>>>> +int efi_net_register(void **handle)
>>>>> +{
>>>>> + struct efi_net_obj *netobj;
>>>>> + struct efi_device_path_file_path dp_net = {
>>>>> + .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
>>>>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
>>>>> + .dp.length = sizeof(dp_net),
>>>>> + .str = { 'N', 'e', 't' },
>>>>> + };
>>>>> + struct efi_device_path_file_path dp_end = {
>>>>> + .dp.type = DEVICE_PATH_TYPE_END,
>>>>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
>>>>> + .dp.length = sizeof(dp_end),
>>>>> + };
>>>>> +
>>>>> + if (!eth_get_dev()) {
>>>>> + /* No eth device active, don't expose any */
>>>>> + return 0;
>>>>> + }
>>>>> +
>>>>> + /* We only expose the "active" eth device, so one is enough */
>>>>> + netobj = calloc(1, sizeof(*netobj));
>>>>> +
>>>>> + /* Fill in object data */
>>>>> + netobj->parent.protocols[0].guid = &efi_net_guid;
>>>>> + netobj->parent.protocols[0].open = efi_return_handle;
>>>>> + netobj->parent.protocols[1].guid = &efi_guid_device_path;
>>>>> + netobj->parent.protocols[1].open = efi_net_open_dp;
>>>>> + netobj->parent.protocols[2].guid = &efi_pxe_guid;
>>>>> + netobj->parent.protocols[2].open = efi_net_open_pxe;
>>>>> + netobj->parent.handle = &netobj->net;
>>>>> + netobj->net.start = efi_net_start;
>>>>> + netobj->net.stop = efi_net_stop;
>>>>> + netobj->net.initialize = efi_net_initialize;
>>>>> + netobj->net.reset = efi_net_reset;
>>>>> + netobj->net.shutdown = efi_net_shutdown;
>>>>> + netobj->net.receive_filters = efi_net_receive_filters;
>>>>> + netobj->net.station_address = efi_net_station_address;
>>>>> + netobj->net.statistics = efi_net_statistics;
>>>>> + netobj->net.mcastiptomac = efi_net_mcastiptomac;
>>>>> + netobj->net.nvdata = efi_net_nvdata;
>>>>> + netobj->net.get_status = efi_net_get_status;
>>>>> + netobj->net.transmit = efi_net_transmit;
>>>>> + netobj->net.receive = efi_net_receive;
>>>>> + netobj->net.mode = &netobj->net_mode;
>>>>> + netobj->net_mode.state = EFI_NETWORK_STARTED;
>>>>> + netobj->dp[0] = dp_net;
>>>>> + netobj->dp[1] = dp_end;
>>>>> + memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
>>>>> + netobj->net_mode.max_packet_size = PKTSIZE;
>>>>
>>>> Why is this statically created? Shouldn't it come from the U-Boot
>>>> ethernet tables dynamically when it is needed?
>>>
>>> The driver as is only exposes a single interface for the currently selected network device. My main goal behind this was pxe boot - where you usually load the payload from tftp and continue acting on the same interface later on.
>>>
>>> I guess we could create devices for all network devices as well. I remember that I wanted to only expose network if it's really necessary because of resource usage. But I don't remember exactly what resource the peoblem was otoh ;).
>>
>> I think in general (given that you are writing this code and this is
>> the best opportunity to get the design right) that things like this
>> should look up U-Boot tables rather than creating their own. So a
>> model where the device is scanned as needed seems better. Then if we
>> want to change the constraints later, e.g. devices appear that were
>> not previously present, then we can deal with that.
>>
>> I understand with block devices your point that there is no single
>> table of block devices. However, this support will be applied soon
>> (see u-boot-dm/master), even without driver model. I think we should
>> fix these things rather than work around them, as the code will be
>> more maintainable that way.
>
> I agree wholeheartedly :). The beauty of "proper" open source code is
> that you can actually modify the guts of it to make the code easier at
> the end of the day.
>
>> In this case I wonder if we should have an EFI device uclass, and
>> allow devices to have this as a child? It would allow for easy
>> enumeration and avoid another system-specific device table (something
>> that driver model is trying to reduce).
>
> I'm not 100% sure the EFI driver exposure is actually a child-parent
> relationship with the respective driver model objects. In Java speech
> it's more of an "interface" definition than a subclass.
The parent/child relationship is how this is done in driver model. For
example, MMC devices (UCLASS_MMC) provide a block device interface, as
a child device in UCLASS_BLK.
>
> But that said, I think that it may still make sense to move it into the
> respective driver cores and just have the EFI structs part of the block
> device structs.
But won't you have different types of drivers? E.g. video, network?
>
> However I don't consider it as very high priority at the moment.
> Functionally nothing should change from a payload point of view and the
> current code allows us to iron out bugs and have non-believers gain
> faith in the whole uEFI story without breaking non-uEFI code paths ;).
> And all of the actual interface code shouldn't change with a move into
> device objects.
>
> So how about we start to tackle this once the non-DM code is gone? That
> should simplify things for everyone.
I think instead we should set this up so that it works nicely with DM.
The non-DM code will be around for a long time. I'm not sure how long.
At present the EFI impl really doesn't use it at all. I'm not too
bothered about when, but I think it is worth looking at before too
long. I also suggest that we require DM with new features like this,
to encourage people to move.
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v3 1/7] efi_loader: Add network access support
2016-05-18 17:21 ` Simon Glass
@ 2016-05-19 16:18 ` Alexander Graf
2016-05-19 16:34 ` Simon Glass
0 siblings, 1 reply; 30+ messages in thread
From: Alexander Graf @ 2016-05-19 16:18 UTC (permalink / raw)
To: u-boot
On 05/18/2016 07:21 PM, Simon Glass wrote:
> +Tom
>
> Hi Alex,
>
> On 16 May 2016 at 12:06, Alexander Graf <agraf@suse.de> wrote:
>>
>> On 16.05.16 15:24, Simon Glass wrote:
>>> Hi Alexander,
>>>
>>> On 14 May 2016 at 14:34, Alexander Graf <agraf@suse.de> wrote:
>>>>
>>>>> Am 14.05.2016 um 21:49 schrieb Simon Glass <sjg@chromium.org>:
>>>>>
>>>>> Hi Alexander,
>>>>>
>>>>>> On 10 May 2016 at 15:25, Alexander Graf <agraf@suse.de> wrote:
>>>>>> We can now successfully boot EFI applications from disk, but users
>>>>>> may want to also run them from a PXE setup.
>>>>>>
>>>>>> This patch implements rudimentary network support, allowing a payload
>>>>>> to send and receive network packets.
>>>>>>
>>>>>> With this patch, I was able to successfully run grub2 with network
>>>>>> access inside of QEMU's -M xlnx-ep108 and on a zcu102 system.
>>>>>>
>>>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>>>>
>>>>>> ---
>>>>>>
>>>>>> v2 -> v3:
>>>>>>
>>>>>> - Align initialization sequence with net code
>>>>>> - Set device to initialized after init call
>>>>>> - Align tx buffers to DMA alignment (rx gets memcpy'd)
>>>>>> - Add comment about eth_rx()
>>>>>> ---
>>>>>> cmd/bootefi.c | 7 ++
>>>>>> include/efi_api.h | 119 ++++++++++++++++++
>>>>>> include/efi_loader.h | 7 ++
>>>>>> include/net.h | 2 +-
>>>>>> lib/efi_loader/Makefile | 1 +
>>>>>> lib/efi_loader/efi_net.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>>> net/bootp.c | 2 +
>>>>>> net/net.c | 4 +-
>>>>>> net/tftp.c | 2 +
>>>>>> 9 files changed, 455 insertions(+), 3 deletions(-)
>>>>>> create mode 100644 lib/efi_loader/efi_net.c
>>>>>>
>>>>>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>>>>>> index 7f552fc..d3a2331 100644
>>>>>> --- a/cmd/bootefi.c
>>>>>> +++ b/cmd/bootefi.c
>>>>>> @@ -197,6 +197,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
>>>>>> #ifdef CONFIG_LCD
>>>>>> efi_gop_register();
>>>>>> #endif
>>>>>> +#ifdef CONFIG_NET
>>>>>> + void *nethandle = loaded_image_info.device_handle;
>>>>>> + efi_net_register(&nethandle);
>>>>>> +
>>>>>> + if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
>>>>>> + loaded_image_info.device_handle = nethandle;
>>>>>> +#endif
>>>>>>
>>>>>> /* Call our payload! */
>>>>>> #ifdef DEBUG_EFI
>>>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>>>> index 51d7586..20035d7 100644
>>>>>> --- a/include/efi_api.h
>>>>>> +++ b/include/efi_api.h
>>>>>> @@ -412,4 +412,123 @@ struct efi_gop
>>>>>> struct efi_gop_mode *mode;
>>>>>> };
>>>>>>
>>>>>> +#define EFI_SIMPLE_NETWORK_GUID \
>>>>>> + EFI_GUID(0xa19832b9, 0xac25, 0x11d3, \
>>>>>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>>>>> +
>>>>>> +struct efi_mac_address {
>>>>>> + char mac_addr[32];
>>>>>> +};
>>>>>> +
>>>>>> +struct efi_ip_address {
>>>>>> + u8 ip_addr[16];
>>>>>> +};
>>>>>> +
>>>>>> +enum efi_simple_network_state {
>>>>>> + EFI_NETWORK_STOPPED,
>>>>>> + EFI_NETWORK_STARTED,
>>>>>> + EFI_NETWORK_INITIALIZED,
>>>>>> +};
>>>>>> +
>>>>>> +struct efi_simple_network_mode {
>>>>>> + enum efi_simple_network_state state;
>>>>>> + u32 hwaddr_size;
>>>>>> + u32 media_header_size;
>>>>>> + u32 max_packet_size;
>>>>>> + u32 nvram_size;
>>>>>> + u32 nvram_access_size;
>>>>>> + u32 receive_filter_mask;
>>>>>> + u32 receive_filter_setting;
>>>>>> + u32 max_mcast_filter_count;
>>>>>> + u32 mcast_filter_count;
>>>>>> + struct efi_mac_address mcast_filter[16];
>>>>>> + struct efi_mac_address current_address;
>>>>>> + struct efi_mac_address broadcast_address;
>>>>>> + struct efi_mac_address permanent_address;
>>>>>> + u8 if_type;
>>>>>> + u8 mac_changeable;
>>>>>> + u8 multitx_supported;
>>>>>> + u8 media_present_supported;
>>>>>> + u8 media_present;
>>>>>> +};
>>>>>> +
>>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01,
>>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02,
>>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04,
>>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08,
>>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10,
>>>>>> +
>>>>>> +struct efi_simple_network
>>>>>> +{
>>>>>> + u64 revision;
>>>>>> + efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
>>>>>> + efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
>>>>>> + efi_status_t (EFIAPI *initialize)(struct efi_simple_network *this,
>>>>>> + ulong extra_rx, ulong extra_tx);
>>>>>> + efi_status_t (EFIAPI *reset)(struct efi_simple_network *this,
>>>>>> + int extended_verification);
>>>>>> + efi_status_t (EFIAPI *shutdown)(struct efi_simple_network *this);
>>>>>> + efi_status_t (EFIAPI *receive_filters)(struct efi_simple_network *this,
>>>>>> + u32 enable, u32 disable, int reset_mcast_filter,
>>>>>> + ulong mcast_filter_count,
>>>>>> + struct efi_mac_address *mcast_filter);
>>>>>> + efi_status_t (EFIAPI *station_address)(struct efi_simple_network *this,
>>>>>> + int reset, struct efi_mac_address *new_mac);
>>>>>> + efi_status_t (EFIAPI *statistics)(struct efi_simple_network *this,
>>>>>> + int reset, ulong *stat_size, void *stat_table);
>>>>>> + efi_status_t (EFIAPI *mcastiptomac)(struct efi_simple_network *this,
>>>>>> + int ipv6, struct efi_ip_address *ip,
>>>>>> + struct efi_mac_address *mac);
>>>>>> + efi_status_t (EFIAPI *nvdata)(struct efi_simple_network *this,
>>>>>> + int read_write, ulong offset, ulong buffer_size,
>>>>>> + char *buffer);
>>>>>> + efi_status_t (EFIAPI *get_status)(struct efi_simple_network *this,
>>>>>> + u32 *int_status, void **txbuf);
>>>>>> + efi_status_t (EFIAPI *transmit)(struct efi_simple_network *this,
>>>>>> + ulong header_size, ulong buffer_size, void *buffer,
>>>>>> + struct efi_mac_address *src_addr,
>>>>>> + struct efi_mac_address *dest_addr, u16 *protocol);
>>>>>> + efi_status_t (EFIAPI *receive)(struct efi_simple_network *this,
>>>>>> + ulong *header_size, ulong *buffer_size, void *buffer,
>>>>>> + struct efi_mac_address *src_addr,
>>>>>> + struct efi_mac_address *dest_addr, u16 *protocol);
>>>>>> + void (EFIAPI *waitforpacket)(void);
>>>>>> + struct efi_simple_network_mode *mode;
>>>>>> +};
>>>>>> +
>>>>>> +#define EFI_PXE_GUID \
>>>>>> + EFI_GUID(0x03c4e603, 0xac28, 0x11d3, \
>>>>>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>>>>> +
>>>>>> +struct efi_pxe_packet {
>>>>>> + u8 packet[1472];
>>>>>> +};
>>>>>> +
>>>>>> +struct efi_pxe_mode
>>>>>> +{
>>>>>> + u8 unused[52];
>>>>>> + struct efi_pxe_packet dhcp_discover;
>>>>>> + struct efi_pxe_packet dhcp_ack;
>>>>>> + struct efi_pxe_packet proxy_offer;
>>>>>> + struct efi_pxe_packet pxe_discover;
>>>>>> + struct efi_pxe_packet pxe_reply;
>>>>>> +};
>>>>>> +
>>>>>> +struct efi_pxe {
>>>>>> + u64 rev;
>>>>>> + void (EFIAPI *start)(void);
>>>>>> + void (EFIAPI *stop)(void);
>>>>>> + void (EFIAPI *dhcp)(void);
>>>>>> + void (EFIAPI *discover)(void);
>>>>>> + void (EFIAPI *mftp)(void);
>>>>>> + void (EFIAPI *udpwrite)(void);
>>>>>> + void (EFIAPI *udpread)(void);
>>>>>> + void (EFIAPI *setipfilter)(void);
>>>>>> + void (EFIAPI *arp)(void);
>>>>>> + void (EFIAPI *setparams)(void);
>>>>>> + void (EFIAPI *setstationip)(void);
>>>>>> + void (EFIAPI *setpackets)(void);
>>>>>> + struct efi_pxe_mode *mode;
>>>>>> +};
>>>>>> +
>>>>>> #endif
>>>>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>>>>> index 88b8149..8005454 100644
>>>>>> --- a/include/efi_loader.h
>>>>>> +++ b/include/efi_loader.h
>>>>>> @@ -91,6 +91,12 @@ extern struct list_head efi_obj_list;
>>>>>> int efi_disk_register(void);
>>>>>> /* Called by bootefi to make GOP (graphical) interface available */
>>>>>> int efi_gop_register(void);
>>>>>> +/* Called by bootefi to make the network interface available */
>>>>>> +int efi_net_register(void **handle);
>>>>>> +
>>>>>> +/* Called by networking code to memorize the dhcp ack package */
>>>>>> +void efi_net_set_dhcp_ack(void *pkt, int len);
>>>>>> +
>>>>>> /*
>>>>>> * Stub implementation for a protocol opener that just returns the handle as
>>>>>> * interface
>>>>>> @@ -157,5 +163,6 @@ static inline void ascii2unicode(u16 *unicode, char *ascii)
>>>>>> static inline void efi_restore_gd(void) { }
>>>>>> static inline void efi_set_bootdev(const char *dev, const char *devnr,
>>>>>> const char *path) { }
>>>>>> +static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
>>>>>>
>>>>>> #endif
>>>>>> diff --git a/include/net.h b/include/net.h
>>>>>> index 05800c4..5ee5929 100644
>>>>>> --- a/include/net.h
>>>>>> +++ b/include/net.h
>>>>>> @@ -269,7 +269,7 @@ int eth_getenv_enetaddr_by_index(const char *base_name, int index,
>>>>>> int eth_init(void); /* Initialize the device */
>>>>>> int eth_send(void *packet, int length); /* Send a packet */
>>>>>>
>>>>>> -#ifdef CONFIG_API
>>>>>> +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
>>>>>> int eth_receive(void *packet, int length); /* Receive a packet*/
>>>>>> extern void (*push_packet)(void *packet, int length);
>>>>>> #endif
>>>>>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>>>>>> index 83e31f6..2a3849e 100644
>>>>>> --- a/lib/efi_loader/Makefile
>>>>>> +++ b/lib/efi_loader/Makefile
>>>>>> @@ -11,3 +11,4 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>>>>> obj-y += efi_memory.o
>>>>>> obj-$(CONFIG_LCD) += efi_gop.o
>>>>>> obj-$(CONFIG_PARTITIONS) += efi_disk.o
>>>>>> +obj-$(CONFIG_NET) += efi_net.o
>>>>>> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
>>>>>> new file mode 100644
>>>>>> index 0000000..a95ff3c
>>>>>> --- /dev/null
>>>>>> +++ b/lib/efi_loader/efi_net.c
>>>>>> @@ -0,0 +1,314 @@
>>>>>> +/*
>>>>>> + * EFI application network access support
>>>>>> + *
>>>>>> + * Copyright (c) 2016 Alexander Graf
>>>>>> + *
>>>>>> + * SPDX-License-Identifier: GPL-2.0+
>>>>>> + */
>>>>>> +
>>>>>> +#include <common.h>
>>>>>> +#include <efi_loader.h>
>>>>>> +#include <inttypes.h>
>>>>>> +#include <lcd.h>
>>>>>> +#include <malloc.h>
>>>>>> +
>>>>>> +DECLARE_GLOBAL_DATA_PTR;
>>>>>> +
>>>>>> +static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
>>>>>> +static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
>>>>>> +static struct efi_pxe_packet *dhcp_ack;
>>>>>> +static bool new_rx_packet;
>>>>>> +static void *new_tx_packet;
>>>>>> +
>>>>>> +struct efi_net_obj {
>>>>>> + /* Generic EFI object parent class data */
>>>>>> + struct efi_object parent;
>>>>>> + /* EFI Interface callback struct for network */
>>>>>> + struct efi_simple_network net;
>>>>>> + struct efi_simple_network_mode net_mode;
>>>>>> + /* Device path to the network adapter */
>>>>>> + struct efi_device_path_file_path dp[2];
>>>>>> + /* PXE struct to transmit dhcp data */
>>>>>> + struct efi_pxe pxe;
>>>>>> + struct efi_pxe_mode pxe_mode;
>>>>>> +};
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p", this);
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p", this);
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
>>>>>> + ulong extra_rx, ulong extra_tx)
>>>>>> +{
>>>>>> + struct efi_net_obj *netobj = container_of(this, struct efi_net_obj, net);
>>>>>> + int ret;
>>>>>> + EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
>>>>>> +
>>>>>> + eth_halt();
>>>>>> + eth_set_current();
>>>>>> + ret = eth_init();
>>>>>> + if (ret < 0) {
>>>>>> + eth_halt();
>>>>>> + return EFI_EXIT(EFI_DEVICE_ERROR);
>>>>>> + }
>>>>>> +
>>>>>> + netobj->net_mode.state = EFI_NETWORK_INITIALIZED;
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
>>>>>> + int extended_verification)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p, %x", this, extended_verification);
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p", this);
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_receive_filters(
>>>>>> + struct efi_simple_network *this, u32 enable, u32 disable,
>>>>>> + int reset_mcast_filter, ulong mcast_filter_count,
>>>>>> + struct efi_mac_address *mcast_filter)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
>>>>>> + reset_mcast_filter, mcast_filter_count, mcast_filter);
>>>>>> +
>>>>>> + /* XXX Do we care? */
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_station_address(
>>>>>> + struct efi_simple_network *this, int reset,
>>>>>> + struct efi_mac_address *new_mac)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
>>>>>> + int reset, ulong *stat_size,
>>>>>> + void *stat_table)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
>>>>>> + int ipv6,
>>>>>> + struct efi_ip_address *ip,
>>>>>> + struct efi_mac_address *mac)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
>>>>>> + int read_write, ulong offset,
>>>>>> + ulong buffer_size, char *buffer)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
>>>>>> + buffer);
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
>>>>>> + u32 *int_status, void **txbuf)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
>>>>>> +
>>>>>> + /* We send packets synchronously, so nothing is outstanding */
>>>>>> + if (int_status)
>>>>>> + *int_status = 0;
>>>>>> + if (txbuf)
>>>>>> + *txbuf = new_tx_packet;
>>>>>> +
>>>>>> + new_tx_packet = NULL;
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
>>>>>> + ulong header_size, ulong buffer_size, void *buffer,
>>>>>> + struct efi_mac_address *src_addr,
>>>>>> + struct efi_mac_address *dest_addr, u16 *protocol)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
>>>>>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>>>>>> +
>>>>>> + if (header_size) {
>>>>>> + /* We would need to create the header if header_size != 0 */
>>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>>> + }
>>>>>> +
>>>>>> + /*
>>>>>> + * Some drivers need to have DMA aligned buffers, so if
>>>>>> + * it's misaligned, let's use our own.
>>>>>> + */
>>>>>> + if ((ulong)buffer & (ARCH_DMA_MINALIGN - 1)) {
>>>>>> + void *packet = memalign(ARCH_DMA_MINALIGN, buffer_size);
>>>>>> + memcpy(packet, buffer, buffer_size);
>>>>>> + net_send_packet(packet, buffer_size);
>>>>>> + free(packet);
>>>>>> + } else {
>>>>>> + net_send_packet(buffer, buffer_size);
>>>>>> + }
>>>>>> +
>>>>>> + new_tx_packet = buffer;
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>> +}
>>>>>> +
>>>>>> +static void efi_net_push(void *pkt, int len)
>>>>>> +{
>>>>>> + new_rx_packet = true;
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
>>>>>> + ulong *header_size, ulong *buffer_size, void *buffer,
>>>>>> + struct efi_mac_address *src_addr,
>>>>>> + struct efi_mac_address *dest_addr, u16 *protocol)
>>>>>> +{
>>>>>> + EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
>>>>>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>>>>>> +
>>>>>> + push_packet = efi_net_push;
>>>>>> + /* XXX With device model this reads multiple packets, we only want 1 */
>>>>>> + eth_rx();
>>>>>> + push_packet = NULL;
>>>>>> +
>>>>>> + if (!new_rx_packet)
>>>>>> + return EFI_EXIT(EFI_NOT_READY);
>>>>>> +
>>>>>> + if (*buffer_size < net_rx_packet_len) {
>>>>>> + /* Packet doesn't fit, try again with bigger buf */
>>>>>> + *buffer_size = net_rx_packet_len;
>>>>>> + return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
>>>>>> + }
>>>>>> +
>>>>>> + memcpy(buffer, net_rx_packet, net_rx_packet_len);
>>>>>> + *buffer_size = net_rx_packet_len;
>>>>>> + new_rx_packet = false;
>>>>>> +
>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
>>>>>> + void **protocol_interface, void *agent_handle,
>>>>>> + void *controller_handle, uint32_t attributes)
>>>>>> +{
>>>>>> + struct efi_simple_network *net = handle;
>>>>>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>>>>>> +
>>>>>> + *protocol_interface = netobj->dp;
>>>>>> +
>>>>>> + return EFI_SUCCESS;
>>>>>> +}
>>>>>> +
>>>>>> +static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol,
>>>>>> + void **protocol_interface, void *agent_handle,
>>>>>> + void *controller_handle, uint32_t attributes)
>>>>>> +{
>>>>>> + struct efi_simple_network *net = handle;
>>>>>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>>>>>> +
>>>>>> + *protocol_interface = &netobj->pxe;
>>>>>> +
>>>>>> + return EFI_SUCCESS;
>>>>>> +}
>>>>>> +
>>>>>> +void efi_net_set_dhcp_ack(void *pkt, int len)
>>>>>> +{
>>>>>> + int maxsize = sizeof(*dhcp_ack);
>>>>>> +
>>>>>> + if (!dhcp_ack)
>>>>>> + dhcp_ack = malloc(maxsize);
>>>>>> +
>>>>>> + memcpy(dhcp_ack, pkt, min(len, maxsize));
>>>>>> +}
>>>>>> +
>>>>>> +/* This gets called from do_bootefi_exec(). */
>>>>>> +int efi_net_register(void **handle)
>>>>>> +{
>>>>>> + struct efi_net_obj *netobj;
>>>>>> + struct efi_device_path_file_path dp_net = {
>>>>>> + .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
>>>>>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
>>>>>> + .dp.length = sizeof(dp_net),
>>>>>> + .str = { 'N', 'e', 't' },
>>>>>> + };
>>>>>> + struct efi_device_path_file_path dp_end = {
>>>>>> + .dp.type = DEVICE_PATH_TYPE_END,
>>>>>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
>>>>>> + .dp.length = sizeof(dp_end),
>>>>>> + };
>>>>>> +
>>>>>> + if (!eth_get_dev()) {
>>>>>> + /* No eth device active, don't expose any */
>>>>>> + return 0;
>>>>>> + }
>>>>>> +
>>>>>> + /* We only expose the "active" eth device, so one is enough */
>>>>>> + netobj = calloc(1, sizeof(*netobj));
>>>>>> +
>>>>>> + /* Fill in object data */
>>>>>> + netobj->parent.protocols[0].guid = &efi_net_guid;
>>>>>> + netobj->parent.protocols[0].open = efi_return_handle;
>>>>>> + netobj->parent.protocols[1].guid = &efi_guid_device_path;
>>>>>> + netobj->parent.protocols[1].open = efi_net_open_dp;
>>>>>> + netobj->parent.protocols[2].guid = &efi_pxe_guid;
>>>>>> + netobj->parent.protocols[2].open = efi_net_open_pxe;
>>>>>> + netobj->parent.handle = &netobj->net;
>>>>>> + netobj->net.start = efi_net_start;
>>>>>> + netobj->net.stop = efi_net_stop;
>>>>>> + netobj->net.initialize = efi_net_initialize;
>>>>>> + netobj->net.reset = efi_net_reset;
>>>>>> + netobj->net.shutdown = efi_net_shutdown;
>>>>>> + netobj->net.receive_filters = efi_net_receive_filters;
>>>>>> + netobj->net.station_address = efi_net_station_address;
>>>>>> + netobj->net.statistics = efi_net_statistics;
>>>>>> + netobj->net.mcastiptomac = efi_net_mcastiptomac;
>>>>>> + netobj->net.nvdata = efi_net_nvdata;
>>>>>> + netobj->net.get_status = efi_net_get_status;
>>>>>> + netobj->net.transmit = efi_net_transmit;
>>>>>> + netobj->net.receive = efi_net_receive;
>>>>>> + netobj->net.mode = &netobj->net_mode;
>>>>>> + netobj->net_mode.state = EFI_NETWORK_STARTED;
>>>>>> + netobj->dp[0] = dp_net;
>>>>>> + netobj->dp[1] = dp_end;
>>>>>> + memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
>>>>>> + netobj->net_mode.max_packet_size = PKTSIZE;
>>>>> Why is this statically created? Shouldn't it come from the U-Boot
>>>>> ethernet tables dynamically when it is needed?
>>>> The driver as is only exposes a single interface for the currently selected network device. My main goal behind this was pxe boot - where you usually load the payload from tftp and continue acting on the same interface later on.
>>>>
>>>> I guess we could create devices for all network devices as well. I remember that I wanted to only expose network if it's really necessary because of resource usage. But I don't remember exactly what resource the peoblem was otoh ;).
>>> I think in general (given that you are writing this code and this is
>>> the best opportunity to get the design right) that things like this
>>> should look up U-Boot tables rather than creating their own. So a
>>> model where the device is scanned as needed seems better. Then if we
>>> want to change the constraints later, e.g. devices appear that were
>>> not previously present, then we can deal with that.
>>>
>>> I understand with block devices your point that there is no single
>>> table of block devices. However, this support will be applied soon
>>> (see u-boot-dm/master), even without driver model. I think we should
>>> fix these things rather than work around them, as the code will be
>>> more maintainable that way.
>> I agree wholeheartedly :). The beauty of "proper" open source code is
>> that you can actually modify the guts of it to make the code easier at
>> the end of the day.
>>
>>> In this case I wonder if we should have an EFI device uclass, and
>>> allow devices to have this as a child? It would allow for easy
>>> enumeration and avoid another system-specific device table (something
>>> that driver model is trying to reduce).
>> I'm not 100% sure the EFI driver exposure is actually a child-parent
>> relationship with the respective driver model objects. In Java speech
>> it's more of an "interface" definition than a subclass.
> The parent/child relationship is how this is done in driver model. For
> example, MMC devices (UCLASS_MMC) provide a block device interface, as
> a child device in UCLASS_BLK.
I'd have to take a closer look to really say something intelligible here.
>
>> But that said, I think that it may still make sense to move it into the
>> respective driver cores and just have the EFI structs part of the block
>> device structs.
> But won't you have different types of drivers? E.g. video, network?
We do have different types of drivers, that's why there are different
files in lib/efi_loader :).
>
>> However I don't consider it as very high priority at the moment.
>> Functionally nothing should change from a payload point of view and the
>> current code allows us to iron out bugs and have non-believers gain
>> faith in the whole uEFI story without breaking non-uEFI code paths ;).
>> And all of the actual interface code shouldn't change with a move into
>> device objects.
>>
>> So how about we start to tackle this once the non-DM code is gone? That
>> should simplify things for everyone.
> I think instead we should set this up so that it works nicely with DM.
> The non-DM code will be around for a long time. I'm not sure how long.
>
> At present the EFI impl really doesn't use it at all. I'm not too
> bothered about when, but I think it is worth looking at before too
> long. I also suggest that we require DM with new features like this,
> to encourage people to move.
You might overestimate the power of uEFI support. Most people run away
screaming rather than embrace uEFI when you mention it. My most
important goal for now is to make sure that they do not run away.
Forcing anything on them will cause that to happen though.
Alex
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [PATCH v3 1/7] efi_loader: Add network access support
2016-05-19 16:18 ` Alexander Graf
@ 2016-05-19 16:34 ` Simon Glass
0 siblings, 0 replies; 30+ messages in thread
From: Simon Glass @ 2016-05-19 16:34 UTC (permalink / raw)
To: u-boot
Hi Alexander.
On 19 May 2016 at 10:18, Alexander Graf <agraf@suse.de> wrote:
>
> On 05/18/2016 07:21 PM, Simon Glass wrote:
>>
>> +Tom
>>
>> Hi Alex,
>>
>> On 16 May 2016 at 12:06, Alexander Graf <agraf@suse.de> wrote:
>>>
>>>
>>> On 16.05.16 15:24, Simon Glass wrote:
>>>>
>>>> Hi Alexander,
>>>>
>>>> On 14 May 2016 at 14:34, Alexander Graf <agraf@suse.de> wrote:
>>>>>
>>>>>
>>>>>> Am 14.05.2016 um 21:49 schrieb Simon Glass <sjg@chromium.org>:
>>>>>>
>>>>>> Hi Alexander,
>>>>>>
>>>>>>> On 10 May 2016 at 15:25, Alexander Graf <agraf@suse.de> wrote:
>>>>>>> We can now successfully boot EFI applications from disk, but users
>>>>>>> may want to also run them from a PXE setup.
>>>>>>>
>>>>>>> This patch implements rudimentary network support, allowing a payload
>>>>>>> to send and receive network packets.
>>>>>>>
>>>>>>> With this patch, I was able to successfully run grub2 with network
>>>>>>> access inside of QEMU's -M xlnx-ep108 and on a zcu102 system.
>>>>>>>
>>>>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>>>>>
>>>>>>> ---
>>>>>>>
>>>>>>> v2 -> v3:
>>>>>>>
>>>>>>> - Align initialization sequence with net code
>>>>>>> - Set device to initialized after init call
>>>>>>> - Align tx buffers to DMA alignment (rx gets memcpy'd)
>>>>>>> - Add comment about eth_rx()
>>>>>>> ---
>>>>>>> cmd/bootefi.c | 7 ++
>>>>>>> include/efi_api.h | 119 ++++++++++++++++++
>>>>>>> include/efi_loader.h | 7 ++
>>>>>>> include/net.h | 2 +-
>>>>>>> lib/efi_loader/Makefile | 1 +
>>>>>>> lib/efi_loader/efi_net.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>> net/bootp.c | 2 +
>>>>>>> net/net.c | 4 +-
>>>>>>> net/tftp.c | 2 +
>>>>>>> 9 files changed, 455 insertions(+), 3 deletions(-)
>>>>>>> create mode 100644 lib/efi_loader/efi_net.c
>>>>>>>
>>>>>>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>>>>>>> index 7f552fc..d3a2331 100644
>>>>>>> --- a/cmd/bootefi.c
>>>>>>> +++ b/cmd/bootefi.c
>>>>>>> @@ -197,6 +197,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
>>>>>>> #ifdef CONFIG_LCD
>>>>>>> efi_gop_register();
>>>>>>> #endif
>>>>>>> +#ifdef CONFIG_NET
>>>>>>> + void *nethandle = loaded_image_info.device_handle;
>>>>>>> + efi_net_register(&nethandle);
>>>>>>> +
>>>>>>> + if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
>>>>>>> + loaded_image_info.device_handle = nethandle;
>>>>>>> +#endif
>>>>>>>
>>>>>>> /* Call our payload! */
>>>>>>> #ifdef DEBUG_EFI
>>>>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>>>>> index 51d7586..20035d7 100644
>>>>>>> --- a/include/efi_api.h
>>>>>>> +++ b/include/efi_api.h
>>>>>>> @@ -412,4 +412,123 @@ struct efi_gop
>>>>>>> struct efi_gop_mode *mode;
>>>>>>> };
>>>>>>>
>>>>>>> +#define EFI_SIMPLE_NETWORK_GUID \
>>>>>>> + EFI_GUID(0xa19832b9, 0xac25, 0x11d3, \
>>>>>>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>>>>>> +
>>>>>>> +struct efi_mac_address {
>>>>>>> + char mac_addr[32];
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct efi_ip_address {
>>>>>>> + u8 ip_addr[16];
>>>>>>> +};
>>>>>>> +
>>>>>>> +enum efi_simple_network_state {
>>>>>>> + EFI_NETWORK_STOPPED,
>>>>>>> + EFI_NETWORK_STARTED,
>>>>>>> + EFI_NETWORK_INITIALIZED,
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct efi_simple_network_mode {
>>>>>>> + enum efi_simple_network_state state;
>>>>>>> + u32 hwaddr_size;
>>>>>>> + u32 media_header_size;
>>>>>>> + u32 max_packet_size;
>>>>>>> + u32 nvram_size;
>>>>>>> + u32 nvram_access_size;
>>>>>>> + u32 receive_filter_mask;
>>>>>>> + u32 receive_filter_setting;
>>>>>>> + u32 max_mcast_filter_count;
>>>>>>> + u32 mcast_filter_count;
>>>>>>> + struct efi_mac_address mcast_filter[16];
>>>>>>> + struct efi_mac_address current_address;
>>>>>>> + struct efi_mac_address broadcast_address;
>>>>>>> + struct efi_mac_address permanent_address;
>>>>>>> + u8 if_type;
>>>>>>> + u8 mac_changeable;
>>>>>>> + u8 multitx_supported;
>>>>>>> + u8 media_present_supported;
>>>>>>> + u8 media_present;
>>>>>>> +};
>>>>>>> +
>>>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01,
>>>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02,
>>>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04,
>>>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08,
>>>>>>> +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10,
>>>>>>> +
>>>>>>> +struct efi_simple_network
>>>>>>> +{
>>>>>>> + u64 revision;
>>>>>>> + efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
>>>>>>> + efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
>>>>>>> + efi_status_t (EFIAPI *initialize)(struct efi_simple_network *this,
>>>>>>> + ulong extra_rx, ulong extra_tx);
>>>>>>> + efi_status_t (EFIAPI *reset)(struct efi_simple_network *this,
>>>>>>> + int extended_verification);
>>>>>>> + efi_status_t (EFIAPI *shutdown)(struct efi_simple_network *this);
>>>>>>> + efi_status_t (EFIAPI *receive_filters)(struct efi_simple_network *this,
>>>>>>> + u32 enable, u32 disable, int reset_mcast_filter,
>>>>>>> + ulong mcast_filter_count,
>>>>>>> + struct efi_mac_address *mcast_filter);
>>>>>>> + efi_status_t (EFIAPI *station_address)(struct efi_simple_network *this,
>>>>>>> + int reset, struct efi_mac_address *new_mac);
>>>>>>> + efi_status_t (EFIAPI *statistics)(struct efi_simple_network *this,
>>>>>>> + int reset, ulong *stat_size, void *stat_table);
>>>>>>> + efi_status_t (EFIAPI *mcastiptomac)(struct efi_simple_network *this,
>>>>>>> + int ipv6, struct efi_ip_address *ip,
>>>>>>> + struct efi_mac_address *mac);
>>>>>>> + efi_status_t (EFIAPI *nvdata)(struct efi_simple_network *this,
>>>>>>> + int read_write, ulong offset, ulong buffer_size,
>>>>>>> + char *buffer);
>>>>>>> + efi_status_t (EFIAPI *get_status)(struct efi_simple_network *this,
>>>>>>> + u32 *int_status, void **txbuf);
>>>>>>> + efi_status_t (EFIAPI *transmit)(struct efi_simple_network *this,
>>>>>>> + ulong header_size, ulong buffer_size, void *buffer,
>>>>>>> + struct efi_mac_address *src_addr,
>>>>>>> + struct efi_mac_address *dest_addr, u16 *protocol);
>>>>>>> + efi_status_t (EFIAPI *receive)(struct efi_simple_network *this,
>>>>>>> + ulong *header_size, ulong *buffer_size, void *buffer,
>>>>>>> + struct efi_mac_address *src_addr,
>>>>>>> + struct efi_mac_address *dest_addr, u16 *protocol);
>>>>>>> + void (EFIAPI *waitforpacket)(void);
>>>>>>> + struct efi_simple_network_mode *mode;
>>>>>>> +};
>>>>>>> +
>>>>>>> +#define EFI_PXE_GUID \
>>>>>>> + EFI_GUID(0x03c4e603, 0xac28, 0x11d3, \
>>>>>>> + 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>>>>>> +
>>>>>>> +struct efi_pxe_packet {
>>>>>>> + u8 packet[1472];
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct efi_pxe_mode
>>>>>>> +{
>>>>>>> + u8 unused[52];
>>>>>>> + struct efi_pxe_packet dhcp_discover;
>>>>>>> + struct efi_pxe_packet dhcp_ack;
>>>>>>> + struct efi_pxe_packet proxy_offer;
>>>>>>> + struct efi_pxe_packet pxe_discover;
>>>>>>> + struct efi_pxe_packet pxe_reply;
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct efi_pxe {
>>>>>>> + u64 rev;
>>>>>>> + void (EFIAPI *start)(void);
>>>>>>> + void (EFIAPI *stop)(void);
>>>>>>> + void (EFIAPI *dhcp)(void);
>>>>>>> + void (EFIAPI *discover)(void);
>>>>>>> + void (EFIAPI *mftp)(void);
>>>>>>> + void (EFIAPI *udpwrite)(void);
>>>>>>> + void (EFIAPI *udpread)(void);
>>>>>>> + void (EFIAPI *setipfilter)(void);
>>>>>>> + void (EFIAPI *arp)(void);
>>>>>>> + void (EFIAPI *setparams)(void);
>>>>>>> + void (EFIAPI *setstationip)(void);
>>>>>>> + void (EFIAPI *setpackets)(void);
>>>>>>> + struct efi_pxe_mode *mode;
>>>>>>> +};
>>>>>>> +
>>>>>>> #endif
>>>>>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>>>>>> index 88b8149..8005454 100644
>>>>>>> --- a/include/efi_loader.h
>>>>>>> +++ b/include/efi_loader.h
>>>>>>> @@ -91,6 +91,12 @@ extern struct list_head efi_obj_list;
>>>>>>> int efi_disk_register(void);
>>>>>>> /* Called by bootefi to make GOP (graphical) interface available */
>>>>>>> int efi_gop_register(void);
>>>>>>> +/* Called by bootefi to make the network interface available */
>>>>>>> +int efi_net_register(void **handle);
>>>>>>> +
>>>>>>> +/* Called by networking code to memorize the dhcp ack package */
>>>>>>> +void efi_net_set_dhcp_ack(void *pkt, int len);
>>>>>>> +
>>>>>>> /*
>>>>>>> * Stub implementation for a protocol opener that just returns the handle as
>>>>>>> * interface
>>>>>>> @@ -157,5 +163,6 @@ static inline void ascii2unicode(u16 *unicode, char *ascii)
>>>>>>> static inline void efi_restore_gd(void) { }
>>>>>>> static inline void efi_set_bootdev(const char *dev, const char *devnr,
>>>>>>> const char *path) { }
>>>>>>> +static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
>>>>>>>
>>>>>>> #endif
>>>>>>> diff --git a/include/net.h b/include/net.h
>>>>>>> index 05800c4..5ee5929 100644
>>>>>>> --- a/include/net.h
>>>>>>> +++ b/include/net.h
>>>>>>> @@ -269,7 +269,7 @@ int eth_getenv_enetaddr_by_index(const char *base_name, int index,
>>>>>>> int eth_init(void); /* Initialize the device */
>>>>>>> int eth_send(void *packet, int length); /* Send a packet */
>>>>>>>
>>>>>>> -#ifdef CONFIG_API
>>>>>>> +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
>>>>>>> int eth_receive(void *packet, int length); /* Receive a packet*/
>>>>>>> extern void (*push_packet)(void *packet, int length);
>>>>>>> #endif
>>>>>>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>>>>>>> index 83e31f6..2a3849e 100644
>>>>>>> --- a/lib/efi_loader/Makefile
>>>>>>> +++ b/lib/efi_loader/Makefile
>>>>>>> @@ -11,3 +11,4 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>>>>>> obj-y += efi_memory.o
>>>>>>> obj-$(CONFIG_LCD) += efi_gop.o
>>>>>>> obj-$(CONFIG_PARTITIONS) += efi_disk.o
>>>>>>> +obj-$(CONFIG_NET) += efi_net.o
>>>>>>> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
>>>>>>> new file mode 100644
>>>>>>> index 0000000..a95ff3c
>>>>>>> --- /dev/null
>>>>>>> +++ b/lib/efi_loader/efi_net.c
>>>>>>> @@ -0,0 +1,314 @@
>>>>>>> +/*
>>>>>>> + * EFI application network access support
>>>>>>> + *
>>>>>>> + * Copyright (c) 2016 Alexander Graf
>>>>>>> + *
>>>>>>> + * SPDX-License-Identifier: GPL-2.0+
>>>>>>> + */
>>>>>>> +
>>>>>>> +#include <common.h>
>>>>>>> +#include <efi_loader.h>
>>>>>>> +#include <inttypes.h>
>>>>>>> +#include <lcd.h>
>>>>>>> +#include <malloc.h>
>>>>>>> +
>>>>>>> +DECLARE_GLOBAL_DATA_PTR;
>>>>>>> +
>>>>>>> +static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
>>>>>>> +static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
>>>>>>> +static struct efi_pxe_packet *dhcp_ack;
>>>>>>> +static bool new_rx_packet;
>>>>>>> +static void *new_tx_packet;
>>>>>>> +
>>>>>>> +struct efi_net_obj {
>>>>>>> + /* Generic EFI object parent class data */
>>>>>>> + struct efi_object parent;
>>>>>>> + /* EFI Interface callback struct for network */
>>>>>>> + struct efi_simple_network net;
>>>>>>> + struct efi_simple_network_mode net_mode;
>>>>>>> + /* Device path to the network adapter */
>>>>>>> + struct efi_device_path_file_path dp[2];
>>>>>>> + /* PXE struct to transmit dhcp data */
>>>>>>> + struct efi_pxe pxe;
>>>>>>> + struct efi_pxe_mode pxe_mode;
>>>>>>> +};
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p", this);
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p", this);
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
>>>>>>> + ulong extra_rx, ulong extra_tx)
>>>>>>> +{
>>>>>>> + struct efi_net_obj *netobj = container_of(this, struct efi_net_obj, net);
>>>>>>> + int ret;
>>>>>>> + EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
>>>>>>> +
>>>>>>> + eth_halt();
>>>>>>> + eth_set_current();
>>>>>>> + ret = eth_init();
>>>>>>> + if (ret < 0) {
>>>>>>> + eth_halt();
>>>>>>> + return EFI_EXIT(EFI_DEVICE_ERROR);
>>>>>>> + }
>>>>>>> +
>>>>>>> + netobj->net_mode.state = EFI_NETWORK_INITIALIZED;
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
>>>>>>> + int extended_verification)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p, %x", this, extended_verification);
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p", this);
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_receive_filters(
>>>>>>> + struct efi_simple_network *this, u32 enable, u32 disable,
>>>>>>> + int reset_mcast_filter, ulong mcast_filter_count,
>>>>>>> + struct efi_mac_address *mcast_filter)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
>>>>>>> + reset_mcast_filter, mcast_filter_count, mcast_filter);
>>>>>>> +
>>>>>>> + /* XXX Do we care? */
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_station_address(
>>>>>>> + struct efi_simple_network *this, int reset,
>>>>>>> + struct efi_mac_address *new_mac)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
>>>>>>> + int reset, ulong *stat_size,
>>>>>>> + void *stat_table)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
>>>>>>> + int ipv6,
>>>>>>> + struct efi_ip_address *ip,
>>>>>>> + struct efi_mac_address *mac)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
>>>>>>> + int read_write, ulong offset,
>>>>>>> + ulong buffer_size, char *buffer)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
>>>>>>> + buffer);
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
>>>>>>> + u32 *int_status, void **txbuf)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
>>>>>>> +
>>>>>>> + /* We send packets synchronously, so nothing is outstanding */
>>>>>>> + if (int_status)
>>>>>>> + *int_status = 0;
>>>>>>> + if (txbuf)
>>>>>>> + *txbuf = new_tx_packet;
>>>>>>> +
>>>>>>> + new_tx_packet = NULL;
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
>>>>>>> + ulong header_size, ulong buffer_size, void *buffer,
>>>>>>> + struct efi_mac_address *src_addr,
>>>>>>> + struct efi_mac_address *dest_addr, u16 *protocol)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
>>>>>>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>>>>>>> +
>>>>>>> + if (header_size) {
>>>>>>> + /* We would need to create the header if header_size != 0 */
>>>>>>> + return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>>>>> + }
>>>>>>> +
>>>>>>> + /*
>>>>>>> + * Some drivers need to have DMA aligned buffers, so if
>>>>>>> + * it's misaligned, let's use our own.
>>>>>>> + */
>>>>>>> + if ((ulong)buffer & (ARCH_DMA_MINALIGN - 1)) {
>>>>>>> + void *packet = memalign(ARCH_DMA_MINALIGN, buffer_size);
>>>>>>> + memcpy(packet, buffer, buffer_size);
>>>>>>> + net_send_packet(packet, buffer_size);
>>>>>>> + free(packet);
>>>>>>> + } else {
>>>>>>> + net_send_packet(buffer, buffer_size);
>>>>>>> + }
>>>>>>> +
>>>>>>> + new_tx_packet = buffer;
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static void efi_net_push(void *pkt, int len)
>>>>>>> +{
>>>>>>> + new_rx_packet = true;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
>>>>>>> + ulong *header_size, ulong *buffer_size, void *buffer,
>>>>>>> + struct efi_mac_address *src_addr,
>>>>>>> + struct efi_mac_address *dest_addr, u16 *protocol)
>>>>>>> +{
>>>>>>> + EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
>>>>>>> + buffer_size, buffer, src_addr, dest_addr, protocol);
>>>>>>> +
>>>>>>> + push_packet = efi_net_push;
>>>>>>> + /* XXX With device model this reads multiple packets, we only want 1 */
>>>>>>> + eth_rx();
>>>>>>> + push_packet = NULL;
>>>>>>> +
>>>>>>> + if (!new_rx_packet)
>>>>>>> + return EFI_EXIT(EFI_NOT_READY);
>>>>>>> +
>>>>>>> + if (*buffer_size < net_rx_packet_len) {
>>>>>>> + /* Packet doesn't fit, try again with bigger buf */
>>>>>>> + *buffer_size = net_rx_packet_len;
>>>>>>> + return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
>>>>>>> + }
>>>>>>> +
>>>>>>> + memcpy(buffer, net_rx_packet, net_rx_packet_len);
>>>>>>> + *buffer_size = net_rx_packet_len;
>>>>>>> + new_rx_packet = false;
>>>>>>> +
>>>>>>> + return EFI_EXIT(EFI_SUCCESS);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
>>>>>>> + void **protocol_interface, void *agent_handle,
>>>>>>> + void *controller_handle, uint32_t attributes)
>>>>>>> +{
>>>>>>> + struct efi_simple_network *net = handle;
>>>>>>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>>>>>>> +
>>>>>>> + *protocol_interface = netobj->dp;
>>>>>>> +
>>>>>>> + return EFI_SUCCESS;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol,
>>>>>>> + void **protocol_interface, void *agent_handle,
>>>>>>> + void *controller_handle, uint32_t attributes)
>>>>>>> +{
>>>>>>> + struct efi_simple_network *net = handle;
>>>>>>> + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net);
>>>>>>> +
>>>>>>> + *protocol_interface = &netobj->pxe;
>>>>>>> +
>>>>>>> + return EFI_SUCCESS;
>>>>>>> +}
>>>>>>> +
>>>>>>> +void efi_net_set_dhcp_ack(void *pkt, int len)
>>>>>>> +{
>>>>>>> + int maxsize = sizeof(*dhcp_ack);
>>>>>>> +
>>>>>>> + if (!dhcp_ack)
>>>>>>> + dhcp_ack = malloc(maxsize);
>>>>>>> +
>>>>>>> + memcpy(dhcp_ack, pkt, min(len, maxsize));
>>>>>>> +}
>>>>>>> +
>>>>>>> +/* This gets called from do_bootefi_exec(). */
>>>>>>> +int efi_net_register(void **handle)
>>>>>>> +{
>>>>>>> + struct efi_net_obj *netobj;
>>>>>>> + struct efi_device_path_file_path dp_net = {
>>>>>>> + .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
>>>>>>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
>>>>>>> + .dp.length = sizeof(dp_net),
>>>>>>> + .str = { 'N', 'e', 't' },
>>>>>>> + };
>>>>>>> + struct efi_device_path_file_path dp_end = {
>>>>>>> + .dp.type = DEVICE_PATH_TYPE_END,
>>>>>>> + .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
>>>>>>> + .dp.length = sizeof(dp_end),
>>>>>>> + };
>>>>>>> +
>>>>>>> + if (!eth_get_dev()) {
>>>>>>> + /* No eth device active, don't expose any */
>>>>>>> + return 0;
>>>>>>> + }
>>>>>>> +
>>>>>>> + /* We only expose the "active" eth device, so one is enough */
>>>>>>> + netobj = calloc(1, sizeof(*netobj));
>>>>>>> +
>>>>>>> + /* Fill in object data */
>>>>>>> + netobj->parent.protocols[0].guid = &efi_net_guid;
>>>>>>> + netobj->parent.protocols[0].open = efi_return_handle;
>>>>>>> + netobj->parent.protocols[1].guid = &efi_guid_device_path;
>>>>>>> + netobj->parent.protocols[1].open = efi_net_open_dp;
>>>>>>> + netobj->parent.protocols[2].guid = &efi_pxe_guid;
>>>>>>> + netobj->parent.protocols[2].open = efi_net_open_pxe;
>>>>>>> + netobj->parent.handle = &netobj->net;
>>>>>>> + netobj->net.start = efi_net_start;
>>>>>>> + netobj->net.stop = efi_net_stop;
>>>>>>> + netobj->net.initialize = efi_net_initialize;
>>>>>>> + netobj->net.reset = efi_net_reset;
>>>>>>> + netobj->net.shutdown = efi_net_shutdown;
>>>>>>> + netobj->net.receive_filters = efi_net_receive_filters;
>>>>>>> + netobj->net.station_address = efi_net_station_address;
>>>>>>> + netobj->net.statistics = efi_net_statistics;
>>>>>>> + netobj->net.mcastiptomac = efi_net_mcastiptomac;
>>>>>>> + netobj->net.nvdata = efi_net_nvdata;
>>>>>>> + netobj->net.get_status = efi_net_get_status;
>>>>>>> + netobj->net.transmit = efi_net_transmit;
>>>>>>> + netobj->net.receive = efi_net_receive;
>>>>>>> + netobj->net.mode = &netobj->net_mode;
>>>>>>> + netobj->net_mode.state = EFI_NETWORK_STARTED;
>>>>>>> + netobj->dp[0] = dp_net;
>>>>>>> + netobj->dp[1] = dp_end;
>>>>>>> + memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
>>>>>>> + netobj->net_mode.max_packet_size = PKTSIZE;
>>>>>>
>>>>>> Why is this statically created? Shouldn't it come from the U-Boot
>>>>>> ethernet tables dynamically when it is needed?
>>>>>
>>>>> The driver as is only exposes a single interface for the currently selected network device. My main goal behind this was pxe boot - where you usually load the payload from tftp and continue acting on the same interface later on.
>>>>>
>>>>> I guess we could create devices for all network devices as well. I remember that I wanted to only expose network if it's really necessary because of resource usage. But I don't remember exactly what resource the peoblem was otoh ;).
>>>>
>>>> I think in general (given that you are writing this code and this is
>>>> the best opportunity to get the design right) that things like this
>>>> should look up U-Boot tables rather than creating their own. So a
>>>> model where the device is scanned as needed seems better. Then if we
>>>> want to change the constraints later, e.g. devices appear that were
>>>> not previously present, then we can deal with that.
>>>>
>>>> I understand with block devices your point that there is no single
>>>> table of block devices. However, this support will be applied soon
>>>> (see u-boot-dm/master), even without driver model. I think we should
>>>> fix these things rather than work around them, as the code will be
>>>> more maintainable that way.
>>>
>>> I agree wholeheartedly :). The beauty of "proper" open source code is
>>> that you can actually modify the guts of it to make the code easier at
>>> the end of the day.
>>>
>>>> In this case I wonder if we should have an EFI device uclass, and
>>>> allow devices to have this as a child? It would allow for easy
>>>> enumeration and avoid another system-specific device table (something
>>>> that driver model is trying to reduce).
>>>
>>> I'm not 100% sure the EFI driver exposure is actually a child-parent
>>> relationship with the respective driver model objects. In Java speech
>>> it's more of an "interface" definition than a subclass.
>>
>> The parent/child relationship is how this is done in driver model. For
>> example, MMC devices (UCLASS_MMC) provide a block device interface, as
>> a child device in UCLASS_BLK.
>
>
> I'd have to take a closer look to really say something intelligible here.
OK - when you get a chance, take a look at driver/block/blk-uclass.c
in mainline - e.g. blk_get_devnum_by_type(). I think something similar
might work for EFI.
>
>>
>>> But that said, I think that it may still make sense to move it into the
>>> respective driver cores and just have the EFI structs part of the block
>>> device structs.
>>
>> But won't you have different types of drivers? E.g. video, network?
>
>
> We do have different types of drivers, that's why there are different files in lib/efi_loader :).
Right, so I don't really see how you can put (for example) a video
driver in a block device struct. I must be misunderstanding your idea
here.
>
>>
>>> However I don't consider it as very high priority at the moment.
>>> Functionally nothing should change from a payload point of view and the
>>> current code allows us to iron out bugs and have non-believers gain
>>> faith in the whole uEFI story without breaking non-uEFI code paths ;).
>>> And all of the actual interface code shouldn't change with a move into
>>> device objects.
>>>
>>> So how about we start to tackle this once the non-DM code is gone? That
>>> should simplify things for everyone.
>>
>> I think instead we should set this up so that it works nicely with DM.
>> The non-DM code will be around for a long time. I'm not sure how long.
>>
>> At present the EFI impl really doesn't use it at all. I'm not too
>> bothered about when, but I think it is worth looking at before too
>> long. I also suggest that we require DM with new features like this,
>> to encourage people to move.
>
>
> You might overestimate the power of uEFI support. Most people run away screaming rather than embrace uEFI when you mention it. My most important goal for now is to make sure that they do not run away. Forcing anything on them will cause that to happen though.
>
Just to be clear, what are you wanting to avoid forcing on them? I'm
really not following. My response here is that I'd like to see the EFI
support use driver model at some point, rather than inventing its own
tables. As I say, I'm not too worried about when. But I'd encourage
you to take a look at some point.
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [U-Boot, v2, 1/7] efi_loader: Add network access support
2016-05-06 19:01 ` [U-Boot] [PATCH v2 1/7] efi_loader: Add network access support Alexander Graf
2016-05-10 21:25 ` [U-Boot] [PATCH v3 " Alexander Graf
@ 2016-05-30 17:56 ` Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-30 17:56 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:01PM +0200, Alexander Graf wrote:
> We can now successfully boot EFI applications from disk, but users
> may want to also run them from a PXE setup.
>
> This patch implements rudimentary network support, allowing a payload
> to send and receive network packets.
>
> With this patch, I was able to successfully run grub2 with network
> access inside of QEMU's -M xlnx-ep108.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
Applied to u-boot/master, thanks!
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160530/f80d332f/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [U-Boot, v2, 2/7] bootp: Move vendor class identifier set to function
2016-05-06 19:01 ` [U-Boot] [PATCH v2 2/7] bootp: Move vendor class identifier set to function Alexander Graf
2016-05-06 19:28 ` Tom Rini
@ 2016-05-30 17:56 ` Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-30 17:56 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:02PM +0200, Alexander Graf wrote:
> Both the dhcp as well as the bootp case add vendor class identifier
> parameters into their packets. Let's move that into a separate function
> to make overlaying easier.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> Reviewed-by: Tom Rini <trini@konsulko.com>
Applied to u-boot/master, thanks!
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160530/e6d46df8/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [U-Boot, v2, 3/7] net: Move the VCI and client arch values to Kconfig
2016-05-06 19:01 ` [U-Boot] [PATCH v2 3/7] net: Move the VCI and client arch values to Kconfig Alexander Graf
2016-05-06 19:28 ` Tom Rini
@ 2016-05-30 17:56 ` Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-30 17:56 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:03PM +0200, Alexander Graf wrote:
> We have a bunch of boards that define their vendor class identifier and
> client archs in the board files or in the distro config. Move everything
> to the generic Kconfig options.
>
> We're missing the distinction between i386 and x86_64, as I couldn't find
> any config variable that would tell us the difference. Is that really important
> to people? I guess not, so I left it out.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> Reviewed-by: Tom Rini <trini@konsulko.com>
Applied to u-boot/master, thanks!
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160530/675d838e/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [U-Boot,v2,4/7] net: Fix client identifiers for ARM
2016-05-06 19:01 ` [U-Boot] [PATCH v2 4/7] net: Fix client identifiers for ARM Alexander Graf
2016-05-06 19:28 ` Tom Rini
@ 2016-05-30 17:56 ` Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-30 17:56 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:04PM +0200, Alexander Graf wrote:
> There are client identifiers specifically reserved for ARM U-Boot
> according to http://www.ietf.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml#processor-architecture.
>
> So let's actually make use of them rather than the bogus 0x100 that
> we emitted so far.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> Reviewed-by: Tom Rini <trini@konsulko.com>
Applied to u-boot/master, thanks!
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160530/d2b4386e/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [U-Boot, v2, 5/7] net: Move CONFIG_SPL_NET_VCI_STRING into Kconfig
2016-05-06 19:01 ` [U-Boot] [PATCH v2 5/7] net: Move CONFIG_SPL_NET_VCI_STRING into Kconfig Alexander Graf
2016-05-06 19:28 ` Tom Rini
@ 2016-05-30 17:57 ` Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-30 17:57 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:05PM +0200, Alexander Graf wrote:
> This patch also adds the SPL time VCI string into Kconfig.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> Reviewed-by: Tom Rini <trini@konsulko.com>
Applied to u-boot/master, thanks!
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160530/11e5f9a6/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [U-Boot,v2,7/7] distro: Add efi pxe boot code
2016-05-06 19:01 ` [U-Boot] [PATCH v2 7/7] distro: Add efi pxe boot code Alexander Graf
2016-05-06 19:28 ` Tom Rini
@ 2016-05-30 17:57 ` Tom Rini
1 sibling, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-30 17:57 UTC (permalink / raw)
To: u-boot
On Fri, May 06, 2016 at 09:01:07PM +0200, Alexander Graf wrote:
> Now that we can expose network functionality to EFI applications,
> the logical next step is to load them via pxe to execute them as
> well.
>
> This patch adds the necessary bits to the distro script to automatically
> load and execute EFI payloads. It identifies the dhcp client as a uEFI
> capable PXE client, hoping the server returns a tftp path to a workable
> EFI binary that we can then execute.
>
> To enable boards that don't come with a working device tree preloaded,
> this patch also adds support to load a device tree from the /dtb directory
> on the remote tftp server.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> Reviewed-by: Tom Rini <trini@konsulko.com>
Applied to u-boot/master, thanks!
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160530/aae95144/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [U-Boot] [U-Boot, v4, 6/7] net: Optionally use pxe client arch from variable
2016-05-12 13:51 ` [U-Boot] [PATCH v4 " Alexander Graf
@ 2016-05-30 17:57 ` Tom Rini
0 siblings, 0 replies; 30+ messages in thread
From: Tom Rini @ 2016-05-30 17:57 UTC (permalink / raw)
To: u-boot
On Thu, May 12, 2016 at 03:51:45PM +0200, Alexander Graf wrote:
> The client architecture that we pass to a dhcp server depends on the target
> payload that we want to execute. An EFI binary has a different client arch
> than a legacy binary or a u-boot binary.
>
> So let's parameterize the pxe client arch field to allow an override via
> the distro script, so that our efi boot path can tell the dhcp server that
> it's actually an efi firmware.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
Applied to u-boot/master, thanks!
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160530/4d3e178f/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2016-05-30 17:57 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-05-06 19:01 [U-Boot] [PATCH v2 0/7] efi_loader: PXE boot support Alexander Graf
2016-05-06 19:01 ` [U-Boot] [PATCH v2 1/7] efi_loader: Add network access support Alexander Graf
2016-05-10 21:25 ` [U-Boot] [PATCH v3 " Alexander Graf
2016-05-14 19:49 ` Simon Glass
2016-05-14 20:34 ` Alexander Graf
2016-05-16 13:24 ` Simon Glass
2016-05-16 18:06 ` Alexander Graf
2016-05-18 17:21 ` Simon Glass
2016-05-19 16:18 ` Alexander Graf
2016-05-19 16:34 ` Simon Glass
2016-05-30 17:56 ` [U-Boot] [U-Boot, v2, " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 2/7] bootp: Move vendor class identifier set to function Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-30 17:56 ` [U-Boot] [U-Boot, v2, " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 3/7] net: Move the VCI and client arch values to Kconfig Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-30 17:56 ` [U-Boot] [U-Boot, v2, " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 4/7] net: Fix client identifiers for ARM Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-30 17:56 ` [U-Boot] [U-Boot,v2,4/7] " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 5/7] net: Move CONFIG_SPL_NET_VCI_STRING into Kconfig Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-30 17:57 ` [U-Boot] [U-Boot, v2, " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 6/7] net: Optionally use pxe client arch from variable Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-12 13:51 ` [U-Boot] [PATCH v4 " Alexander Graf
2016-05-30 17:57 ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-05-06 19:01 ` [U-Boot] [PATCH v2 7/7] distro: Add efi pxe boot code Alexander Graf
2016-05-06 19:28 ` Tom Rini
2016-05-30 17:57 ` [U-Boot] [U-Boot,v2,7/7] " Tom Rini
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.