Module Name:    src
Committed By:   jmcneill
Date:           Mon Sep  3 00:04:02 UTC 2018

Modified Files:
        src/sys/stand/efiboot: Makefile.efiboot boot.c conf.c devopen.c
            efiboot.c efiboot.h version
Added Files:
        src/sys/stand/efiboot: dev_net.c efigetsecs.c efinet.c efinet.h
            efipxe.c

Log Message:
Add PXE support.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/stand/efiboot/Makefile.efiboot \
    src/sys/stand/efiboot/conf.c src/sys/stand/efiboot/devopen.c \
    src/sys/stand/efiboot/efiboot.h
cvs rdiff -u -r1.3 -r1.4 src/sys/stand/efiboot/boot.c
cvs rdiff -u -r0 -r1.1 src/sys/stand/efiboot/dev_net.c \
    src/sys/stand/efiboot/efinet.c src/sys/stand/efiboot/efinet.h \
    src/sys/stand/efiboot/efipxe.c
cvs rdiff -u -r1.4 -r1.5 src/sys/stand/efiboot/efiboot.c
cvs rdiff -u -r0 -r1.3 src/sys/stand/efiboot/efigetsecs.c
cvs rdiff -u -r1.1 -r1.2 src/sys/stand/efiboot/version

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/stand/efiboot/Makefile.efiboot
diff -u src/sys/stand/efiboot/Makefile.efiboot:1.2 src/sys/stand/efiboot/Makefile.efiboot:1.3
--- src/sys/stand/efiboot/Makefile.efiboot:1.2	Sun Aug 26 21:28:18 2018
+++ src/sys/stand/efiboot/Makefile.efiboot	Mon Sep  3 00:04:02 2018
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.efiboot,v 1.2 2018/08/26 21:28:18 jmcneill Exp $
+# $NetBSD: Makefile.efiboot,v 1.3 2018/09/03 00:04:02 jmcneill Exp $
 
 S=		${.CURDIR}/../../..
 
