From d8588d75972945c80d72025ebda443440db58c9c Mon Sep 17 00:00:00 2001 From: jmcneill Date: Sun, 26 Aug 2018 21:28:18 +0000 Subject: [PATCH] Add support for booting kernels from FFS partitions. --- sys/stand/efiboot/Makefile.efiboot | 8 +- sys/stand/efiboot/boot.c | 51 ++++- sys/stand/efiboot/conf.c | 11 +- sys/stand/efiboot/devopen.c | 7 +- sys/stand/efiboot/efiblock.c | 350 +++++++++++++++++++++++++++++ sys/stand/efiboot/efiblock.h | 71 ++++++ sys/stand/efiboot/efiboot.c | 4 +- sys/stand/efiboot/efiboot.h | 8 +- sys/stand/efiboot/efidev.c | 59 +++++ sys/stand/efiboot/efifile.c | 34 +-- 10 files changed, 567 insertions(+), 36 deletions(-) create mode 100644 sys/stand/efiboot/efiblock.c create mode 100644 sys/stand/efiboot/efiblock.h create mode 100644 sys/stand/efiboot/efidev.c diff --git a/sys/stand/efiboot/Makefile.efiboot b/sys/stand/efiboot/Makefile.efiboot index a0696f6254f4..736aec00c478 100644 --- a/sys/stand/efiboot/Makefile.efiboot +++ b/sys/stand/efiboot/Makefile.efiboot @@ -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":?-no-integrated-as:} .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} diff --git a/sys/stand/efiboot/boot.c b/sys/stand/efiboot/boot.c index 42ce96da3265..054ec68c361a 100644 --- a/sys/stand/efiboot/boot.c +++ b/sys/stand/efiboot/boot.c @@ -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 @@ -28,6 +28,7 @@ */ #include "efiboot.h" +#include "efiblock.h" #include #include @@ -40,9 +41,9 @@ extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[]; 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 }, @@ -85,6 +92,27 @@ command_boot(char *arg) exec_netbsd(*fname ? fname : DEFFILENAME, bootargs); } +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) { @@ -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) { diff --git a/sys/stand/efiboot/conf.c b/sys/stand/efiboot/conf.c index dd56b6f5658e..893e0422244c 100644 --- a/sys/stand/efiboot/conf.c +++ b/sys/stand/efiboot/conf.c @@ -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 @@ -28,9 +28,15 @@ #include "efiboot.h" #include "efifile.h" +#include "efiblock.h" + +#include +#include +#include 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); diff --git a/sys/stand/efiboot/devopen.c b/sys/stand/efiboot/devopen.c index 1f6312b3c3fa..f2ab07c6f5b5 100644 --- a/sys/stand/efiboot/devopen.c +++ b/sys/stand/efiboot/devopen.c @@ -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 @@ -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; } diff --git a/sys/stand/efiboot/efiblock.c b/sys/stand/efiboot/efiblock.c new file mode 100644 index 000000000000..f3a8ce900d26 --- /dev/null +++ b/sys/stand/efiboot/efiblock.c @@ -0,0 +1,350 @@ +/* $NetBSD: efiblock.c,v 1.1 2018/08/26 21:28:18 jmcneill Exp $ */ + +/*- + * Copyright (c) 2016 Kimihiro Nonaka + * Copyright (c) 2018 Jared McNeill + * 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 + +#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; +} diff --git a/sys/stand/efiboot/efiblock.h b/sys/stand/efiboot/efiblock.h new file mode 100644 index 000000000000..39c76d621df4 --- /dev/null +++ b/sys/stand/efiboot/efiblock.h @@ -0,0 +1,71 @@ +/* $NetBSD: efiblock.h,v 1.1 2018/08/26 21:28:18 jmcneill Exp $ */ + +/*- + * Copyright (c) 2018 Jared McNeill + * 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 +#include +#include + +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 *); diff --git a/sys/stand/efiboot/efiboot.c b/sys/stand/efiboot/efiboot.c index 3bae732a207a..d5581cc9fb38 100644 --- a/sys/stand/efiboot/efiboot.c +++ b/sys/stand/efiboot/efiboot.c @@ -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 @@ -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_SYSTEM_TABLE *systemTable) efi_fdt_probe(); efi_file_system_probe(); + efi_block_probe(); boot(); diff --git a/sys/stand/efiboot/efiboot.h b/sys/stand/efiboot/efiboot.h index 60f6b64c7dae..e5b7ae7a53c1 100644 --- a/sys/stand/efiboot/efiboot.h +++ b/sys/stand/efiboot/efiboot.h @@ -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 @@ -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 *); diff --git a/sys/stand/efiboot/efidev.c b/sys/stand/efiboot/efidev.c new file mode 100644 index 000000000000..17d4405edf5a --- /dev/null +++ b/sys/stand/efiboot/efidev.c @@ -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 + * + * 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); +} diff --git a/sys/stand/efiboot/efifile.c b/sys/stand/efiboot/efifile.c index f16b35833b52..490f9ee9e343 100644 --- a/sys/stand/efiboot/efifile.c +++ b/sys/stand/efiboot/efifile.c @@ -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 @@ -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 *pvol, const char **pfile) 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;