Module Name:    src
Committed By:   jmcneill
Date:           Sun Aug 26 21:28:18 UTC 2018

Modified Files:
        src/sys/stand/efiboot: Makefile.efiboot boot.c conf.c devopen.c
            efiboot.c efiboot.h efifile.c
Added Files:
        src/sys/stand/efiboot: efiblock.c efiblock.h efidev.c

Log Message:
Add support for booting kernels from FFS partitions.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 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.2 -r1.3 src/sys/stand/efiboot/boot.c \
    src/sys/stand/efiboot/efifile.c
cvs rdiff -u -r0 -r1.1 src/sys/stand/efiboot/efiblock.c \
    src/sys/stand/efiboot/efiblock.h src/sys/stand/efiboot/efidev.c
cvs rdiff -u -r1.3 -r1.4 src/sys/stand/efiboot/efiboot.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/stand/efiboot/Makefile.efiboot
diff -u src/sys/stand/efiboot/Makefile.efiboot:1.1 src/sys/stand/efiboot/Makefile.efiboot:1.2
--- src/sys/stand/efiboot/Makefile.efiboot:1.1	Fri Aug 24 02:01:06 2018
+++ src/sys/stand/efiboot/Makefile.efiboot	Sun Aug 26 21:28:18 2018
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.efiboot,v 1.1 2018/08/24 02:01:06 jmcneill Exp $
+# $NetBSD: Makefile.efiboot,v 1.2 2018/08/26 21:28:18 jmcneill Exp $
 
 S=		${.CURDIR}/../../..
 
@@ -22,7 +22,7 @@ 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 efifdt.c efifile.c
+SOURCES+=	efiboot.c efichar.c efidev.c efifdt.c efifile.c efiblock.c
 
 .PATH: ${S}/external/bsd/libfdt/dist
 CPPFLAGS+=	-I${S}/external/bsd/libfdt/dist
@@ -74,7 +74,7 @@ CPPFLAGS+= -D"devb2cdb(bno)=(bno)"
 #CPPFLAGS+= -DSUPPORT_DHCP
 #CPPFLAGS+= -DSUPPORT_NFS
 #CPPFLAGS+= -DSUPPORT_TFTP
-#CPPFLAGS+= -DLIBSA_ENABLE_LS_OP
+CPPFLAGS+= -DLIBSA_ENABLE_LS_OP
 
 #CPPFLAGS+= -DARP_DEBUG
 #CPPFLAGS+= -DBOOTP_DEBUG
@@ -93,7 +93,7 @@ SA_AS= library
 SAMISCMAKEFLAGS+="SA_USE_LOADFILE=yes"
 SAMISCMAKEFLAGS+="SA_USE_CREAD=yes"
 #SAMISCMAKEFLAGS+="SA_INCLUDE_NET=yes"
-#SAMISCMAKEFLAGS+="SA_ENABLE_LS_OP=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.1 src/sys/stand/efiboot/conf.c:1.2
--- src/sys/stand/efiboot/conf.c:1.1	Fri Aug 24 02:01:06 2018
+++ src/sys/stand/efiboot/conf.c	Sun Aug 26 21:28:18 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: conf.c,v 1.1 2018/08/24 02:01:06 jmcneill Exp $ */
+/* $NetBSD: conf.c,v 1.2 2018/08/26 21:28:18 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -28,9 +28,15 @@
 
 #include "efiboot.h"
 #include "efifile.h"
+#include "efiblock.h"
+
+#include <lib/libsa/stand.h>
+#include <lib/libsa/ufs.h>
+#include <lib/libsa/dosfs.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 },
 };
 int ndevs = __arraycount(devsw);
 
@@ -39,5 +45,8 @@ struct netif_driver *netif_drivers[] = {
 int n_netif_drivers = __arraycount(netif_drivers);
 
 struct fs_ops file_system[] = {
+	FS_OPS(ffsv1),
+	FS_OPS(ffsv2),
+	FS_OPS(dosfs),
 };
 int nfsys = __arraycount(file_system);
Index: src/sys/stand/efiboot/devopen.c
diff -u src/sys/stand/efiboot/devopen.c:1.1 src/sys/stand/efiboot/devopen.c:1.2
--- src/sys/stand/efiboot/devopen.c:1.1	Fri Aug 24 02:01:06 2018
+++ src/sys/stand/efiboot/devopen.c	Sun Aug 26 21:28:18 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: devopen.c,v 1.1 2018/08/24 02:01:06 jmcneill Exp $ */
+/* $NetBSD: devopen.c,v 1.2 2018/08/26 21:28:18 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -28,13 +28,16 @@
 
 #include "efiboot.h"
 #include "efifile.h"
+#include "efiblock.h"
 
 int
 devopen(struct open_file *f, const char *fname, char **file)
 {
 	int error;
 
-	error = efi_file_open(f, fname);
+	error = efi_block_open(f, fname, file);
+	if (error)
+		error = efi_file_open(f, fname);
 
 	return error;
 }
Index: src/sys/stand/efiboot/efiboot.h
diff -u src/sys/stand/efiboot/efiboot.h:1.1 src/sys/stand/efiboot/efiboot.h:1.2
--- src/sys/stand/efiboot/efiboot.h:1.1	Fri Aug 24 02:01:06 2018
+++ src/sys/stand/efiboot/efiboot.h	Sun Aug 26 21:28:18 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: efiboot.h,v 1.1 2018/08/24 02:01:06 jmcneill Exp $	*/
+/*	$NetBSD: efiboot.h,v 1.2 2018/08/26 21:28:18 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -46,6 +46,8 @@ void clearit(void);
 void print_banner(void);
 extern const struct boot_command commands[];
 void command_help(char *);
+int set_default_device(char *);
+char *get_default_device(void);
 
 /* console.c */
 int ischar(void);
