diff options
author | smh <smh@FreeBSD.org> | 2016-01-28 16:52:02 +0000 |
---|---|---|
committer | smh <smh@FreeBSD.org> | 2016-01-28 16:52:02 +0000 |
commit | 7cf27587c4119bcb0ff4c5f60930a61fc32683f2 (patch) | |
tree | f22fb47fb8da3036fafeae36c25ca7dbf64f7dee /sys/boot/efi/boot1 | |
parent | ee931520cdd5e9ef403c108aaf33f3b98f3ff222 (diff) | |
download | FreeBSD-src-7cf27587c4119bcb0ff4c5f60930a61fc32683f2.zip FreeBSD-src-7cf27587c4119bcb0ff4c5f60930a61fc32683f2.tar.gz |
MFC r281060, r294060, r294291, r294493, r294284:
MFC r281060:
Remove an unnecessary space in a printf call
MFC r294060:
Modularise EFI boot loader
MFC r294291 (by andrew):
Reset the filesystem cache
MFC r294493:
Fix EFI UFS caching
MFC r294284 (by emaste):
boot1: correct typo in error message
Sponsored by: Multiplay
Diffstat (limited to 'sys/boot/efi/boot1')
-rw-r--r-- | sys/boot/efi/boot1/Makefile | 3 | ||||
-rw-r--r-- | sys/boot/efi/boot1/boot1.c | 399 | ||||
-rw-r--r-- | sys/boot/efi/boot1/boot_module.h | 110 | ||||
-rw-r--r-- | sys/boot/efi/boot1/ufs_module.c | 185 |
4 files changed, 516 insertions, 181 deletions
diff --git a/sys/boot/efi/boot1/Makefile b/sys/boot/efi/boot1/Makefile index ce72c15..58b3b6b 100644 --- a/sys/boot/efi/boot1/Makefile +++ b/sys/boot/efi/boot1/Makefile @@ -11,7 +11,7 @@ INTERNALPROG= WARNS?= 6 # architecture-specific loader code -SRCS= boot1.c reloc.c start.S +SRCS= boot1.c reloc.c start.S ufs_module.c CFLAGS+= -fPIC CFLAGS+= -I. @@ -19,6 +19,7 @@ CFLAGS+= -I${.CURDIR}/../include CFLAGS+= -I${.CURDIR}/../include/${MACHINE} CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. +CFLAGS+= -DEFI_UFS_BOOT # Always add MI sources and REGULAR efi loader bits .PATH: ${.CURDIR}/../loader/arch/${MACHINE} diff --git a/sys/boot/efi/boot1/boot1.c b/sys/boot/efi/boot1/boot1.c index 020936d..d7bfe48 100644 --- a/sys/boot/efi/boot1/boot1.c +++ b/sys/boot/efi/boot1/boot1.c @@ -5,6 +5,8 @@ * All rights reserved. * Copyright (c) 2014 Nathan Whitehorn * All rights reserved. + * Copyright (c) 2015 Eric McCorkle + * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this @@ -21,7 +23,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/dirent.h> #include <machine/elf.h> #include <machine/stdarg.h> #include <stand.h> @@ -29,19 +30,29 @@ __FBSDID("$FreeBSD$"); #include <efi.h> #include <eficonsctl.h> +#include "boot_module.h" + #define _PATH_LOADER "/boot/loader.efi" -#define _PATH_KERNEL "/boot/kernel/kernel" -#define BSIZEMAX 16384 +static const boot_module_t *boot_modules[] = +{ +#ifdef EFI_UFS_BOOT + &ufs_module +#endif +}; + +#define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*)) +/* The initial number of handles used to query EFI for partitions. */ +#define NUM_HANDLES_INIT 24 -void panic(const char *fmt, ...) __dead2; void putchar(int c); EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); -static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet); -static void load(const char *fname); +static void try_load(const boot_module_t* mod); +static EFI_STATUS probe_handle(EFI_HANDLE h); -static EFI_SYSTEM_TABLE *systab; +EFI_SYSTEM_TABLE *systab; +EFI_BOOT_SERVICES *bs; static EFI_HANDLE *image; static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; @@ -49,27 +60,92 @@ static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; -static EFI_BLOCK_IO *bootdev; -static EFI_DEVICE_PATH *bootdevpath; -static EFI_HANDLE *bootdevhandle; +/* + * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures + * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from + * EFI methods. + */ +void * +Malloc(size_t len, const char *file __unused, int line __unused) +{ + void *out; + + if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) + return (out); + + return (NULL); +} + +void +Free(void *buf, const char *file __unused, int line __unused) +{ + (void)bs->FreePool(buf); +} -EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab) +/* + * This function only returns if it fails to load the kernel. If it + * succeeds, it simply boots the kernel. + */ +void +try_load(const boot_module_t *mod) { - EFI_HANDLE handles[128]; - EFI_BLOCK_IO *blkio; - UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode; + size_t bufsize; + void *buf; + dev_info_t *dev; + EFI_HANDLE loaderhandle; + EFI_LOADED_IMAGE *loaded_image; + EFI_STATUS status; + + status = mod->load(_PATH_LOADER, &dev, &buf, &bufsize); + if (status == EFI_NOT_FOUND) + return; + + if (status != EFI_SUCCESS) { + printf("%s failed to load %s (%lu)\n", mod->name, _PATH_LOADER, + EFI_ERROR_CODE(status)); + return; + } + + if ((status = bs->LoadImage(TRUE, image, dev->devpath, buf, bufsize, + &loaderhandle)) != EFI_SUCCESS) { + printf("Failed to load image provided by %s, size: %zu, (%lu)\n", + mod->name, bufsize, EFI_ERROR_CODE(status)); + return; + } + + if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID, + (VOID**)&loaded_image)) != EFI_SUCCESS) { + printf("Failed to query LoadedImage provided by %s (%lu)\n", + mod->name, EFI_ERROR_CODE(status)); + return; + } + + loaded_image->DeviceHandle = dev->devhandle; + + if ((status = bs->StartImage(loaderhandle, NULL, NULL)) != + EFI_SUCCESS) { + printf("Failed to start image provided by %s (%lu)\n", + mod->name, EFI_ERROR_CODE(status)); + return; + } +} + +EFI_STATUS +efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) +{ + EFI_HANDLE *handles; EFI_STATUS status; - EFI_DEVICE_PATH *devpath; - EFI_BOOT_SERVICES *BS; EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; - const char *path = _PATH_LOADER; + UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; + /* Basic initialization*/ systab = Xsystab; image = Ximage; + bs = Xsystab->BootServices; - BS = systab->BootServices; - status = BS->LocateProtocol(&ConsoleControlGUID, NULL, + /* Set up the console, so printf works. */ + status = bs->LocateProtocol(&ConsoleControlGUID, NULL, (VOID **)&ConsoleControl); if (status == EFI_SUCCESS) (void)ConsoleControl->SetMode(ConsoleControl, @@ -94,199 +170,162 @@ EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab) conout->EnableCursor(conout, TRUE); conout->ClearScreen(conout); - printf(" \n>> FreeBSD EFI boot block\n"); - printf(" Loader path: %s\n", path); - - status = systab->BootServices->LocateHandle(ByProtocol, - &BlockIoProtocolGUID, NULL, &nparts, handles); - nparts /= sizeof(handles[0]); - - for (i = 0; i < nparts; i++) { - status = systab->BootServices->HandleProtocol(handles[i], - &DevicePathGUID, (void **)&devpath); - if (EFI_ERROR(status)) + printf("\n>> FreeBSD EFI boot block\n"); + printf(" Loader path: %s\n\n", _PATH_LOADER); + printf(" Initializing modules:"); + for (i = 0; i < NUM_BOOT_MODULES; i++) { + if (boot_modules[i] == NULL) continue; - while (!IsDevicePathEnd(NextDevicePathNode(devpath))) - devpath = NextDevicePathNode(devpath); + printf(" %s", boot_modules[i]->name); + if (boot_modules[i]->init != NULL) + boot_modules[i]->init(); + } + putchar('\n'); - status = systab->BootServices->HandleProtocol(handles[i], - &BlockIoProtocolGUID, (void **)&blkio); - if (EFI_ERROR(status)) - continue; + /* Get all the device handles */ + hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); + if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles)) + != EFI_SUCCESS) + panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT, + EFI_ERROR_CODE(status)); - if (!blkio->Media->LogicalPartition) - continue; + status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, + &hsize, handles); + switch (status) { + case EFI_SUCCESS: + break; + case EFI_BUFFER_TOO_SMALL: + (void)bs->FreePool(handles); + if ((status = bs->AllocatePool(EfiLoaderData, hsize, + (void **)&handles) != EFI_SUCCESS)) { + panic("Failed to allocate %zu handles (%lu)", hsize / + sizeof(*handles), EFI_ERROR_CODE(status)); + } + status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, + NULL, &hsize, handles); + if (status != EFI_SUCCESS) + panic("Failed to get device handles (%lu)\n", + EFI_ERROR_CODE(status)); + break; + default: + panic("Failed to get device handles (%lu)", + EFI_ERROR_CODE(status)); + } - if (domount(devpath, blkio, 1) >= 0) + /* Scan all partitions, probing with all modules. */ + nhandles = hsize / sizeof(*handles); + printf(" Probing %zu block devices...", nhandles); + for (i = 0; i < nhandles; i++) { + status = probe_handle(handles[i]); + switch (status) { + case EFI_UNSUPPORTED: + printf("."); + break; + case EFI_SUCCESS: + printf("+"); break; + default: + printf("x"); + break; + } } + printf(" done\n"); - if (i == nparts) - panic("No bootable partition found"); - - bootdevhandle = handles[i]; - load(path); + /* Status summary. */ + for (i = 0; i < NUM_BOOT_MODULES; i++) { + if (boot_modules[i] != NULL) { + printf(" "); + boot_modules[i]->status(); + } + } - panic("Load failed"); + /* Select a partition to boot by trying each module in order. */ + for (i = 0; i < NUM_BOOT_MODULES; i++) + if (boot_modules[i] != NULL) + try_load(boot_modules[i]); - return EFI_SUCCESS; + /* If we get here, we're out of luck... */ + panic("No bootable partitions found!"); } -static int -dskread(void *buf, u_int64_t lba, int nblk) +static EFI_STATUS +probe_handle(EFI_HANDLE h) { + dev_info_t *devinfo; + EFI_BLOCK_IO *blkio; + EFI_DEVICE_PATH *devpath; EFI_STATUS status; - int size; + UINTN i; - lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE); - size = nblk * DEV_BSIZE; - status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba, - size, buf); + /* Figure out if we're dealing with an actual partition. */ + status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); + if (status == EFI_UNSUPPORTED) + return (status); - if (EFI_ERROR(status)) - return (-1); + if (status != EFI_SUCCESS) { + DPRINTF("\nFailed to query DevicePath (%lu)\n", + EFI_ERROR_CODE(status)); + return (status); + } - return (0); -} + while (!IsDevicePathEnd(NextDevicePathNode(devpath))) + devpath = NextDevicePathNode(devpath); -#include "ufsread.c" + status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); + if (status == EFI_UNSUPPORTED) + return (status); -static ssize_t -fsstat(ufs_ino_t inode) -{ -#ifndef UFS2_ONLY - static struct ufs1_dinode dp1; -#endif -#ifndef UFS1_ONLY - static struct ufs2_dinode dp2; -#endif - static struct fs fs; - static ufs_ino_t inomap; - char *blkbuf; - void *indbuf; - size_t n, size; - static ufs2_daddr_t blkmap, indmap; - - blkbuf = dmadat->blkbuf; - indbuf = dmadat->indbuf; - if (!dsk_meta) { - inomap = 0; - for (n = 0; sblock_try[n] != -1; n++) { - if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, - SBLOCKSIZE / DEV_BSIZE)) - return -1; - memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); - if (( -#if defined(UFS1_ONLY) - fs.fs_magic == FS_UFS1_MAGIC -#elif defined(UFS2_ONLY) - (fs.fs_magic == FS_UFS2_MAGIC && - fs.fs_sblockloc == sblock_try[n]) -#else - fs.fs_magic == FS_UFS1_MAGIC || - (fs.fs_magic == FS_UFS2_MAGIC && - fs.fs_sblockloc == sblock_try[n]) -#endif - ) && - fs.fs_bsize <= MAXBSIZE && - fs.fs_bsize >= (int32_t)sizeof(struct fs)) - break; - } - if (sblock_try[n] == -1) { - return -1; - } - dsk_meta++; - } else - memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); - if (!inode) - return 0; - if (inomap != inode) { - n = IPERVBLK(&fs); - if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) - return -1; - n = INO_TO_VBO(n, inode); -#if defined(UFS1_ONLY) - memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, - sizeof(struct ufs1_dinode)); -#elif defined(UFS2_ONLY) - memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, - sizeof(struct ufs2_dinode)); -#else - if (fs.fs_magic == FS_UFS1_MAGIC) - memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, - sizeof(struct ufs1_dinode)); - else - memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, - sizeof(struct ufs2_dinode)); -#endif - inomap = inode; - fs_off = 0; - blkmap = indmap = 0; + if (status != EFI_SUCCESS) { + DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", + EFI_ERROR_CODE(status)); + return (status); } - size = DIP(di_size); - n = size - fs_off; - return (n); -} -static struct dmadat __dmadat; + if (!blkio->Media->LogicalPartition) + return (EFI_UNSUPPORTED); -static int -domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet) -{ + /* Run through each module, see if it can load this partition */ + for (i = 0; i < NUM_BOOT_MODULES; i++) { + if (boot_modules[i] == NULL) + continue; - dmadat = &__dmadat; - bootdev = blkio; - bootdevpath = device; - if (fsread(0, NULL, 0)) { - if (!quiet) - printf("domount: can't read superblock\n"); - return (-1); + if ((status = bs->AllocatePool(EfiLoaderData, + sizeof(*devinfo), (void **)&devinfo)) != + EFI_SUCCESS) { + DPRINTF("\nFailed to allocate devinfo (%lu)\n", + EFI_ERROR_CODE(status)); + continue; + } + devinfo->dev = blkio; + devinfo->devpath = devpath; + devinfo->devhandle = h; + devinfo->devdata = NULL; + devinfo->next = NULL; + + status = boot_modules[i]->probe(devinfo); + if (status == EFI_SUCCESS) + return (EFI_SUCCESS); + (void)bs->FreePool(devinfo); } - if (!quiet) - printf("Succesfully mounted UFS filesystem\n"); - return (0); + + return (EFI_UNSUPPORTED); } -static void -load(const char *fname) +void +add_device(dev_info_t **devinfop, dev_info_t *devinfo) { - ufs_ino_t ino; - EFI_STATUS status; - EFI_HANDLE loaderhandle; - EFI_LOADED_IMAGE *loaded_image; - void *buffer; - size_t bufsize; + dev_info_t *dev; - if ((ino = lookup(fname)) == 0) { - printf("File %s not found\n", fname); + if (*devinfop == NULL) { + *devinfop = devinfo; return; } - bufsize = fsstat(ino); - status = systab->BootServices->AllocatePool(EfiLoaderData, - bufsize, &buffer); - fsread(ino, buffer, bufsize); + for (dev = *devinfop; dev->next != NULL; dev = dev->next) + ; - /* XXX: For secure boot, we need our own loader here */ - status = systab->BootServices->LoadImage(TRUE, image, bootdevpath, - buffer, bufsize, &loaderhandle); - if (EFI_ERROR(status)) - printf("LoadImage failed with error %lu\n", - EFI_ERROR_CODE(status)); - - status = systab->BootServices->HandleProtocol(loaderhandle, - &LoadedImageGUID, (VOID**)&loaded_image); - if (EFI_ERROR(status)) - printf("HandleProtocol failed with error %lu\n", - EFI_ERROR_CODE(status)); - - loaded_image->DeviceHandle = bootdevhandle; - - status = systab->BootServices->StartImage(loaderhandle, NULL, NULL); - if (EFI_ERROR(status)) - printf("StartImage failed with error %lu\n", - EFI_ERROR_CODE(status)); + dev->next = devinfo; } void diff --git a/sys/boot/efi/boot1/boot_module.h b/sys/boot/efi/boot1/boot_module.h new file mode 100644 index 0000000..ceb8843 --- /dev/null +++ b/sys/boot/efi/boot1/boot_module.h @@ -0,0 +1,110 @@ +/*- + * Copyright (c) 2015 Eric McCorkle + * 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. + * + * $FreeBSD$ + */ + +#ifndef _BOOT_MODULE_H_ +#define _BOOT_MODULE_H_ + +#include <stdbool.h> + +#include <efi.h> +#include <efilib.h> +#include <eficonsctl.h> + +#ifdef EFI_DEBUG +#define DPRINTF(fmt, args...) \ + do { \ + printf(fmt, ##args) \ + } while (0) +#else +#define DPRINTF(fmt, args...) {} +#endif + +/* EFI device info */ +typedef struct dev_info +{ + EFI_BLOCK_IO *dev; + EFI_DEVICE_PATH *devpath; + EFI_HANDLE *devhandle; + void *devdata; + struct dev_info *next; +} dev_info_t; + +/* + * A boot loader module. + * + * This is a standard interface for filesystem modules in the EFI system. + */ +typedef struct boot_module_t +{ + const char *name; + + /* init is the optional initialiser for the module. */ + void (*init)(); + + /* + * probe checks to see if the module can handle dev. + * + * Return codes: + * EFI_SUCCESS = The module can handle the device. + * EFI_NOT_FOUND = The module can not handle the device. + * Other = The module encountered an error. + */ + EFI_STATUS (*probe)(dev_info_t* dev); + + /* + * load should select the best out of a set of devices that probe + * indicated were loadable and load it. + * + * Return codes: + * EFI_SUCCESS = The module can handle the device. + * EFI_NOT_FOUND = The module can not handle the device. + * Other = The module encountered an error. + */ + EFI_STATUS (*load)(const char *loader_path, dev_info_t **devinfo, + void **buf, size_t *bufsize); + + /* status outputs information about the probed devices. */ + void (*status)(); + +} boot_module_t; + +/* Standard boot modules. */ +#ifdef EFI_UFS_BOOT +extern const boot_module_t ufs_module; +#endif + +/* Functions available to modules. */ +extern void add_device(dev_info_t **devinfop, dev_info_t *devinfo); +extern void panic(const char *fmt, ...) __dead2; +extern int printf(const char *fmt, ...); +extern int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); + +extern EFI_SYSTEM_TABLE *systab; +extern EFI_BOOT_SERVICES *bs; + +#endif diff --git a/sys/boot/efi/boot1/ufs_module.c b/sys/boot/efi/boot1/ufs_module.c new file mode 100644 index 0000000..07c7152 --- /dev/null +++ b/sys/boot/efi/boot1/ufs_module.c @@ -0,0 +1,185 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * Copyright (c) 2001 Robert Drehmel + * All rights reserved. + * Copyright (c) 2014 Nathan Whitehorn + * All rights reserved. + * Copyright (c) 2015 Eric McCorkle + * All rights reverved. + * + * 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$ + */ + +#include <stdarg.h> +#include <stdbool.h> +#include <sys/cdefs.h> +#include <sys/param.h> +#include <efi.h> + +#include "boot_module.h" + +static dev_info_t *devinfo; +static dev_info_t *devices; + +static int +dskread(void *buf, u_int64_t lba, int nblk) +{ + int size; + EFI_STATUS status; + + lba = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE); + size = nblk * DEV_BSIZE; + + status = devinfo->dev->ReadBlocks(devinfo->dev, + devinfo->dev->Media->MediaId, lba, size, buf); + + if (status != EFI_SUCCESS) { + DPRINTF("dskread: failed dev: %p, id: %u, lba: %lu, size: %d, " + "status: %lu\n", devinfo->dev, + devinfo->dev->Media->MediaId, lba, size, + EFI_ERROR_CODE(status)); + return (-1); + } + + return (0); +} + +#include "ufsread.c" + +static struct dmadat __dmadat; + +static int +init_dev(dev_info_t* dev) +{ + + devinfo = dev; + dmadat = &__dmadat; + + return fsread(0, NULL, 0); +} + +static EFI_STATUS +probe(dev_info_t* dev) +{ + + if (init_dev(dev) < 0) + return (EFI_UNSUPPORTED); + + add_device(&devices, dev); + + return (EFI_SUCCESS); +} + +static EFI_STATUS +try_load(dev_info_t *dev, const char *loader_path, void **bufp, size_t *bufsize) +{ + ufs_ino_t ino; + EFI_STATUS status; + size_t size; + ssize_t read; + void *buf; + + if (init_dev(dev) < 0) + return (EFI_UNSUPPORTED); + + if ((ino = lookup(loader_path)) == 0) + return (EFI_NOT_FOUND); + + if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) { + printf("Failed to read size of '%s' ino: %d\n", loader_path, + ino); + return (EFI_INVALID_PARAMETER); + } + + if ((status = bs->AllocatePool(EfiLoaderData, size, &buf)) != + EFI_SUCCESS) { + printf("Failed to allocate read buffer (%lu)\n", + EFI_ERROR_CODE(status)); + return (status); + } + + read = fsread(ino, buf, size); + if ((size_t)read != size) { + printf("Failed to read '%s' (%zd != %zu)\n", loader_path, read, + size); + (void)bs->FreePool(buf); + return (EFI_INVALID_PARAMETER); + } + + *bufp = buf; + *bufsize = size; + + return (EFI_SUCCESS); +} + +static EFI_STATUS +load(const char *loader_path, dev_info_t **devinfop, void **buf, + size_t *bufsize) +{ + dev_info_t *dev; + EFI_STATUS status; + + for (dev = devices; dev != NULL; dev = dev->next) { + status = try_load(dev, loader_path, buf, bufsize); + if (status == EFI_SUCCESS) { + *devinfop = dev; + return (EFI_SUCCESS); + } else if (status != EFI_NOT_FOUND) { + return (status); + } + } + + return (EFI_NOT_FOUND); +} + +static void +status() +{ + int i; + dev_info_t *dev; + + for (dev = devices, i = 0; dev != NULL; dev = dev->next, i++) + ; + + printf("%s found ", ufs_module.name); + switch (i) { + case 0: + printf("no partitions\n"); + break; + case 1: + printf("%d partition\n", i); + break; + default: + printf("%d partitions\n", i); + } +} + +const boot_module_t ufs_module = +{ + .name = "UFS", + .probe = probe, + .load = load, + .status = status +}; |