@@ -21,8 +21,8 @@ AFLAGS.start.S= ${${ACTIVE_CC} == "clang
 
 .PATH: ${EFIDIR}/gnuefi
 SOURCES=	crt0-efi-${GNUEFIARCH}.S reloc_${GNUEFIARCH}.c
-SOURCES+=	boot.c conf.c console.c devopen.c exec.c panic.c prompt.c
-SOURCES+=	efiboot.c efichar.c efidev.c efifdt.c efifile.c efiblock.c
+SOURCES+=	boot.c conf.c console.c dev_net.c devopen.c exec.c panic.c prompt.c
+SOURCES+=	efiboot.c efichar.c efidev.c efigetsecs.c efifdt.c efifile.c efiblock.c efinet.c efipxe.c
 
 .PATH: ${S}/external/bsd/libfdt/dist
 CPPFLAGS+=	-I${S}/external/bsd/libfdt/dist
@@ -68,12 +68,12 @@ CPPFLAGS+= -Wno-pointer-sign
 CPPFLAGS+= -DHEAP_VARIABLE
 #CPPFLAGS+= -DSUPPORT_CD9660
 CPPFLAGS+= -D"devb2cdb(bno)=(bno)"
-#CPPFLAGS+= -DSUPPORT_DOSFS
+CPPFLAGS+= -DSUPPORT_DOSFS
 #CPPFLAGS+= -DSUPPORT_EXT2FS
-#CPPFLAGS+= -DSUPPORT_BOOTP
-#CPPFLAGS+= -DSUPPORT_DHCP
+CPPFLAGS+= -DSUPPORT_BOOTP
+CPPFLAGS+= -DSUPPORT_DHCP
 #CPPFLAGS+= -DSUPPORT_NFS
-#CPPFLAGS+= -DSUPPORT_TFTP
+CPPFLAGS+= -DSUPPORT_TFTP
 CPPFLAGS+= -DLIBSA_ENABLE_LS_OP
 
 #CPPFLAGS+= -DARP_DEBUG
@@ -92,7 +92,7 @@ SAMISCCPPFLAGS+= -D"cdb2devb(bno)=(bno)"
 SA_AS= library
 SAMISCMAKEFLAGS+="SA_USE_LOADFILE=yes"
 SAMISCMAKEFLAGS+="SA_USE_CREAD=yes"
-#SAMISCMAKEFLAGS+="SA_INCLUDE_NET=yes"
+SAMISCMAKEFLAGS+="SA_INCLUDE_NET=yes"
 SAMISCMAKEFLAGS+="SA_ENABLE_LS_OP=yes"
 .include "${S}/lib/libsa/Makefile.inc"
 LIBSA= ${SALIB}
Index: src/sys/stand/efiboot/conf.c
diff -u src/sys/stand/efiboot/conf.c:1.2 src/sys/stand/efiboot/conf.c:1.3
--- src/sys/stand/efiboot/conf.c:1.2	Sun Aug 26 21:28:18 2018
+++ src/sys/stand/efiboot/conf.c	Mon Sep  3 00:04:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: conf.c,v 1.2 2018/08/26 21:28:18 jmcneill Exp $ */
+/* $NetBSD: conf.c,v 1.3 2018/09/03 00:04:02 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -33,20 +33,29 @@
 #include <lib/libsa/stand.h>
 #include <lib/libsa/ufs.h>
 #include <lib/libsa/dosfs.h>
+#include <lib/libsa/tftp.h>
+#include <lib/libsa/net.h>
+#include <lib/libsa/dev_net.h>
 
 struct devsw devsw[] = {
 	{ "efifile", efi_file_strategy, efi_file_open, efi_file_close, noioctl },
 	{ "efiblock", efi_block_strategy, efi_block_open, efi_block_close, noioctl },
+	{ "net", net_strategy, net_open, net_close, noioctl },
 };
 int ndevs = __arraycount(devsw);
 
 struct netif_driver *netif_drivers[] = {
+	&efinetif,
 };
 int n_netif_drivers = __arraycount(netif_drivers);
 
 struct fs_ops file_system[] = {
+	FS_OPS(null),
 	FS_OPS(ffsv1),
 	FS_OPS(ffsv2),
 	FS_OPS(dosfs),
 };
 int nfsys = __arraycount(file_system);
+
+struct fs_ops null_fs_ops = FS_OPS(null);
+struct fs_ops tftp_fs_ops = FS_OPS(tftp);
Index: src/sys/stand/efiboot/devopen.c
diff -u src/sys/stand/efiboot/devopen.c:1.2 src/sys/stand/efiboot/devopen.c:1.3
--- src/sys/stand/efiboot/devopen.c:1.2	Sun Aug 26 21:28:18 2018
+++ src/sys/stand/efiboot/devopen.c	Mon Sep  3 00:04:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: devopen.c,v 1.2 2018/08/26 21:28:18 jmcneill Exp $ */
+/* $NetBSD: devopen.c,v 1.3 2018/09/03 00:04:02 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -35,7 +35,11 @@ devopen(struct open_file *f, const char 
 {
 	int error;
 
-	error = efi_block_open(f, fname, file);
+	error = efi_net_open(f, fname, file);
+	file_system[0] = error ? null_fs_ops : tftp_fs_ops;
+
+	if (error)
+		error = efi_block_open(f, fname, file);
 	if (error)
 		error = efi_file_open(f, fname);
 
Index: src/sys/stand/efiboot/efiboot.h
diff -u src/sys/stand/efiboot/efiboot.h:1.2 src/sys/stand/efiboot/efiboot.h:1.3
--- src/sys/stand/efiboot/efiboot.h:1.2	Sun Aug 26 21:28:18 2018
+++ src/sys/stand/efiboot/efiboot.h	Mon Sep  3 00:04:02 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: efiboot.h,v 1.2 2018/08/26 21:28:18 jmcneill Exp $	*/
+/*	$NetBSD: efiboot.h,v 1.3 2018/09/03 00:04:02 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <[email protected]>
@@ -40,6 +40,10 @@ struct boot_command {
 	const char *c_help;
 };
 
+/* conf.c */
+extern struct fs_ops null_fs_ops;
+extern struct fs_ops tftp_fs_ops;
+
 /* boot.c */
 void boot(void);
 void clearit(void);
@@ -69,6 +73,18 @@ int utf8_to_ucs2(const char *, CHAR16 **
 int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
 int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
 
+/* efinet.c */
+int efi_net_open(struct open_file *, ...);
+void efi_net_probe(void);
+void efi_net_show(void);
+int efi_net_get_booted_interface_unit(void);
+extern struct netif_driver efinetif;
+
+/* efipxe.c */
+void efi_pxe_probe(void);
+void efi_pxe_show(void);
+bool efi_pxe_match_booted_interface(const EFI_MAC_ADDRESS *, UINT32);
+
 /* exec.c */
 int exec_netbsd(const char *, const char *);
 

Index: src/sys/stand/efiboot/boot.c
diff -u src/sys/stand/efiboot/boot.c:1.3 src/sys/stand/efiboot/boot.c:1.4
--- src/sys/stand/efiboot/boot.c:1.3	Sun Aug 26 21:28:18 2018
+++ src/sys/stand/efiboot/boot.c	Mon Sep  3 00:04:02 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: boot.c,v 1.3 2018/08/26 21:28:18 jmcneill Exp $	*/
+/*	$NetBSD: boot.c,v 1.4 2018/09/03 00:04:02 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <[email protected]>
@@ -63,7 +63,7 @@ void	command_quit(char *);
 const struct boot_command commands[] = {
 	{ "boot",	command_boot,		"boot [fsN:][filename] [args]\n     (ex. \"fs0:\\netbsd.old -s\"" },
 	{ "dev",	command_dev,		"dev" },
-	{ "ls",		command_ls,		"ls [hdNn:/path]\n" },
+	{ "ls",		command_ls,		"ls [hdNn:/path]" },
 	{ "version",	command_version,	"version" },
 	{ "help",	command_help,		"help|?" },
 	{ "?",		command_help,		NULL },
@@ -99,6 +99,8 @@ command_dev(char *arg)
 		set_default_device(arg);
 	} else {
 		efi_block_show();
+		efi_net_show();
+		efi_pxe_show();
 	}
 
 	if (strlen(default_device) > 0) {

Index: src/sys/stand/efiboot/efiboot.c
diff -u src/sys/stand/efiboot/efiboot.c:1.4 src/sys/stand/efiboot/efiboot.c:1.5
--- src/sys/stand/efiboot/efiboot.c:1.4	Sun Aug 26 21:28:18 2018
+++ src/sys/stand/efiboot/efiboot.c	Mon Sep  3 00:04:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: efiboot.c,v 1.4 2018/08/26 21:28:18 jmcneill Exp $ */
+/* $NetBSD: efiboot.c,v 1.5 2018/09/03 00:04:02 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -31,7 +31,7 @@
 #include "efiblock.h"
 #include "efifdt.h"
 
-EFI_HANDLE efi_ih;
+EFI_HANDLE IH;
 EFI_DEVICE_PATH *efi_bootdp;
 EFI_LOADED_IMAGE *efi_li;
 
@@ -47,7 +47,7 @@ efi_main(EFI_HANDLE imageHandle, EFI_SYS
 	EFI_STATUS status;
 	u_int sz = EFI_SIZE_TO_PAGES(heap_size);
 
-	efi_ih = imageHandle;
+	IH = imageHandle;
 
 	InitializeLib(imageHandle, systemTable);
 
@@ -76,6 +76,8 @@ efi_main(EFI_HANDLE imageHandle, EFI_SYS
 	efi_fdt_probe();
 	efi_file_system_probe();
 	efi_block_probe();
+	efi_pxe_probe();
+	efi_net_probe();
 
 	boot();
 
@@ -91,7 +93,7 @@ efi_cleanup(void)
 
 	LibMemoryMap(&nentries, &mapkey, &descsize, &descver);
 
-	status = uefi_call_wrapper(BS->ExitBootServices, 2, efi_ih, mapkey);
+	status = uefi_call_wrapper(BS->ExitBootServices, 2, IH, mapkey);
 	if (EFI_ERROR(status))
 		printf("WARNING: ExitBootServices failed\n");
 }
@@ -101,7 +103,7 @@ efi_exit(void)
 {
 	EFI_STATUS status;
 
-	status = uefi_call_wrapper(BS->Exit, 4, efi_ih, EFI_ABORTED, 0, NULL);
+	status = uefi_call_wrapper(BS->Exit, 4, IH, EFI_ABORTED, 0, NULL);
 	if (EFI_ERROR(status))
 		printf("WARNING: Exit failed\n");
 }

Index: src/sys/stand/efiboot/version
diff -u src/sys/stand/efiboot/version:1.1 src/sys/stand/efiboot/version:1.2
--- src/sys/stand/efiboot/version:1.1	Fri Aug 24 02:01:06 2018
+++ src/sys/stand/efiboot/version	Mon Sep  3 00:04:02 2018
@@ -1,7 +1,8 @@
-$NetBSD: version,v 1.1 2018/08/24 02:01:06 jmcneill Exp $
+$NetBSD: version,v 1.2 2018/09/03 00:04:02 jmcneill Exp $
 
 NOTE ANY CHANGES YOU MAKE TO THE EFI BOOTLOADER HERE.  The format of this
 file is important - make sure the entries are appended on end, last item
 is taken as the current.
 
 1.0:	Initial version.
+1.1:	Add PXE booting support.

Added files:

Index: src/sys/stand/efiboot/dev_net.c
diff -u /dev/null src/sys/stand/efiboot/dev_net.c:1.1
--- /dev/null	Mon Sep  3 00:04:02 2018
+++ src/sys/stand/efiboot/dev_net.c	Mon Sep  3 00:04:02 2018
@@ -0,0 +1,96 @@
+/*	$NetBSD: dev_net.c,v 1.1 2018/09/03 00:04:02 jmcneill Exp $	*/
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[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.
+ */
+
+#include "efiboot.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <lib/libsa/net.h>
+#include <lib/libsa/netif.h>
+#include <lib/libsa/bootparam.h>
+#include <lib/libsa/bootp.h>
+
+#include "dev_net.h"
+
+static int	net_socket = -1;
+
+int
+net_open(struct open_file *f, ...)
+{
+	va_list ap;
+	char *devname;
+	int error;
+
+	va_start(ap, f);
+	devname = va_arg(ap, char *);
+	va_end(ap);
+
+	if (net_socket < 0)
+		net_socket = netif_open(devname);
+	if (net_socket < 0)
+		return ENXIO;
+
+	if (myip.s_addr == INADDR_ANY) {
+		bootp(net_socket);
+
+		if (myip.s_addr == INADDR_ANY) {
+			error = EIO;
+			goto fail;
+		}
+
+		printf("boot: client ip: %s\n", inet_ntoa(myip));
+		printf("boot: server ip: %s\n", inet_ntoa(rootip));
+	}
+
+	f->f_devdata = &net_socket;
+
+	return 0;
+
+fail:
+	printf("net_open failed: %d\n", error);
+	netif_close(net_socket);
+	net_socket = -1;
+	return error;	
+}
+
+int
+net_close(struct open_file *f)
+{
+	f->f_devdata = NULL;
+
+	return 0;
+}
+
+int
+net_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
+{
+	return EIO;
+}
Index: src/sys/stand/efiboot/efinet.c
diff -u /dev/null src/sys/stand/efiboot/efinet.c:1.1
--- /dev/null	Mon Sep  3 00:04:02 2018
+++ src/sys/stand/efiboot/efinet.c	Mon Sep  3 00:04:02 2018
@@ -0,0 +1,529 @@
+/*	$NetBSD: efinet.c,v 1.1 2018/09/03 00:04:02 jmcneill 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>
+
+#include "efiboot.h"
+
+#include <lib/libsa/net.h>
+#include <lib/libsa/netif.h>
+#include <lib/libsa/dev_net.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;
+};
+#if notyet
+static struct btinfo_netif bi_netif;
+#endif
+
+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) && status != EFI_INVALID_PARAMETER) {
+		printf("net%d: cannot set rx. filters (status=%" PRIxMAX ")\n",
+		    nif->nif_unit, (uintmax_t)status);
+		return;
+	}
+
+#if notyet
+	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));
+	}
+#endif
+
+#ifdef EFINET_DEBUG
+	dump_mode(net->Mode);
+#endif
+
+	memcpy(desc->myea, net->Mode->PermanentAddress.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)
+{
+#if notyet
+	PCI_DEVICE_PATH *pci = (PCI_DEVICE_PATH *)dp;
+#endif
+	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;
+
+#if notyet
+	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;
+#endif
+	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->PermanentAddress, 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->PermanentAddress.Addr[x]);
+			}
+		}
+#if notyet
+		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);
+		}
+#endif
+		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;
+}
+
+int
+efi_net_open(struct open_file *f, ...)
+{
+	struct devdesc desc;
+	const char *fname;
+	char **file, *ep;
+	intmax_t dev;
+	va_list ap;
+	int n;
+
+	va_start(ap, f);
+	fname = va_arg(ap, const char *);
+	file = va_arg(ap, char **);
+	va_end(ap);
+
+	if (strncmp(fname, "net", 3) != 0)
+		return EINVAL;
+        dev = strtoimax(fname + 3, &ep, 10);
+        if (dev < 0 || dev >= efinetif.netif_nifs)
+                return ENXIO;
+	if (*ep != ':')
+		return ENXIO;
+
+        for (n = 0; n < ndevs; n++)
+                if (strcmp(DEV_NAME(&devsw[n]), "net") == 0) {
+                        f->f_dev = &devsw[n];
+                        break;
+                }
+        if (n == ndevs)
+                return ENXIO;
+
+	*file = ep + 1;
+
+	//try_bootp = 1;
+
+	memset(&desc, 0, sizeof(desc));
+	strlcpy(desc.d_name, "net", sizeof(desc.d_name));
+	desc.d_unit = dev;
+
+	return DEV_OPEN(f->f_dev)(f, &desc);
+}
Index: src/sys/stand/efiboot/efinet.h
diff -u /dev/null src/sys/stand/efiboot/efinet.h:1.1
--- /dev/null	Mon Sep  3 00:04:02 2018
+++ src/sys/stand/efiboot/efinet.h	Mon Sep  3 00:04:02 2018
@@ -0,0 +1,29 @@
+/*	$NetBSD: efinet.h,v 1.1 2018/09/03 00:04:02 jmcneill 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/stand/efiboot/efipxe.c
diff -u /dev/null src/sys/stand/efiboot/efipxe.c:1.1
--- /dev/null	Mon Sep  3 00:04:02 2018
+++ src/sys/stand/efiboot/efipxe.c	Mon Sep  3 00:04:02 2018
@@ -0,0 +1,141 @@
+/*	$NetBSD: efipxe.c,v 1.1 2018/09/03 00:04:02 jmcneill 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;
+}

Index: src/sys/stand/efiboot/efigetsecs.c
diff -u /dev/null src/sys/stand/efiboot/efigetsecs.c:1.3
--- /dev/null	Mon Sep  3 00:04:02 2018
+++ src/sys/stand/efiboot/efigetsecs.c	Mon Sep  3 00:04:02 2018
@@ -0,0 +1,81 @@
+/*	$NetBSD: efigetsecs.c,v 1.3 2018/09/03 00:04:02 jmcneill Exp $	*/
+
+/*
+ * Copyright (c) 2015 YASUOKA Masahiko <[email protected]>
+ * Copyright (c) 2018 Jared McNeill <[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 "efiboot.h"
+
+#include <lib/libsa/net.h>
+
+static EFI_EVENT getsecs_ev = 0;
+static satime_t getsecs_val = 0;
+
+static satime_t
+getsecs_rtc(void)
+{
+	static const int daytab[][14] = {
+	    { 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 },
+	    { 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+	};
+	EFI_TIME t;
+	satime_t r;
+	int y;
+#define isleap(_y) (((_y) % 4) == 0 && (((_y) % 100) != 0 || ((_y) % 400) == 0))
+
+	uefi_call_wrapper(RT->GetTime, 2, &t, NULL);
+
+	/* Calc days from UNIX epoch */
+	r = (t.Year - 1970) * 365;
+	for (y = 1970; y < t.Year; y++) {
+		if (isleap(y))
+			r++;
+	}
+	r += daytab[isleap(t.Year) ? 1 : 0][t.Month] + t.Day;
+
+	/* Calc secs */
+	r *= 60 * 60 * 24;
+	r += ((t.Hour * 60) + t.Minute) * 60 + t.Second;
+	if (-24 * 60 < t.TimeZone && t.TimeZone < 24 * 60)
+		r += t.TimeZone * 60;
+
+	return r;
+}
+
+static void
+getsecs_notify_func(EFI_EVENT ev, VOID *context)
+{
+	getsecs_val++;
+}
+
+satime_t
+getsecs(void)
+{
+	EFI_STATUS status;
+
+	if (getsecs_ev == 0) {
+		status = uefi_call_wrapper(BS->CreateEvent, 5, EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+		    getsecs_notify_func, 0, &getsecs_ev);
+		if (EFI_ERROR(status))
+			panic("%s: couldn't create event timer: 0x%lx", __func__, status);
+		status = uefi_call_wrapper(BS->SetTimer, 3, getsecs_ev, TimerPeriodic, 10000000);	/* 1s in "100ns" units */
+		if (EFI_ERROR(status))
+			panic("%s: couldn't start event timer: 0x%lx", __func__, status);
+		getsecs_val = getsecs_rtc();
+	}
+
+	return getsecs_val;
+}

Reply via email to