Index: head/stand/efi/Makefile =================================================================== --- head/stand/efi/Makefile (revision 348811) +++ head/stand/efi/Makefile (revision 348812) @@ -1,19 +1,19 @@ # $FreeBSD$ NO_OBJ=t .include # In-tree GCC does not support __attribute__((ms_abi)), but gcc newer # than 4.5 supports it. .if ${COMPILER_TYPE} != "gcc" || ${COMPILER_VERSION} >= 40500 SUBDIR.${MK_FDT}+= fdt -SUBDIR.yes+= libefi boot1 +SUBDIR.yes+= libefi boot1 gptboot SUBDIR.${MK_FORTH}+= loader_4th SUBDIR.${MK_LOADER_LUA}+= loader_lua SUBDIR.yes+= loader_simp .endif # ${COMPILER_TYPE} != "gcc" || ${COMPILER_VERSION} >= 40500 .include Index: head/stand/efi/gptboot/Makefile =================================================================== --- head/stand/efi/gptboot/Makefile (nonexistent) +++ head/stand/efi/gptboot/Makefile (revision 348812) @@ -0,0 +1,17 @@ +# $FreeBSD$ + +# ZFS is not supported, we want debugging until this is vetted and +# we don't want the gptboot.efifat thing created. +MK_LOADER_ZFS=no +EFI_DEBUG=yes +NOFAT=yes + +BOOT1?= gptboot +.PATH: ${SRCTOP}/stand/efi/boot1 ${SRCTOP}/stand/libsa +CFLAGS+= -I${SRCTOP}/stand/efi/boot1 +CFLAGS+= -I${.CURDIR} +CFLAGS+= -DBOOTPROG=\"gptboot.efi\" +SRCS+= gpt.c +CWARNFLAGS.gpt.c+= -Wno-sign-compare -Wno-cast-align +WARNS=6 +.include "${.CURDIR}/../boot1/Makefile" Property changes on: head/stand/efi/gptboot/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/stand/efi/gptboot/drv.h =================================================================== --- head/stand/efi/gptboot/drv.h (nonexistent) +++ head/stand/efi/gptboot/drv.h (revision 348812) @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2019 Netflix, Inc + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _DRV_H_ +#define _DRV_H_ + +struct dsk { + int part; + daddr_t start; + void *devinfo; /* Really a dev_into_t *, but that's not in scope */ +}; + +int drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk); +int drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk); +uint64_t drvsize(struct dsk *dskp); + +#endif /* !_DRV_H_ */ Property changes on: head/stand/efi/gptboot/drv.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/stand/efi/gptboot/proto.c =================================================================== --- head/stand/efi/gptboot/proto.c (nonexistent) +++ head/stand/efi/gptboot/proto.c (revision 348812) @@ -0,0 +1,279 @@ +/*- + * Copyright (c) 2019 Netflix, Inc + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include + +#include "boot_module.h" +#include "paths.h" +#include "proto.h" + +#include "gpt.h" +#include +static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS; +static char secbuf[4096]; +static struct dsk dsk; +static dev_info_t *devices = NULL; +static dev_info_t *raw_device = NULL; + +static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; +static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; + +/* + * Shim routine for the gpt code to read in the gpt table. The + * devinfo is always going to be for the raw device. + */ +int +drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) +{ + int size; + EFI_STATUS status; + dev_info_t *devinfo = (dev_info_t *)dskp->devinfo; + EFI_BLOCK_IO *dev = devinfo->dev; + + lba = lba / (dev->Media->BlockSize / DEV_BSIZE); + size = nblk * DEV_BSIZE; + + status = dev->ReadBlocks(dev, dev->Media->MediaId, lba, size, buf); + if (status != EFI_SUCCESS) { + DPRINTF("dskread: failed dev: %p, id: %u, lba: %ju, size: %d, " + "status: %lu\n", devinfo->dev, + dev->Media->MediaId, (uintmax_t)lba, size, + EFI_ERROR_CODE(status)); + return (-1); + } + + return (0); +} + +/* + * Shim routine for the gpt code to write in the gpt table. The + * devinfo is always going to be for the raw device. + */ +int +drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) +{ + int size; + EFI_STATUS status; + dev_info_t *devinfo = (dev_info_t *)dskp->devinfo; + EFI_BLOCK_IO *dev = devinfo->dev; + + if (dev->Media->ReadOnly) + return -1; + + lba = lba / (dev->Media->BlockSize / DEV_BSIZE); + size = nblk * DEV_BSIZE; + + status = dev->WriteBlocks(dev, dev->Media->MediaId, lba, size, buf); + if (status != EFI_SUCCESS) { + DPRINTF("dskread: failed dev: %p, id: %u, lba: %ju, size: %d, " + "status: %lu\n", devinfo->dev, + dev->Media->MediaId, (uintmax_t)lba, size, + EFI_ERROR_CODE(status)); + return (-1); + } + + return (0); +} + +/* + * Return the number of LBAs the drive has. + */ +uint64_t +drvsize(struct dsk *dskp) +{ + dev_info_t *devinfo = (dev_info_t *)dskp->devinfo; + EFI_BLOCK_IO *dev = devinfo->dev; + + return (dev->Media->LastBlock + 1); +} + +static int +partition_number(EFI_DEVICE_PATH *devpath) +{ + EFI_DEVICE_PATH *md; + HARDDRIVE_DEVICE_PATH *hd; + + md = efi_devpath_last_node(devpath); + if (md == NULL) + return (-1); + if (DevicePathSubType(md) != MEDIA_HARDDRIVE_DP) + return (-1); + hd = (HARDDRIVE_DEVICE_PATH *)md; + return (hd->PartitionNumber); +} + +/* + * Find the raw partition for the imgpath and save it + */ +static void +probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) +{ + dev_info_t *devinfo; + EFI_BLOCK_IO *blkio; + EFI_DEVICE_PATH *devpath, *trimmed = NULL; + EFI_STATUS status; + + /* Figure out if we're dealing with an actual partition. */ + status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); + if (status != EFI_SUCCESS) + return; +#ifdef EFI_DEBUG + { + CHAR16 *text = efi_devpath_name(devpath); + DPRINTF("probing: %S ", text); + efi_free_devpath_name(text); + } +#endif + /* + * The RAW device is the same as the imgpath with the last + * MEDIA_DEVICE bit trimmed off. imgpath will end with the + * MEDIA_DEVICE for the ESP we booted off of. + */ + if (!efi_devpath_same_disk(imgpath, devpath)) { + trimmed = efi_devpath_trim(imgpath); + if (!efi_devpath_match(trimmed, devpath)) { + free(trimmed); + DPRINTF("Not the same disk\n"); + return; + } + } + status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); + if (status != EFI_SUCCESS) { + DPRINTF("Can't get the block I/O protocol block\n"); + return; + } + devinfo = malloc(sizeof(*devinfo)); + if (devinfo == NULL) { + DPRINTF("Failed to allocate devinfo\n"); + return; + } + devinfo->dev = blkio; + devinfo->devpath = devpath; + devinfo->devhandle = h; + devinfo->preferred = 1; + devinfo->next = NULL; + devinfo->devdata = NULL; + if (trimmed == NULL) { + DPRINTF("Found partition %d\n", partition_number(devpath)); + add_device(&devices, devinfo); + } else { + free(trimmed); + DPRINTF("Found raw device\n"); + if (raw_device) { + printf(BOOTPROG": Found two raw devices, inconceivable?\n"); + return; + } + raw_device = devinfo; + } +} + +static void +probe_handles(EFI_HANDLE *handles, UINTN nhandles, EFI_DEVICE_PATH *imgpath) +{ + UINTN i; + + for (i = 0; i < nhandles; i++) + probe_handle(handles[i], imgpath); +} + +static dev_info_t * +find_partition(int part) +{ + dev_info_t *dev; + + if (part == 0) + return (NULL); + for (dev = devices; dev != NULL; dev = dev->next) + if (partition_number(dev->devpath) == part) + break; + return (dev); +} + +void +choice_protocol(EFI_HANDLE *handles, UINTN nhandles, EFI_DEVICE_PATH *imgpath) +{ + const boot_module_t *mod = &ufs_module; + dev_info_t *bootdev; + void *loaderbuf; + size_t loadersize; + int parts; + const char *fn = PATH_LOADER_EFI; + + /* + * Probe the provided handles to find the partitions that + * are on the same drive. + */ + probe_handles(handles, nhandles, imgpath); + dsk.devinfo = raw_device; + if (dsk.devinfo == NULL) { + printf(BOOTPROG": unable to find raw disk to read gpt\n"); + return; + } + + /* + * Read in the GPT table, and then find the right partition. + * gptread, gptfind and gptfaileboot are shared with the + * BIOS version of the gptboot program. + */ + if (gptread(&dsk, secbuf) == -1) { + printf(BOOTPROG ": unable to load GPT\n"); + return; + } + // XXX: + // real gptboot can parse a command line before trying this loop. + // But since we don't parse anything at all, hard wire the partition + // to be -1 (meaning look for the next one). + parts = 0; + while (gptfind(&freebsd_ufs_uuid, &dsk, -1) != -1) { + parts++; + bootdev = find_partition(dsk.part); + if (bootdev == NULL) { + printf(BOOTPROG": Can't find partition %d\n", + dsk.part); + goto next; + } + if (mod->load(fn, bootdev, &loaderbuf, &loadersize) != + EFI_SUCCESS) { + printf(BOOTPROG": Can't load %s from partition %d\n", + fn, dsk.part); + goto next; + } + try_boot(mod, bootdev, loaderbuf, loadersize); +next: + gptbootfailed(&dsk); + } + if (parts == 0) + printf("%s: no UFS partition was found\n", BOOTPROG); +} Property changes on: head/stand/efi/gptboot/proto.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property