@@ -63,6 +65,10 @@ size_t ucs2len(const CHAR16 *);
 int ucs2_to_utf8(const CHAR16 *, char **);
 int utf8_to_ucs2(const char *, CHAR16 **, size_t *);
 
+/* efidev.c */
+int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
+int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
+
 /* 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.2 src/sys/stand/efiboot/boot.c:1.3
--- src/sys/stand/efiboot/boot.c:1.2	Fri Aug 24 23:22:10 2018
+++ src/sys/stand/efiboot/boot.c	Sun Aug 26 21:28:18 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: boot.c,v 1.2 2018/08/24 23:22:10 jmcneill Exp $	*/
+/*	$NetBSD: boot.c,v 1.3 2018/08/26 21:28:18 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -28,6 +28,7 @@
  */
 
 #include "efiboot.h"
+#include "efiblock.h"
 
 #include <sys/bootblock.h>
 #include <sys/boot_flag.h>
@@ -40,9 +41,9 @@ extern const char bootprog_name[], bootp
 extern char twiddle_toggle;
 
 static const char * const names[][2] = {
-	{ "\\netbsd", "\\netbsd.gz" },
-	{ "\\onetbsd", "\\onetbsd.gz" },
-	{ "\\netbsd.old", "\\netbsd.old.gz" },
+	{ "netbsd", "netbsd.gz" },
+	{ "onetbsd", "onetbsd.gz" },
+	{ "netbsd.old", "netbsd.old.gz" },
 };
 
 #define NUMNAMES	__arraycount(names)
@@ -50,13 +51,19 @@ static const char * const names[][2] = {
 
 #define	DEFTIMEOUT	5
 
+static char default_device[32];
+
 void	command_boot(char *);
+void	command_dev(char *);
+void	command_ls(char *);
 void	command_reset(char *);
 void	command_version(char *);
 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" },
 	{ "version",	command_version,	"version" },
 	{ "help",	command_help,		"help|?" },
 	{ "?",		command_help,		NULL },
@@ -86,6 +93,27 @@ command_boot(char *arg)
 }
 
 void
+command_dev(char *arg)
+{
+	if (arg && *arg) {
+		set_default_device(arg);
+	} else {
+		efi_block_show();
+	}
+
+	if (strlen(default_device) > 0) {
+		printf("\n");
+		printf("default: %s\n", default_device);
+	}
+}
+
+void
+command_ls(char *arg)
+{
+	ls(arg);
+}
+
+void
 command_version(char *arg)
 {
 	char *ufirmware;
@@ -109,6 +137,21 @@ command_quit(char *arg)
 	efi_exit();
 }
 
