Module Name: src
Committed By: martin
Date: Wed Apr 11 14:51:43 UTC 2018
Modified Files:
src/sys/arch/i386/stand/efiboot [netbsd-8]: Makefile.efiboot boot.c
conf.c devopen.c devopen.h efiboot.c efiboot.h efidisk.c
Added Files:
src/sys/arch/i386/stand/efiboot [netbsd-8]: dev_net.c efinet.c efinet.h
efipxe.c
Log Message:
Pull up following revision(s) (requested by nonaka in ticket #739):
sys/arch/i386/stand/efiboot/efinet.h: revision 1.1
sys/arch/i386/stand/efiboot/efinet.c: revision 1.1
sys/arch/i386/stand/efiboot/conf.c: revision 1.2
sys/arch/i386/stand/efiboot/devopen.c: revision 1.5
sys/arch/i386/stand/efiboot/efidisk.c: revision 1.6
sys/arch/i386/stand/efiboot/devopen.h: revision 1.3
sys/arch/i386/stand/efiboot/efipxe.c: revision 1.1
sys/arch/i386/stand/efiboot/efiboot.c: revision 1.7
sys/arch/i386/stand/efiboot/boot.c: revision 1.10
sys/arch/i386/stand/efiboot/efiboot.h: revision 1.8
sys/arch/i386/stand/efiboot/Makefile.efiboot: revision 1.12
sys/arch/i386/stand/efiboot/dev_net.c: revision 1.1
efiboot: Added network boot support.
To generate a diff of this commit:
cvs rdiff -u -r1.9.2.2 -r1.9.2.3 \
src/sys/arch/i386/stand/efiboot/Makefile.efiboot
cvs rdiff -u -r1.5.2.4 -r1.5.2.5 src/sys/arch/i386/stand/efiboot/boot.c
cvs rdiff -u -r1.1 -r1.1.12.1 src/sys/arch/i386/stand/efiboot/conf.c
cvs rdiff -u -r0 -r1.1.2.2 src/sys/arch/i386/stand/efiboot/dev_net.c \
src/sys/arch/i386/stand/efiboot/efinet.c \
src/sys/arch/i386/stand/efiboot/efinet.h \
src/sys/arch/i386/stand/efiboot/efipxe.c
cvs rdiff -u -r1.1.12.3 -r1.1.12.4 src/sys/arch/i386/stand/efiboot/devopen.c
cvs rdiff -u -r1.1.12.1 -r1.1.12.2 src/sys/arch/i386/stand/efiboot/devopen.h
cvs rdiff -u -r1.4.10.2 -r1.4.10.3 src/sys/arch/i386/stand/efiboot/efiboot.c
cvs rdiff -u -r1.5.2.2 -r1.5.2.3 src/sys/arch/i386/stand/efiboot/efiboot.h
cvs rdiff -u -r1.1.12.4 -r1.1.12.5 src/sys/arch/i386/stand/efiboot/efidisk.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/i386/stand/efiboot/Makefile.efiboot
diff -u src/sys/arch/i386/stand/efiboot/Makefile.efiboot:1.9.2.2 src/sys/arch/i386/stand/efiboot/Makefile.efiboot:1.9.2.3
--- src/sys/arch/i386/stand/efiboot/Makefile.efiboot:1.9.2.2 Mon Apr 2 08:50:33 2018
+++ src/sys/arch/i386/stand/efiboot/Makefile.efiboot Wed Apr 11 14:51:43 2018
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.efiboot,v 1.9.2.2 2018/04/02 08:50:33 martin Exp $
+# $NetBSD: Makefile.efiboot,v 1.9.2.3 2018/04/11 14:51:43 martin Exp $
S= ${.CURDIR}/../../../../..
@@ -8,12 +8,12 @@ NEWVERSWHAT?= "EFI Boot"
AFLAGS.start.S= ${${ACTIVE_CC} == "clang":?-no-integrated-as:}
-SOURCES?= start.S conf.c devopen.c efiboot.c self_reloc.c
-LIBI386SRCS= boot.c biosdisk.c bootinfo.c bootinfo_biosgeom.c
-LIBI386SRCS+= bootmenu.c diskbuf.c exec.c menuutils.c
-LIBI386SRCS+= panic.c parseutils.c pread.c
-LIBI386SRCS+= efichar.c eficons.c efidelay.c efidev.c efidisk.c efidisk_ll.c
-LIBI386SRCS+= efigetsecs.c efimemory.c
+SOURCES= start.S boot.c conf.c devopen.c dev_net.c self_reloc.c panic.c
+SOURCES+= efiboot.c efichar.c eficons.c efidelay.c efidev.c
+SOURCES+= efidisk.c efidisk_ll.c efigetsecs.c efimemory.c
+SOURCES+= efinet.c efipxe.c
+LIBI386SRCS= biosdisk.c bootinfo.c bootinfo_biosgeom.c bootmenu.c
+LIBI386SRCS+= diskbuf.c exec.c menuutils.c parseutils.c pread.c
SRCS= ${SOURCES} ${EXTRA_SOURCES} ${LIBI386SRCS}
PIE_CFLAGS=
@@ -57,10 +57,22 @@ CPPFLAGS+= -DSUPPORT_CD9660
CPPFLAGS+= -D"devb2cdb(bno)=(bno)"
CPPFLAGS+= -DSUPPORT_DOSFS
CPPFLAGS+= -DSUPPORT_EXT2FS
+CPPFLAGS+= -DSUPPORT_BOOTP
+CPPFLAGS+= -DSUPPORT_DHCP
+CPPFLAGS+= -DSUPPORT_NFS
+#CPPFLAGS+= -DSUPPORT_TFTP
CPPFLAGS+= -DPASS_BIOSGEOM
CPPFLAGS+= -DBIOSDISK_DEFAULT_SECSIZE=2048 # for bootinfo_biosgeom.c
CPPFLAGS+= -DLIBSA_ENABLE_LS_OP
+#CPPFLAGS+= -DARP_DEBUG
+#CPPFLAGS+= -DBOOTP_DEBUG
+#CPPFLAGS+= -DNET_DEBUG
+#CPPFLAGS+= -DNETIF_DEBUG
+#CPPFLAGS+= -DNFS_DEBUG
+#CPPFLAGS+= -DRARP_DEBUG
+#CPPFLAGS+= -DRPC_DEBUG
+
EFIDIR= ${S}/external/bsd/gnu-efi/dist
GNUEFIARCH?= ${MACHINE_CPU}
CPPFLAGS+= -I${EFIDIR}/inc -I${EFIDIR}/inc/${GNUEFIARCH}
@@ -69,12 +81,12 @@ CPPFLAGS+= -I${EFIDIR}/inc/protocol
SAMISCCPPFLAGS+= -DLIBSA_PRINTF_LONGLONG_SUPPORT
SAMISCCPPFLAGS+= -DLIBSA_PRINTF_WIDTH_SUPPORT
SAMISCCPPFLAGS+= -D"cdb2devb(bno)=(bno)"
-SAMISCMAKEFLAGS+= SA_USE_CREAD=yes # Read compressed kernels
-SAMISCMAKEFLAGS+= SA_INCLUDE_NET=no # Netboot via TFTP, NFS
### find out what to use for libsa
SA_AS= library
SAMISCMAKEFLAGS+="SA_USE_LOADFILE=yes"
+SAMISCMAKEFLAGS+="SA_USE_CREAD=yes"
+SAMISCMAKEFLAGS+="SA_INCLUDE_NET=yes"
SAMISCMAKEFLAGS+="SA_ENABLE_LS_OP=yes"
.include "${S}/lib/libsa/Makefile.inc"
LIBSA= ${SALIB}
Index: src/sys/arch/i386/stand/efiboot/boot.c
diff -u src/sys/arch/i386/stand/efiboot/boot.c:1.5.2.4 src/sys/arch/i386/stand/efiboot/boot.c:1.5.2.5
--- src/sys/arch/i386/stand/efiboot/boot.c:1.5.2.4 Wed Apr 4 16:34:39 2018
+++ src/sys/arch/i386/stand/efiboot/boot.c Wed Apr 11 14:51:43 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: boot.c,v 1.5.2.4 2018/04/04 16:34:39 martin Exp $ */
+/* $NetBSD: boot.c,v 1.5.2.5 2018/04/11 14:51:43 martin Exp $ */
/*-
* Copyright (c) 2016 Kimihiro Nonaka <[email protected]>
@@ -182,6 +182,21 @@ parsebootfile(const char *fname, char **
}
static char *
+snprint_bootdev(char *buf, size_t bufsize, const char *devname, int unit,
+ int partition)
+{
+ static const char *no_partition_devs[] = { "esp", "net", "nfs", "tftp" };
+ int i;
+
+ for (i = 0; i < __arraycount(no_partition_devs); i++)
+ if (strcmp(devname, no_partition_devs[i]) == 0)
+ break;
+ snprintf(buf, bufsize, "%s%d%c", devname, unit,
+ i < __arraycount(no_partition_devs) ? '\0' : 'a' + partition);
+ return buf;
+}
+
+static char *
sprint_bootsel(const char *filename)
{
char *fsname, *devname;
@@ -191,8 +206,8 @@ sprint_bootsel(const char *filename)
if (parsebootfile(filename, &fsname, &devname, &unit,
&partition, &file) == 0) {
- snprintf(buf, sizeof(buf), "%s%d%c:%s", devname, unit,
- 'a' + partition, file);
+ snprintf(buf, sizeof(buf), "%s:%s", snprint_bootdev(buf,
+ sizeof(buf), devname, unit, partition), file);
return buf;
}
return "(invalid)";
@@ -276,7 +291,9 @@ boot(void)
if (!(boot_params.bp_flags & X86_BP_FLAGS_NOBOOTCONF)) {
#ifdef EFIBOOTCFG_FILENAME
- int rv = parsebootconf(EFIBOOTCFG_FILENAME);
+ int rv = EINVAL;
+ if (efi_bootdp_type != BOOT_DEVICE_TYPE_NET)
+ rv = parsebootconf(EFIBOOTCFG_FILENAME);
if (rv)
#endif
parsebootconf(BOOTCFG_FILENAME);
@@ -421,13 +438,15 @@ void
command_dev(char *arg)
{
static char savedevname[MAXDEVNAME + 1];
+ char buf[80];
char *fsname, *devname;
const char *file; /* dummy */
if (*arg == '\0') {
efi_disk_show();
- printf("default %s%d%c\n", default_devname, default_unit,
- 'a' + default_partition);
+ efi_net_show();
+ printf("default %s\n", snprint_bootdev(buf, sizeof(buf),
+ default_devname, default_unit, default_partition));
return;
}
Index: src/sys/arch/i386/stand/efiboot/conf.c
diff -u src/sys/arch/i386/stand/efiboot/conf.c:1.1 src/sys/arch/i386/stand/efiboot/conf.c:1.1.12.1
--- src/sys/arch/i386/stand/efiboot/conf.c:1.1 Tue Jan 24 11:09:14 2017
+++ src/sys/arch/i386/stand/efiboot/conf.c Wed Apr 11 14:51:43 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: conf.c,v 1.1 2017/01/24 11:09:14 nonaka Exp $ */
+/* $NetBSD: conf.c,v 1.1.12.1 2018/04/11 14:51:43 martin Exp $ */
/*
* Copyright (c) 1997
@@ -43,15 +43,52 @@
#ifdef SUPPORT_CD9660
#include <lib/libsa/cd9660.h>
#endif
+#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
+#include <lib/libsa/net.h>
+#include <lib/libsa/dev_net.h>
+#ifdef SUPPORT_NFS
+#include <lib/libsa/nfs.h>
+#endif
+#ifdef SUPPORT_TFTP
+#include <lib/libsa/tftp.h>
+#endif
+#endif
#include <biosdisk.h>
+#include "efinet.h"
struct devsw devsw[] = {
{ "disk", biosdisk_strategy, biosdisk_open, biosdisk_close, biosdisk_ioctl },
+ { "net", net_strategy, net_open, net_close, net_ioctl },
};
int ndevs = __arraycount(devsw);
+#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
+struct netif_driver *netif_drivers[] = {
+ &efinetif,
+};
+int n_netif_drivers = __arraycount(netif_drivers);
+#endif
+
struct fs_ops file_system[] = {
#ifdef SUPPORT_CD9660
+ FS_OPS(null),
+#endif
+ FS_OPS(null), FS_OPS(null),
+ FS_OPS(null), FS_OPS(null),
+#ifdef SUPPORT_EXT2FS
+ FS_OPS(null),
+#endif
+#ifdef SUPPORT_MINIXFS3
+ FS_OPS(null),
+#endif
+#ifdef SUPPORT_DOSFS
+ FS_OPS(null),
+#endif
+};
+int nfsys = __arraycount(file_system);
+
+struct fs_ops file_system_disk[] = {
+#ifdef SUPPORT_CD9660
FS_OPS(cd9660),
#endif
FS_OPS(ffsv1), FS_OPS(ffsv2),
@@ -66,4 +103,13 @@ struct fs_ops file_system[] = {
FS_OPS(dosfs),
#endif
};
-int nfsys = __arraycount(file_system);
+__CTASSERT(__arraycount(file_system) == __arraycount(file_system_disk));
+const int nfsys_disk = __arraycount(file_system_disk);
+
+struct fs_ops file_system_null = FS_OPS(null);
+#ifdef SUPPORT_NFS
+struct fs_ops file_system_nfs = FS_OPS(nfs);
+#endif
+#ifdef SUPPORT_TFTP
+struct fs_ops file_system_tftp = FS_OPS(tftp);
+#endif
Index: src/sys/arch/i386/stand/efiboot/devopen.c
diff -u src/sys/arch/i386/stand/efiboot/devopen.c:1.1.12.3 src/sys/arch/i386/stand/efiboot/devopen.c:1.1.12.4
--- src/sys/arch/i386/stand/efiboot/devopen.c:1.1.12.3 Wed Apr 4 16:34:39 2018
+++ src/sys/arch/i386/stand/efiboot/devopen.c Wed Apr 11 14:51:43 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: devopen.c,v 1.1.12.3 2018/04/04 16:34:39 martin Exp $ */
+/* $NetBSD: devopen.c,v 1.1.12.4 2018/04/11 14:51:43 martin Exp $ */
/*-
* Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -56,6 +56,8 @@
#include "efiboot.h"
+#include <lib/libsa/dev_net.h>
+
#include <biosdisk.h>
#include "devopen.h"
#include <bootinfo.h>
@@ -81,7 +83,14 @@ bios2dev(int biosdev, daddr_t sector, ch
*unit = biosdev & 0x7f;
- if (biosdev >= 0x80 + get_harddrives()) {
+ if (efi_bootdp_type == BOOT_DEVICE_TYPE_NET) {
+ *devname = "net";
+ *unit = efi_net_get_booted_interface_unit();
+ if (*unit < 0)
+ *unit = 0;
+ *partition = 0;
+ return;
+ } else if (biosdev >= 0x80 + get_harddrives()) {
*devname = "cd";
*unit -= get_harddrives();
} else
@@ -99,16 +108,90 @@ extern bool kernel_loaded;
int
devopen(struct open_file *f, const char *fname, char **file)
{
+#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
+ static const char *net_devnames[] = {
+#if defined(SUPPORT_NFS)
+ "nfs",
+#endif
+#if defined(SUPPORT_TFTP)
+ "tftp",
+#endif
+ };
+#endif
+ struct devdesc desc;
+ struct devsw *dev;
char *fsname, *devname;
int unit, partition;
int biosdev;
- int error;
+ int i, n, error;
error = parsebootfile(fname, &fsname, &devname, &unit, &partition,
(const char **) file);
if (error)
return error;
+ memcpy(file_system, file_system_disk, sizeof(*file_system) * nfsys);
+ nfsys = nfsys_disk;
+
+#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
+ for (i = 0; i < __arraycount(net_devnames); i++) {
+ if (strcmp(devname, net_devnames[i]) == 0) {
+ fsname = devname;
+ devname = "net";
+ break;
+ }
+ }
+#endif
+
+ for (i = 1; i < ndevs; i++) {
+ dev = &devsw[i];
+ if (strcmp(devname, DEV_NAME(dev)) == 0) {
+ if (strcmp(devname, "net") == 0) {
+ n = 0;
+#if defined(SUPPORT_NFS)
+ if (strcmp(fsname, "nfs") == 0) {
+ memcpy(&file_system[n++], &file_system_nfs,
+ sizeof(file_system_nfs));
+ } else
+#endif
+#if defined(SUPPORT_TFTP)
+ if (strcmp(fsname, "tftp") == 0) {
+ memcpy(&file_system[n++], &file_system_tftp,
+ sizeof(file_system_tftp));
+ } else
+#endif
+ {
+#if defined(SUPPORT_NFS)
+ memcpy(&file_system[n++], &file_system_nfs,
+ sizeof(file_system_nfs));
+#endif
+#if defined(SUPPORT_TFTP)
+ memcpy(&file_system[n++], &file_system_tftp,
+ sizeof(file_system_tftp));
+#endif
+ }
+ nfsys = n;
+
+ try_bootp = 1;
+ }
+
+ memset(&desc, 0, sizeof(desc));
+ strlcpy(desc.d_name, devname, sizeof(desc.d_name));
+ desc.d_unit = unit;
+
+ f->f_dev = dev;
+ if (!kernel_loaded) {
+ strncpy(bibp.bootpath, *file,
+ sizeof(bibp.bootpath));
+ BI_ADD(&bibp, BTINFO_BOOTPATH, sizeof(bibp));
+ }
+ return DEV_OPEN(f->f_dev)(f, &desc);
+ }
+ }
+
+ /*
+ * biosdisk
+ */
if (strcmp(devname, "esp") == 0) {
bios2dev(boot_biosdev, boot_biossector, &devname, &unit,
&partition);
Index: src/sys/arch/i386/stand/efiboot/devopen.h
diff -u src/sys/arch/i386/stand/efiboot/devopen.h:1.1.12.1 src/sys/arch/i386/stand/efiboot/devopen.h:1.1.12.2
--- src/sys/arch/i386/stand/efiboot/devopen.h:1.1.12.1 Wed Apr 4 16:34:39 2018
+++ src/sys/arch/i386/stand/efiboot/devopen.h Wed Apr 11 14:51:43 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: devopen.h,v 1.1.12.1 2018/04/04 16:34:39 martin Exp $ */
+/* $NetBSD: devopen.h,v 1.1.12.2 2018/04/11 14:51:43 martin Exp $ */
/*-
* Copyright (c) 2016 Kimihiro Nonaka <[email protected]>
@@ -28,7 +28,17 @@
extern int boot_biosdev;
extern daddr_t boot_biossector;
+extern const int nfsys_disk;
+extern struct fs_ops file_system_disk[];
+extern struct fs_ops file_system_nfs;
+extern struct fs_ops file_system_tftp;
+extern struct fs_ops file_system_null;
#define MAXDEVNAME 16
void bios2dev(int, daddr_t, char **, int *, int *);
+
+struct devdesc {
+ char d_name[MAXDEVNAME];
+ char d_unit;
+};
Index: src/sys/arch/i386/stand/efiboot/efiboot.c
diff -u src/sys/arch/i386/stand/efiboot/efiboot.c:1.4.10.2 src/sys/arch/i386/stand/efiboot/efiboot.c:1.4.10.3
--- src/sys/arch/i386/stand/efiboot/efiboot.c:1.4.10.2 Mon Apr 2 08:50:33 2018
+++ src/sys/arch/i386/stand/efiboot/efiboot.c Wed Apr 11 14:51:43 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: efiboot.c,v 1.4.10.2 2018/04/02 08:50:33 martin Exp $ */
+/* $NetBSD: efiboot.c,v 1.4.10.3 2018/04/11 14:51:43 martin Exp $ */
/*-
* Copyright (c) 2016 Kimihiro Nonaka <[email protected]>
@@ -34,7 +34,7 @@
EFI_HANDLE IH;
EFI_DEVICE_PATH *efi_bootdp;
-int efi_bootdp_type = BIOSDISK_TYPE_HD;
+enum efi_boot_device_type efi_bootdp_type = BOOT_DEVICE_TYPE_HD;
EFI_LOADED_IMAGE *efi_li;
uintptr_t efi_main_sp;
physaddr_t efi_loadaddr, efi_kernel_start;
@@ -79,12 +79,19 @@ efi_main(EFI_HANDLE imageHandle, EFI_SYS
for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
if (DevicePathType(dp) == MEDIA_DEVICE_PATH &&
DevicePathSubType(dp) == MEDIA_CDROM_DP) {
- efi_bootdp_type = BIOSDISK_TYPE_CD;
+ efi_bootdp_type = BOOT_DEVICE_TYPE_CD;
+ break;
+ }
+ if (DevicePathType(dp) == MESSAGING_DEVICE_PATH &&
+ DevicePathSubType(dp) == MSG_MAC_ADDR_DP) {
+ efi_bootdp_type = BOOT_DEVICE_TYPE_NET;
break;
}
}
efi_disk_probe();
+ efi_pxe_probe();
+ efi_net_probe();
status = uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0, 0, NULL);
if (EFI_ERROR(status))
Index: src/sys/arch/i386/stand/efiboot/efiboot.h
diff -u src/sys/arch/i386/stand/efiboot/efiboot.h:1.5.2.2 src/sys/arch/i386/stand/efiboot/efiboot.h:1.5.2.3
--- src/sys/arch/i386/stand/efiboot/efiboot.h:1.5.2.2 Mon Apr 2 08:50:33 2018
+++ src/sys/arch/i386/stand/efiboot/efiboot.h Wed Apr 11 14:51:43 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: efiboot.h,v 1.5.2.2 2018/04/02 08:50:33 martin Exp $ */
+/* $NetBSD: efiboot.h,v 1.5.2.3 2018/04/11 14:51:43 martin Exp $ */
/*-
* Copyright (c) 2016 Kimihiro Nonaka <[email protected]>
@@ -46,7 +46,11 @@ void print_banner(void);
/* efiboot.c */
extern EFI_HANDLE IH;
extern EFI_DEVICE_PATH *efi_bootdp;
-extern int efi_bootdp_type;
+extern enum efi_boot_device_type {
+ BOOT_DEVICE_TYPE_HD,
+ BOOT_DEVICE_TYPE_CD,
+ BOOT_DEVICE_TYPE_NET
+} efi_bootdp_type;
extern EFI_LOADED_IMAGE *efi_li;
extern uintptr_t efi_main_sp;
extern physaddr_t efi_loadaddr, efi_kernel_start;
@@ -80,5 +84,15 @@ void efi_memory_show_map(bool);
EFI_MEMORY_DESCRIPTOR *efi_memory_get_map(UINTN *, UINTN *, UINTN *, UINT32 *,
bool);
+/* efinet.c */
+void efi_net_probe(void);
+void efi_net_show(void);
+int efi_net_get_booted_interface_unit(void);
+
+/* efipxe.c */
+void efi_pxe_probe(void);
+void efi_pxe_show(void);
+bool efi_pxe_match_booted_interface(const EFI_MAC_ADDRESS *, UINT32);
+
/* panic.c */
__dead VOID Panic(IN CHAR16 *, ...);
Index: src/sys/arch/i386/stand/efiboot/efidisk.c
diff -u src/sys/arch/i386/stand/efiboot/efidisk.c:1.1.12.4 src/sys/arch/i386/stand/efiboot/efidisk.c:1.1.12.5
--- src/sys/arch/i386/stand/efiboot/efidisk.c:1.1.12.4 Wed Apr 4 16:34:39 2018
+++ src/sys/arch/i386/stand/efiboot/efidisk.c Wed Apr 11 14:51:43 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: efidisk.c,v 1.1.12.4 2018/04/04 16:34:39 martin Exp $ */
+/* $NetBSD: efidisk.c,v 1.1.12.5 2018/04/11 14:51:43 martin Exp $ */
/*-
* Copyright (c) 2016 Kimihiro Nonaka <[email protected]>
@@ -107,7 +107,7 @@ next:
FreePool(handles);
- if (efi_bootdp_type == BIOSDISK_TYPE_CD) {
+ if (efi_bootdp_type == BOOT_DEVICE_TYPE_CD) {
edi = TAILQ_FIRST(&efi_disklist);
if (edi != NULL && edi->bootdev) {
edi->type = BIOSDISK_TYPE_CD;
Added files:
Index: src/sys/arch/i386/stand/efiboot/dev_net.c
diff -u /dev/null src/sys/arch/i386/stand/efiboot/dev_net.c:1.1.2.2
--- /dev/null Wed Apr 11 14:51:43 2018
+++ src/sys/arch/i386/stand/efiboot/dev_net.c Wed Apr 11 14:51:43 2018
@@ -0,0 +1,3 @@
+/* $NetBSD: dev_net.c,v 1.1.2.2 2018/04/11 14:51:43 martin Exp $ */
+
+#include <lib/libsa/dev_net.c>
Index: src/sys/arch/i386/stand/efiboot/efinet.c
diff -u /dev/null src/sys/arch/i386/stand/efiboot/efinet.c:1.1.2.2
--- /dev/null Wed Apr 11 14:51:43 2018
+++ src/sys/arch/i386/stand/efiboot/efinet.c Wed Apr 11 14:51:43 2018
@@ -0,0 +1,480 @@
+/* $NetBSD: efinet.c,v 1.1.2.2 2018/04/11 14:51:43 martin Exp $ */
+
+/*-
+ * Copyright (c) 2001 Doug Rabson
+ * Copyright (c) 2002, 2006 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/stand/efi/libefi/efinet.c 321621 2017-07-27 15:06:34Z andrew $");
+#endif
+
+#include "efiboot.h"
+
+#include <lib/libsa/net.h>
+#include <lib/libsa/netif.h>
+
+#include <bootinfo.h>
+#include "devopen.h"
+
+#ifndef ETHER_ALIGN
+#define ETHER_ALIGN 2
+#endif
+
+#define ETHER_EXT_LEN (ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_ALIGN)
+
+#if defined(DEBUG) || defined(ARP_DEBUG) || defined(BOOTP_DEBUG) || \
+ defined(NET_DEBUG) || defined(NETIF_DEBUG) || defined(NFS_DEBUG) || \
+ defined(RARP_DEBUG) || defined(RPC_DEBUG)
+int debug = 1;
+#else
+int debug = 0;
+#endif
+
+extern bool kernel_loaded;
+
+struct efinetinfo {
+ EFI_SIMPLE_NETWORK *net;
+ bool bootdev;
+ size_t pktbufsz;
+ UINT8 *pktbuf;
+ struct {
+ int type;
+ u_int tag;
+ } bus;
+};
+static struct btinfo_netif bi_netif;
+
+static int efinet_match(struct netif *, void *);
+static int efinet_probe(struct netif *, void *);
+static void efinet_init(struct iodesc *, void *);
+static int efinet_get(struct iodesc *, void *, size_t, saseconds_t);
+static int efinet_put(struct iodesc *, void *, size_t);
+static void efinet_end(struct netif *);
+
+struct netif_driver efinetif = {
+ .netif_bname = "net",
+ .netif_match = efinet_match,
+ .netif_probe = efinet_probe,
+ .netif_init = efinet_init,
+ .netif_get = efinet_get,
+ .netif_put = efinet_put,
+ .netif_end = efinet_end,
+ .netif_ifs = NULL,
+ .netif_nifs = 0
+};
+
+#ifdef EFINET_DEBUG
+static void
+dump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
+{
+ int i;
+
+ printf("State = %x\n", mode->State);
+ printf("HwAddressSize = %u\n", mode->HwAddressSize);
+ printf("MediaHeaderSize = %u\n", mode->MediaHeaderSize);
+ printf("MaxPacketSize = %u\n", mode->MaxPacketSize);
+ printf("NvRamSize = %u\n", mode->NvRamSize);
+ printf("NvRamAccessSize = %u\n", mode->NvRamAccessSize);
+ printf("ReceiveFilterMask = %x\n", mode->ReceiveFilterMask);
+ printf("ReceiveFilterSetting = %u\n", mode->ReceiveFilterSetting);
+ printf("MaxMCastFilterCount = %u\n", mode->MaxMCastFilterCount);
+ printf("MCastFilterCount = %u\n", mode->MCastFilterCount);
+ printf("MCastFilter = {");
+ for (i = 0; i < mode->MCastFilterCount; i++)
+ printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
+ printf(" }\n");
+ printf("CurrentAddress = %s\n",
+ ether_sprintf(mode->CurrentAddress.Addr));
+ printf("BroadcastAddress = %s\n",
+ ether_sprintf(mode->BroadcastAddress.Addr));
+ printf("PermanentAddress = %s\n",
+ ether_sprintf(mode->PermanentAddress.Addr));
+ printf("IfType = %u\n", mode->IfType);
+ printf("MacAddressChangeable = %d\n", mode->MacAddressChangeable);
+ printf("MultipleTxSupported = %d\n", mode->MultipleTxSupported);
+ printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
+ printf("MediaPresent = %d\n", mode->MediaPresent);
+}
+#endif
+
+static int
+efinet_match(struct netif *nif, void *machdep_hint)
+{
+ struct devdesc *dev = machdep_hint;
+
+ if (dev->d_unit != nif->nif_unit)
+ return 0;
+
+ return 1;
+}
+
+static int
+efinet_probe(struct netif *nif, void *machdep_hint)
+{
+
+ return 0;
+}
+
+static int
+efinet_put(struct iodesc *desc, void *pkt, size_t len)
+{
+ struct netif *nif = desc->io_netif;
+ struct efinetinfo *eni = nif->nif_devdata;
+ EFI_SIMPLE_NETWORK *net;
+ EFI_STATUS status;
+ void *buf;
+
+ if (eni == NULL)
+ return -1;
+ net = eni->net;
+
+ status = uefi_call_wrapper(net->Transmit, 7, net, 0, (UINTN)len, pkt, NULL,
+ NULL, NULL);
+ if (EFI_ERROR(status))
+ return -1;
+
+ /* Wait for the buffer to be transmitted */
+ do {
+ buf = NULL; /* XXX Is this needed? */
+ status = uefi_call_wrapper(net->GetStatus, 3, net, NULL, &buf);
+ /*
+ * XXX EFI1.1 and the E1000 card returns a different
+ * address than we gave. Sigh.
+ */
+ } while (!EFI_ERROR(status) && buf == NULL);
+
+ /* XXX How do we deal with status != EFI_SUCCESS now? */
+ return EFI_ERROR(status) ? -1 : len;
+}
+
+static int
+efinet_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
+{
+ struct netif *nif = desc->io_netif;
+ struct efinetinfo *eni = nif->nif_devdata;
+ EFI_SIMPLE_NETWORK *net;
+ EFI_STATUS status;
+ UINTN bufsz, rsz;
+ time_t t;
+ char *buf, *ptr;
+ int ret = -1;
+
+ if (eni == NULL)
+ return -1;
+ net = eni->net;
+
+ if (eni->pktbufsz < net->Mode->MaxPacketSize + ETHER_EXT_LEN) {
+ bufsz = net->Mode->MaxPacketSize + ETHER_EXT_LEN;
+ buf = alloc(bufsz);
+ if (buf == NULL)
+ return -1;
+ dealloc(eni->pktbuf, eni->pktbufsz);
+ eni->pktbufsz = bufsz;
+ eni->pktbuf = buf;
+ }
+ ptr = eni->pktbuf + ETHER_ALIGN;
+
+ t = getsecs();
+ while ((getsecs() - t) < timeout) {
+ rsz = eni->pktbufsz;
+ status = uefi_call_wrapper(net->Receive, 7, net, NULL, &rsz, ptr,
+ NULL, NULL, NULL);
+ if (!EFI_ERROR(status)) {
+ rsz = min(rsz, len);
+ memcpy(pkt, ptr, rsz);
+ ret = (int)rsz;
+ break;
+ }
+ if (status != EFI_NOT_READY)
+ break;
+ }
+
+ return ret;
+}
+
+static void
+efinet_init(struct iodesc *desc, void *machdep_hint)
+{
+ struct netif *nif = desc->io_netif;
+ struct efinetinfo *eni;
+ EFI_SIMPLE_NETWORK *net;
+ EFI_STATUS status;
+ UINT32 mask;
+
+ if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) {
+ printf("Invalid network interface %d\n", nif->nif_unit);
+ return;
+ }
+
+ eni = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
+ nif->nif_devdata = eni;
+ net = eni->net;
+ if (net->Mode->State == EfiSimpleNetworkStopped) {
+ status = uefi_call_wrapper(net->Start, 1, net);
+ if (EFI_ERROR(status)) {
+ printf("net%d: cannot start interface (status=%"
+ PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status);
+ return;
+ }
+ }
+
+ if (net->Mode->State != EfiSimpleNetworkInitialized) {
+ status = uefi_call_wrapper(net->Initialize, 3, net, 0, 0);
+ if (EFI_ERROR(status)) {
+ printf("net%d: cannot init. interface (status=%"
+ PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status);
+ return;
+ }
+ }
+
+ mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+
+ status = uefi_call_wrapper(net->ReceiveFilters, 6, net, mask, 0, FALSE,
+ 0, NULL);
+ if (EFI_ERROR(status)) {
+ printf("net%d: cannot set rx. filters (status=%" PRIxMAX ")\n",
+ nif->nif_unit, (uintmax_t)status);
+ return;
+ }
+
+ if (!kernel_loaded) {
+ bi_netif.bus = eni->bus.type;
+ bi_netif.addr.tag = eni->bus.tag;
+ snprintf(bi_netif.ifname, sizeof(bi_netif.ifname), "net%d",
+ nif->nif_unit);
+ BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
+ }
+
+#ifdef EFINET_DEBUG
+ dump_mode(net->Mode);
+#endif
+
+ memcpy(desc->myea, net->Mode->CurrentAddress.Addr, 6);
+ desc->xid = 1;
+}
+
+static void
+efinet_end(struct netif *nif)
+{
+ struct efinetinfo *eni = nif->nif_devdata;
+ EFI_SIMPLE_NETWORK *net;
+
+ if (eni == NULL)
+ return;
+ net = eni->net;
+
+ uefi_call_wrapper(net->Shutdown, 1, net);
+}
+
+static bool
+efi_net_pci_probe(struct efinetinfo *eni, EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *pdp)
+{
+ PCI_DEVICE_PATH *pci = (PCI_DEVICE_PATH *)dp;
+ int bus = -1;
+
+ if (pdp != NULL &&
+ DevicePathType(pdp) == ACPI_DEVICE_PATH &&
+ (DevicePathSubType(pdp) == ACPI_DP ||
+ DevicePathSubType(pdp) == EXPANDED_ACPI_DP)) {
+ ACPI_HID_DEVICE_PATH *acpi = (ACPI_HID_DEVICE_PATH *)pdp;
+ /* PCI root bus */
+ if (acpi->HID == EISA_PNP_ID(0x0A08) ||
+ acpi->HID == EISA_PNP_ID(0x0A03)) {
+ bus = acpi->UID;
+ }
+ }
+ if (bus < 0)
+ return false;
+
+ eni->bus.type = BI_BUS_PCI;
+ eni->bus.tag = (bus & 0xff) << 8;
+ eni->bus.tag |= (pci->Device & 0x1f) << 3;
+ eni->bus.tag |= pci->Function & 0x7;
+ return true;
+}
+
+void
+efi_net_probe(void)
+{
+ struct efinetinfo *enis;
+ struct netif_dif *dif;
+ struct netif_stats *stats;
+ EFI_DEVICE_PATH *dp0, *dp, *pdp;
+ EFI_SIMPLE_NETWORK *net;
+ EFI_HANDLE *handles;
+ EFI_STATUS status;
+ UINTN i, nhandles;
+ int nifs;
+ bool found;
+
+ status = LibLocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL,
+ &nhandles, &handles);
+ if (EFI_ERROR(status) || nhandles == 0)
+ return;
+
+ enis = alloc(nhandles * sizeof(*enis));
+ if (enis == NULL)
+ return;
+ memset(enis, 0, nhandles * sizeof(*enis));
+
+ nifs = 0;
+ for (i = 0; i < nhandles; i++) {
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
+ &DevicePathProtocol, (void **)&dp0);
+ if (EFI_ERROR(status))
+ continue;
+
+ found = false;
+ for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
+ if (DevicePathType(dp) == MESSAGING_DEVICE_PATH &&
+ DevicePathSubType(dp) == MSG_MAC_ADDR_DP) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+
+ status = uefi_call_wrapper(BS->OpenProtocol, 6, handles[i],
+ &SimpleNetworkProtocol, (void **)&net, IH, NULL,
+ EFI_OPEN_PROTOCOL_EXCLUSIVE);
+ if (EFI_ERROR(status)) {
+ printf("Unable to open network interface %" PRIuMAX
+ " for exclusive access: %" PRIxMAX "\n",
+ (uintmax_t)i, (uintmax_t)status);
+ }
+
+ found = false;
+ for (pdp = NULL, dp = dp0;
+ !IsDevicePathEnd(dp);
+ pdp = dp, dp = NextDevicePathNode(dp)) {
+ if (DevicePathType(dp) == HARDWARE_DEVICE_PATH) {
+ if (DevicePathSubType(dp) == HW_PCI_DP)
+ found = efi_net_pci_probe(&enis[nifs],
+ dp, pdp);
+ break;
+ }
+ }
+ if (found) {
+ enis[nifs].net = net;
+ enis[nifs].bootdev = efi_pxe_match_booted_interface(
+ &net->Mode->CurrentAddress, net->Mode->HwAddressSize);
+ enis[nifs].pktbufsz = net->Mode->MaxPacketSize +
+ ETHER_EXT_LEN;
+ enis[nifs].pktbuf = alloc(enis[nifs].pktbufsz);
+ if (enis[nifs].pktbuf == NULL) {
+ while (i-- > 0) {
+ dealloc(enis[i].pktbuf, enis[i].pktbufsz);
+ if (i == 0)
+ break;
+ }
+ dealloc(enis, nhandles * sizeof(*enis));
+ FreePool(handles);
+ return;
+ }
+ nifs++;
+ }
+ }
+
+ FreePool(handles);
+
+ if (nifs == 0)
+ return;
+
+ efinetif.netif_ifs = alloc(nifs * sizeof(*dif));
+ stats = alloc(nifs * sizeof(*stats));
+ if (efinetif.netif_ifs == NULL || stats == NULL) {
+ if (efinetif.netif_ifs != NULL) {
+ dealloc(efinetif.netif_ifs, nifs * sizeof(*dif));
+ efinetif.netif_ifs = NULL;
+ }
+ if (stats != NULL)
+ dealloc(stats, nifs * sizeof(*stats));
+ for (i = 0; i < nifs; i++)
+ dealloc(enis[i].pktbuf, enis[i].pktbufsz);
+ dealloc(enis, nhandles * sizeof(*enis));
+ return;
+ }
+ memset(efinetif.netif_ifs, 0, nifs * sizeof(*dif));
+ memset(stats, 0, nifs * sizeof(*stats));
+ efinetif.netif_nifs = nifs;
+
+ for (i = 0; i < nifs; i++) {
+ dif = &efinetif.netif_ifs[i];
+ dif->dif_unit = i;
+ dif->dif_nsel = 1;
+ dif->dif_stats = &stats[i];
+ dif->dif_private = &enis[i];
+ }
+}
+
+void
+efi_net_show(void)
+{
+ const struct netif_dif *dif;
+ const struct efinetinfo *eni;
+ EFI_SIMPLE_NETWORK *net;
+ int i;
+
+ for (i = 0; i < efinetif.netif_nifs; i++) {
+ dif = &efinetif.netif_ifs[i];
+ eni = dif->dif_private;
+ net = eni->net;
+
+ printf("net net%d", dif->dif_unit);
+ if (net->Mode != NULL) {
+ for (UINT32 x = 0; x < net->Mode->HwAddressSize; x++) {
+ printf("%c%02x", x == 0 ? ' ' : ':',
+ net->Mode->CurrentAddress.Addr[x]);
+ }
+ }
+ if (eni->bus.type == BI_BUS_PCI) {
+ printf(" pci%d,%d,%d", (eni->bus.tag >> 8) & 0xff,
+ (eni->bus.tag >> 3) & 0x1f, eni->bus.tag & 0x7);
+ }
+ if (eni->bootdev)
+ printf(" pxeboot");
+ printf("\n");
+ }
+}
+
+int
+efi_net_get_booted_interface_unit(void)
+{
+ const struct netif_dif *dif;
+ const struct efinetinfo *eni;
+ int i;
+
+ for (i = 0; i < efinetif.netif_nifs; i++) {
+ dif = &efinetif.netif_ifs[i];
+ eni = dif->dif_private;
+ if (eni->bootdev)
+ return dif->dif_unit;
+ }
+ return -1;
+}
Index: src/sys/arch/i386/stand/efiboot/efinet.h
diff -u /dev/null src/sys/arch/i386/stand/efiboot/efinet.h:1.1.2.2
--- /dev/null Wed Apr 11 14:51:43 2018
+++ src/sys/arch/i386/stand/efiboot/efinet.h Wed Apr 11 14:51:43 2018
@@ -0,0 +1,29 @@
+/* $NetBSD: efinet.h,v 1.1.2.2 2018/04/11 14:51:43 martin Exp $ */
+
+/*-
+ * Copyright (c) 2018 Kimihiro Nonaka <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+extern struct netif_driver efinetif;
Index: src/sys/arch/i386/stand/efiboot/efipxe.c
diff -u /dev/null src/sys/arch/i386/stand/efiboot/efipxe.c:1.1.2.2
--- /dev/null Wed Apr 11 14:51:43 2018
+++ src/sys/arch/i386/stand/efiboot/efipxe.c Wed Apr 11 14:51:43 2018
@@ -0,0 +1,141 @@
+/* $NetBSD: efipxe.c,v 1.1.2.2 2018/04/11 14:51:43 martin Exp $ */
+/* $OpenBSD: efipxe.c,v 1.3 2018/01/30 20:19:06 naddy Exp $ */
+
+/*
+ * Copyright (c) 2017 Patrick Wildt <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/queue.h>
+
+#include "efiboot.h"
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <lib/libsa/bootp.h> /* for VM_RFC1048 */
+
+
+struct efipxeinfo {
+ TAILQ_ENTRY(efipxeinfo) list;
+
+ EFI_PXE_BASE_CODE *pxe;
+ EFI_SIMPLE_NETWORK *net;
+ EFI_MAC_ADDRESS mac;
+ UINT32 addrsz;
+};
+TAILQ_HEAD(efipxeinfo_lh, efipxeinfo);
+static struct efipxeinfo_lh efi_pxelist;
+static int nefipxes;
+
+void
+efi_pxe_probe(void)
+{
+ struct efipxeinfo *epi;
+ EFI_PXE_BASE_CODE *pxe;
+ EFI_DEVICE_PATH *dp;
+ EFI_SIMPLE_NETWORK *net;
+ EFI_HANDLE *handles;
+ EFI_STATUS status;
+ UINTN nhandles;
+ int i, depth;
+ bool found;
+
+ TAILQ_INIT(&efi_pxelist);
+
+ status = LibLocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL,
+ &nhandles, &handles);
+ if (EFI_ERROR(status))
+ return;
+
+ for (i = 0; i < nhandles; i++) {
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
+ &DevicePathProtocol, (void **)&dp);
+ if (EFI_ERROR(status))
+ continue;
+
+ depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
+ if (efi_device_path_ncmp(efi_bootdp, dp, depth))
+ continue;
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
+ &PxeBaseCodeProtocol, (void **)&pxe);
+ if (EFI_ERROR(status))
+ continue;
+
+ if (pxe->Mode == NULL ||
+ (!pxe->Mode->DhcpAckReceived && !pxe->Mode->PxeReplyReceived))
+ continue;
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
+ &SimpleNetworkProtocol, (void **)&net);
+ if (EFI_ERROR(status))
+ continue;
+
+ if (net->Mode == NULL)
+ continue;
+
+ found = false;
+ TAILQ_FOREACH(epi, &efi_pxelist, list) {
+ if (net->Mode->HwAddressSize == epi->addrsz &&
+ memcmp(net->Mode->CurrentAddress.Addr, epi->mac.Addr,
+ net->Mode->HwAddressSize) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ epi = alloc(sizeof(*epi));
+ if (epi == NULL)
+ continue;
+
+ memset(epi, 0, sizeof(*epi));
+ epi->pxe = pxe;
+ epi->net = net;
+ epi->addrsz = net->Mode->HwAddressSize;
+ memcpy(epi->mac.Addr, net->Mode->CurrentAddress.Addr, epi->addrsz);
+
+ TAILQ_INSERT_TAIL(&efi_pxelist, epi, list);
+ nefipxes++;
+ }
+}
+
+void
+efi_pxe_show(void)
+{
+ const struct efipxeinfo *epi;
+ UINT32 i, n;
+
+ n = 0;
+ TAILQ_FOREACH(epi, &efi_pxelist, list) {
+ printf("pxe pxe%d", n++);
+ for (i = 0; i < epi->addrsz; i++)
+ printf("%c%02x", i == 0 ? ' ' : ':', epi->mac.Addr[i]);
+ printf("\n");
+ }
+}
+
+bool
+efi_pxe_match_booted_interface(const EFI_MAC_ADDRESS *mac, UINT32 addrsz)
+{
+ const struct efipxeinfo *epi;
+
+ TAILQ_FOREACH(epi, &efi_pxelist, list) {
+ if (addrsz == epi->addrsz &&
+ memcmp(mac->Addr, epi->mac.Addr, addrsz) == 0)
+ return true;
+ }
+ return false;
+}