+int
+set_default_device(char *arg)
+{
+	if (strlen(arg) + 1 > sizeof(default_device))
+		return ERANGE;
+	strcpy(default_device, arg);
+	return 0;
+}
+
+char *
+get_default_device(void)
+{
+	return default_device;
+}
+
 void
 print_banner(void)
 {
Index: src/sys/stand/efiboot/efifile.c
diff -u src/sys/stand/efiboot/efifile.c:1.2 src/sys/stand/efiboot/efifile.c:1.3
--- src/sys/stand/efiboot/efifile.c:1.2	Fri Aug 24 23:19:42 2018
+++ src/sys/stand/efiboot/efifile.c	Sun Aug 26 21:28:18 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: efifile.c,v 1.2 2018/08/24 23:19:42 jmcneill Exp $ */
+/* $NetBSD: efifile.c,v 1.3 2018/08/26 21:28:18 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -33,7 +33,6 @@
 
 static EFI_HANDLE *efi_vol;
 static UINTN efi_nvol;
-static int efi_bootvol = -1;
 
 static int
 efi_file_parse(const char *fname, UINTN *pvol, const char **pfile)
@@ -49,37 +48,20 @@ efi_file_parse(const char *fname, UINTN 
 			return ENXIO;
 		*pvol = vol;
 		*pfile = ep + 1;
-	} else if (efi_bootvol != -1) {
-		*pvol = efi_bootvol;
-		*pfile = fname;
-	} else {
-		return EINVAL;
+		return 0;
 	}
 
-	return 0;
+	return EINVAL;
 }
 
 void
 efi_file_system_probe(void)
 {
-	EFI_FILE_HANDLE fh;
 	EFI_STATUS status;
-	int n;
 
 	status = LibLocateHandle(ByProtocol, &FileSystemProtocol, NULL, &efi_nvol, &efi_vol);
 	if (EFI_ERROR(status))
 		return;
-
-	for (n = 0; n < efi_nvol; n++) {
-		fh = LibOpenRoot(efi_vol[n]);
-		if (!fh)
-			continue;
-
-		if (efi_bootdp && LibMatchDevicePaths(DevicePathFromHandle(efi_vol[n]), efi_bootdp) == TRUE)
-			efi_bootvol = n;
-		else if (efi_bootdp == NULL && efi_bootvol == -1)
-			efi_bootvol = n;
-	}
 }
 
 int
@@ -94,7 +76,7 @@ efi_file_open(struct open_file *f, ...)
 	CHAR16 *upath;
 	va_list ap;
 	size_t len;
-	int rv;
+	int rv, n;
 
 	va_start(ap, f);
 	fname = va_arg(ap, const char *);
@@ -121,7 +103,13 @@ efi_file_open(struct open_file *f, ...)
 	if (EFI_ERROR(status))
 		return status == EFI_NOT_FOUND ? ENOENT : EIO;
 
-	f->f_dev = &devsw[0];
+	for (n = 0; n < ndevs; n++)
+		if (strcmp(DEV_NAME(&devsw[n]), "efifile") == 0) {
+			f->f_dev = &devsw[n];
+			break;
+		}
+	if (n == ndevs)
+		return ENXIO;
 	f->f_devdata = f;
 	f->f_fsdata = srf;
 	f->f_flags = F_NODEV | F_READ;

Index: src/sys/stand/efiboot/efiboot.c
diff -u src/sys/stand/efiboot/efiboot.c:1.3 src/sys/stand/efiboot/efiboot.c:1.4
--- src/sys/stand/efiboot/efiboot.c:1.3	Fri Aug 24 23:21:56 2018
+++ src/sys/stand/efiboot/efiboot.c	Sun Aug 26 21:28:18 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: efiboot.c,v 1.3 2018/08/24 23:21:56 jmcneill Exp $ */
+/* $NetBSD: efiboot.c,v 1.4 2018/08/26 21:28:18 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -28,6 +28,7 @@
 
 #include "efiboot.h"
 #include "efifile.h"
+#include "efiblock.h"
 #include "efifdt.h"
 
 EFI_HANDLE efi_ih;
@@ -74,6 +75,7 @@ efi_main(EFI_HANDLE imageHandle, EFI_SYS
 
 	efi_fdt_probe();
 	efi_file_system_probe();
+	efi_block_probe();
 
 	boot();
 

Added files:

Index: src/sys/stand/efiboot/efiblock.c
diff -u /dev/null src/sys/stand/efiboot/efiblock.c:1.1
--- /dev/null	Sun Aug 26 21:28:18 2018
+++ src/sys/stand/efiboot/efiblock.c	Sun Aug 26 21:28:18 2018
@@ -0,0 +1,350 @@
+/* $NetBSD: efiblock.c,v 1.1 2018/08/26 21:28:18 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
+ * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
+ * 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.
+ */
+
+#define FSTYPENAMES
+
+#include <sys/param.h>
+
+#include "efiboot.h"
+#include "efiblock.h"
+
+static EFI_HANDLE *efi_block;
+static UINTN efi_nblock;
+
+static TAILQ_HEAD(, efi_block_dev) efi_block_devs = TAILQ_HEAD_INITIALIZER(efi_block_devs);
+
+static int
+efi_block_parse(const char *fname, struct efi_block_part **pbpart, char **pfile)
+{
+	struct efi_block_dev *bdev;
+	struct efi_block_part *bpart;
+	char pathbuf[PATH_MAX], *default_device, *ep = NULL;
+	const char *full_path;
+	intmax_t dev;
+	int part;
+
+	default_device = get_default_device();
+	if (strchr(fname, ':') == NULL) {
+		if (strlen(default_device) > 0) {
+			snprintf(pathbuf, sizeof(pathbuf), "%s:%s", default_device, fname);
+			full_path = pathbuf;
+			*pfile = __UNCONST(fname);
+		} else {
+			return EINVAL;
+		}
+	} else {
+		full_path = fname;
+		*pfile = strchr(fname, ':') + 1;
+	}
+
+	if (strncasecmp(full_path, "hd", 2) != 0)
+		return EINVAL;
+	dev = strtoimax(full_path + 2, &ep, 10);
+	if (dev < 0 || dev >= efi_nblock)
+		return ENXIO;
+	if (ep[0] < 'a' || ep[0] >= 'a' + MAXPARTITIONS || ep[1] != ':')
+		return EINVAL;
+	part = ep[0] - 'a';
+	TAILQ_FOREACH(bdev, &efi_block_devs, entries) {
+		if (bdev->index == dev) {
+			TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
+				if (bpart->index == part) {
+					*pbpart = bpart;
+					return 0;
+				}
+			}
+		}
+	}
+
+	return ENOENT;
+}
+
+static int
+efi_block_find_partitions_disklabel(struct efi_block_dev *bdev, uint32_t start, uint32_t size)
+{
+	struct efi_block_part *bpart;
+	struct disklabel d;
+	struct partition *p;
+	EFI_STATUS status;
+	EFI_LBA lba;
+	uint8_t *buf;
+	UINT32 sz;
+	int n;
+
+	sz = __MAX(sizeof(d), bdev->bio->Media->BlockSize);
+	sz = roundup(sz, bdev->bio->Media->BlockSize);
+	buf = AllocatePool(sz);
+	if (!buf)
+		return ENOMEM;
+
+	lba = ((start + LABELSECTOR) * DEV_BSIZE) / bdev->bio->Media->BlockSize;
+	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id, lba, sz, buf);
+	if (EFI_ERROR(status) || getdisklabel(buf, &d) != NULL) {
+		FreePool(buf);
+		return EIO;
+	}
+	FreePool(buf);
+
+	if (le32toh(d.d_magic) != DISKMAGIC || le32toh(d.d_magic2) != DISKMAGIC)
+		return EINVAL;
+	if (le16toh(d.d_npartitions) > MAXPARTITIONS)
+		return EINVAL;
+
+	for (n = 0; n < le16toh(d.d_npartitions); n++) {
+		p = &d.d_partitions[n];
+		switch (p->p_fstype) {
+		case FS_BSDFFS:
+		case FS_MSDOS:
+		case FS_BSDLFS:
+			break;
+		default:
+			continue;
+		}
+
+		bpart = alloc(sizeof(*bpart));
+		bpart->index = n;
+		bpart->bdev = bdev;
+		bpart->type = EFI_BLOCK_PART_DISKLABEL;
+		bpart->disklabel.secsize = le32toh(d.d_secsize);
+		bpart->disklabel.part = *p;
+		TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
+	}
+
+	return 0;
+}
+
+static int
+efi_block_find_partitions_mbr(struct efi_block_dev *bdev)
+{
+	struct mbr_sector mbr;
+	struct mbr_partition *mbr_part;
+	EFI_STATUS status;
+	uint8_t *buf;
+	UINT32 sz;
+	int n;
+
+	sz = __MAX(sizeof(mbr), bdev->bio->Media->BlockSize);
+	sz = roundup(sz, bdev->bio->Media->BlockSize);
+	buf = AllocatePool(sz);
+	if (!buf)
+		return ENOMEM;
+
+	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id, 0, sz, buf);
+	if (EFI_ERROR(status)) {
+		FreePool(buf);
+		return EIO;
+	}
+	memcpy(&mbr, buf, sizeof(mbr));
+	FreePool(buf);
+
+	if (le32toh(mbr.mbr_magic) != MBR_MAGIC)
+		return ENOENT;
+
+	for (n = 0; n < MBR_PART_COUNT; n++) {
+		mbr_part = &mbr.mbr_parts[n];
+		if (le32toh(mbr_part->mbrp_size) == 0)
+			continue;
+		if (mbr_part->mbrp_type == MBR_PTYPE_NETBSD) {
+			efi_block_find_partitions_disklabel(bdev, le32toh(mbr_part->mbrp_start), le32toh(mbr_part->mbrp_size));
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int
+efi_block_find_partitions(struct efi_block_dev *bdev)
+{
+	return efi_block_find_partitions_mbr(bdev);
+}
+
+void
+efi_block_probe(void)
+{
+	struct efi_block_dev *bdev;
+	EFI_BLOCK_IO *bio;
+	EFI_STATUS status;
+	uint16_t devindex = 0;
+	int depth = -1;
+	int n;
+
+	status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &efi_nblock, &efi_block);
+	if (EFI_ERROR(status))
+		return;
+
+	if (efi_bootdp) {
+		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
+		if (depth == 0)
+			depth = 1;
+	}
+
+	for (n = 0; n < efi_nblock; n++) {
+		status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_block[n], &BlockIoProtocol, (void **)&bio);
+		if (EFI_ERROR(status) || !bio->Media->MediaPresent)
+			continue;
+
+		if (bio->Media->LogicalPartition)
+			continue;
+
+		bdev = alloc(sizeof(*bdev));
+		bdev->index = devindex++;
+		bdev->bio = bio;
+		bdev->media_id = bio->Media->MediaId;
+		bdev->path = DevicePathFromHandle(efi_block[n]);
+		TAILQ_INIT(&bdev->partitions);
+		TAILQ_INSERT_TAIL(&efi_block_devs, bdev, entries);
+
+		if (depth > 0 && efi_device_path_ncmp(efi_bootdp, DevicePathFromHandle(efi_block[n]), depth) == 0) {
+			char devname[9];
+			snprintf(devname, sizeof(devname), "hd%ua", bdev->index);
+			set_default_device(devname);
+		}
+
+		efi_block_find_partitions(bdev);
+	}
+}
+
+void
+efi_block_show(void)
+{
+	struct efi_block_dev *bdev;
+	struct efi_block_part *bpart;
+	uint64_t size;
+	CHAR16 *path;
+
+	TAILQ_FOREACH(bdev, &efi_block_devs, entries) {
+		printf("hd%u (", bdev->index);
+
+		/* Size in MB */
+		size = ((bdev->bio->Media->LastBlock + 1) * bdev->bio->Media->BlockSize) / (1024 * 1024);
+		if (size >= 10000)
+			printf("%"PRIu64" GB", size / 1024);
+		else
+			printf("%"PRIu64" MB", size);
+		printf("): ");
+
+		path = DevicePathToStr(bdev->path);
+		Print(L"%s", path);
+		FreePool(path);
+
+		printf("\n");
+
+		TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
+			switch (bpart->type) {
+			case EFI_BLOCK_PART_DISKLABEL:
+				printf("  hd%u%c (", bdev->index, bpart->index + 'a');
+
+				/* Size in MB */
+				size = ((uint64_t)bpart->disklabel.secsize * bpart->disklabel.part.p_size) / (1024 * 1024);
+				if (size >= 10000)
+					printf("%"PRIu64" GB", size / 1024);
+				else
+					printf("%"PRIu64" MB", size);
+				printf("): ");
+
+				printf("%s\n", fstypenames[bpart->disklabel.part.p_fstype]);
+				break;
+			default:
+				break;
+			}
+		}
+	}
+}
+
+int
+efi_block_open(struct open_file *f, ...)
+{
+	struct efi_block_part *bpart;
+	const char *fname;
+	char **file;
+	char *path;
+	va_list ap;
+	int rv, n;
+	
+	va_start(ap, f);
+	fname = va_arg(ap, const char *);
+	file = va_arg(ap, char **);
+	va_end(ap);
+
+	rv = efi_block_parse(fname, &bpart, &path);
+	if (rv != 0)
+		return rv;
+
+	for (n = 0; n < ndevs; n++)
+		if (strcmp(DEV_NAME(&devsw[n]), "efiblock") == 0) {
+			f->f_dev = &devsw[n];
+			break;
+		}
+	if (n == ndevs)
+		return ENXIO;
+
+	f->f_devdata = bpart;
+
+	*file = path;
+
+	return 0;
+}
+
+int
+efi_block_close(struct open_file *f)
+{
+	return 0;
+}
+
+int
+efi_block_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
+{
+	struct efi_block_part *bpart = devdata;
+	EFI_STATUS status;
+
+	if (rw != F_READ)
+		return EROFS;
+
+	switch (bpart->type) {
+	case EFI_BLOCK_PART_DISKLABEL:
+		if (bpart->bdev->bio->Media->BlockSize != bpart->disklabel.secsize) {
+			printf("%s: unsupported block size %d (expected %d)\n", __func__,
+			    bpart->bdev->bio->Media->BlockSize, bpart->disklabel.secsize);
+			return EIO;
+		}
+		dblk += bpart->disklabel.part.p_offset;
+		break;
+	default:
+		return EINVAL;
+	}
+
+	status = uefi_call_wrapper(bpart->bdev->bio->ReadBlocks, 5, bpart->bdev->bio, bpart->bdev->media_id, dblk, size, buf);
+	if (EFI_ERROR(status))
+		return EIO;
+
+	*rsize = size;
+
+	return 0;
+}
Index: src/sys/stand/efiboot/efiblock.h
diff -u /dev/null src/sys/stand/efiboot/efiblock.h:1.1
--- /dev/null	Sun Aug 26 21:28:18 2018
+++ src/sys/stand/efiboot/efiblock.h	Sun Aug 26 21:28:18 2018
@@ -0,0 +1,71 @@
+/* $NetBSD: efiblock.h,v 1.1 2018/08/26 21:28:18 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
+ * 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 <sys/queue.h>
+#include <sys/bootblock.h>
+#include <sys/disklabel.h>
+
+enum efi_block_part_type {
+	EFI_BLOCK_PART_DISKLABEL,
+	EFI_BLOCK_PART_GPT
+};
+
+struct efi_block_part;
+
+struct efi_block_dev {
+	uint16_t index;
+	EFI_DEVICE_PATH *path;
+	EFI_BLOCK_IO *bio;
+	UINT32 media_id;
+	TAILQ_HEAD(, efi_block_part) partitions;
+
+	TAILQ_ENTRY(efi_block_dev) entries;
+};
+
+struct efi_block_part_disklabel {
+	uint32_t secsize;
+	struct partition part;
+};
+
+struct efi_block_part {
+	uint32_t index;
+	struct efi_block_dev *bdev;
+	enum efi_block_part_type type;
+	union {
+		struct efi_block_part_disklabel disklabel;
+	};
+
+	TAILQ_ENTRY(efi_block_part) entries;
+};
+
+void efi_block_probe(void);
+void efi_block_show(void);
+
+int efi_block_open(struct open_file *, ...);
+int efi_block_close(struct open_file *);
+int efi_block_strategy(void *, int, daddr_t, size_t, void *, size_t *);
Index: src/sys/stand/efiboot/efidev.c
diff -u /dev/null src/sys/stand/efiboot/efidev.c:1.1
--- /dev/null	Sun Aug 26 21:28:18 2018
+++ src/sys/stand/efiboot/efidev.c	Sun Aug 26 21:28:18 2018
@@ -0,0 +1,59 @@
+/*	$NetBSD: efidev.c,v 1.1 2018/08/26 21:28:18 jmcneill Exp $	*/
+/*	$OpenBSD: efiboot.c,v 1.28 2017/11/25 19:02:07 patrick Exp $	*/
+
+/*
+ * Copyright (c) 2015 YASUOKA Masahiko <yasu...@yasuoka.net>
+ *
+ * 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"
+
+/*
+ * Determine the number of nodes up to, but not including, the first
+ * node of the specified type.
+ */
+int
+efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype)
+{
+	int	i;
+
+	for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) {
+		if (DevicePathType(dp) == dptype)
+			return (i);
+	}
+
+	return (-1);
+}
+
+int
+efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn)
+{
+	int	 i, cmp;
+
+	for (i = 0; i < deptn; i++) {
+		if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb))
+			return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb))
+			    ? 0 : (IsDevicePathEnd(dpa))? -1 : 1);
+		cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb);
+		if (cmp)
+			return (cmp);
+		cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa));
+		if (cmp)
+			return (cmp);
+		dpa = NextDevicePathNode(dpa);
+		dpb = NextDevicePathNode(dpb);
+	}
+
+	return (0);
+}

Reply via email to