Index: head/sys/boot/efi/boot1/Makefile =================================================================== --- head/sys/boot/efi/boot1/Makefile (revision 322937) +++ head/sys/boot/efi/boot1/Makefile (revision 322938) @@ -1,152 +1,154 @@ # $FreeBSD$ MAN= .include MK_SSP= no PROG= boot1.sym INTERNALPROG= WARNS?= 6 # Disable warnings that are currently incompatible with the zfs boot code CWARNFLAGS.zfs_module.c += -Wno-array-bounds CWARNFLAGS.zfs_module.c += -Wno-cast-align CWARNFLAGS.zfs_module.c += -Wno-cast-qual CWARNFLAGS.zfs_module.c += -Wno-missing-prototypes CWARNFLAGS.zfs_module.c += -Wno-sign-compare CWARNFLAGS.zfs_module.c += -Wno-unused-parameter CWARNFLAGS.zfs_module.c += -Wno-unused-function CWARNFLAGS.skein.c += -Wno-cast-align .if ${COMPILER_TYPE} == "clang" CWARNFLAGS.skein.c += -Wno-missing-variable-declarations .else if ${COMPILER_TYPE} == "gcc" CWARNFLAGS.skein.c += -Wno-missing-declarations .endif # architecture-specific loader code SRCS= boot1.c self_reloc.c start.S ufs_module.c .if ${MK_ZFS} != "no" SRCS+= zfs_module.c SRCS+= skein.c skein_block.c # Do not unroll skein loops, reduce code size CFLAGS+= -DSKEIN_LOOP=111 .PATH: ${.CURDIR}/../../../crypto/skein .endif .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201 CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized .endif CFLAGS+= -I. CFLAGS+= -I${.CURDIR}/../include CFLAGS+= -I${.CURDIR}/../include/${MACHINE} CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. CFLAGS+= -DEFI_UFS_BOOT .ifdef(EFI_DEBUG) CFLAGS+= -DEFI_DEBUG .endif .if ${MK_ZFS} != "no" CFLAGS+= -I${.CURDIR}/../../zfs/ CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs/ CFLAGS+= -I${.CURDIR}/../../../crypto/skein CFLAGS+= -DEFI_ZFS_BOOT .endif # Always add MI sources and REGULAR efi loader bits .PATH: ${.CURDIR}/../loader/arch/${MACHINE} .PATH: ${.CURDIR}/../loader .PATH: ${.CURDIR}/../../common CFLAGS+= -I${.CURDIR}/../../common FILES= boot1.efi boot1.efifat FILESMODE_boot1.efi= ${BINMODE} LDSCRIPT= ${.CURDIR}/../loader/arch/${MACHINE}/ldscript.${MACHINE} LDFLAGS+= -Wl,-T${LDSCRIPT},-Bsymbolic,-znotext -shared .if ${MACHINE_CPUARCH} == "aarch64" CFLAGS+= -mgeneral-regs-only .endif .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" CFLAGS+= -fPIC LDFLAGS+= -Wl,-znocombreloc .endif +LIBEFI= ${.OBJDIR}/../libefi/libefi.a + # # Add libstand for the runtime functions used by the compiler - for example # __aeabi_* (arm) or __divdi3 (i386). # as well as required string and memory functions for all platforms. # -DPADD+= ${LIBSTAND} -LDADD+= -lstand +DPADD+= ${LIBEFI} ${LIBSTAND} +LDADD+= ${LIBEFI} -lstand DPADD+= ${LDSCRIPT} NM?= nm OBJCOPY?= objcopy .if ${MACHINE_CPUARCH} == "amd64" EFI_TARGET= efi-app-x86_64 .elif ${MACHINE_CPUARCH} == "i386" EFI_TARGET= efi-app-ia32 .else EFI_TARGET= binary .endif # Arbitrarily set the PE/COFF header timestamps to 1 Jan 2016 00:00:00 # for build reproducibility. SOURCE_DATE_EPOCH?=1451606400 boot1.efi: ${PROG} if ${NM} ${.ALLSRC} | grep ' U '; then \ echo "Undefined symbols in ${.ALLSRC}"; \ exit 1; \ fi SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} \ ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \ -j .dynamic -j .dynsym -j .rel.dyn \ -j .rela.dyn -j .reloc -j .eh_frame \ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} boot1.o: ${.CURDIR}/../../common/ufsread.c # The following inserts our objects into a template FAT file system # created by generate-fat.sh .include "${.CURDIR}/Makefile.fat" BOOT1_MAXSIZE?= 131072 boot1.efifat: boot1.efi @set -- `ls -l ${.ALLSRC}`; \ x=$$(($$5-${BOOT1_MAXSIZE})); \ if [ $$x -ge 0 ]; then \ echo "boot1 $$x bytes too large; regenerate FAT templates?" >&2 ;\ exit 1; \ fi echo ${.OBJDIR} uudecode ${.CURDIR}/fat-${MACHINE}.tmpl.bz2.uu mv fat-${MACHINE}.tmpl.bz2 ${.TARGET}.bz2 bzip2 -f -d ${.TARGET}.bz2 ${DD} if=${.ALLSRC} of=${.TARGET} seek=${BOOT1_OFFSET} conv=notrunc CLEANFILES= boot1.efi boot1.efifat .include beforedepend ${OBJS}: machine CLEANFILES+= machine machine: .NOMETA ln -sf ${.CURDIR}/../../../${MACHINE}/include machine .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" beforedepend ${OBJS}: x86 CLEANFILES+= x86 x86: .NOMETA ln -sf ${.CURDIR}/../../../x86/include x86 .endif Index: head/sys/boot/efi/boot1/boot1.c =================================================================== --- head/sys/boot/efi/boot1/boot1.c (revision 322937) +++ head/sys/boot/efi/boot1/boot1.c (revision 322938) @@ -1,719 +1,714 @@ /*- * 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 reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "boot_module.h" #include "paths.h" static const boot_module_t *boot_modules[] = { #ifdef EFI_ZFS_BOOT &zfs_module, #endif #ifdef EFI_UFS_BOOT &ufs_module #endif }; #define NUM_BOOT_MODULES nitems(boot_modules) /* The initial number of handles used to query EFI for partitions. */ #define NUM_HANDLES_INIT 24 -EFI_HANDLE IH; -EFI_SYSTEM_TABLE *ST; -EFI_BOOT_SERVICES *BS; -EFI_RUNTIME_SERVICES *RS; - static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; /* * 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) { if (buf != NULL) (void)BS->FreePool(buf); } /* * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, * FALSE otherwise. */ static BOOLEAN nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) { size_t len; if (imgpath == NULL || imgpath->Type != devpath->Type || imgpath->SubType != devpath->SubType) return (FALSE); len = DevicePathNodeLength(imgpath); if (len != DevicePathNodeLength(devpath)) return (FALSE); return (memcmp(imgpath, devpath, (size_t)len) == 0); } /* * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes * in imgpath and devpath match up to their respective occurrences of a * media node, FALSE otherwise. */ static BOOLEAN device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) { if (imgpath == NULL) return (FALSE); while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) { if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) && IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) return (TRUE); if (!nodes_match(imgpath, devpath)) return (FALSE); imgpath = NextDevicePathNode(imgpath); devpath = NextDevicePathNode(devpath); } return (FALSE); } /* * devpath_last returns the last non-path end node in devpath. */ static EFI_DEVICE_PATH * devpath_last(EFI_DEVICE_PATH *devpath) { while (!IsDevicePathEnd(NextDevicePathNode(devpath))) devpath = NextDevicePathNode(devpath); return (devpath); } /* * devpath_node_str is a basic output method for a devpath node which * only understands a subset of the available sub types. * * If we switch to UEFI 2.x then we should update it to use: * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL. */ static int devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) { switch (devpath->Type) { case MESSAGING_DEVICE_PATH: switch (devpath->SubType) { case MSG_ATAPI_DP: { ATAPI_DEVICE_PATH *atapi; atapi = (ATAPI_DEVICE_PATH *)(void *)devpath; return snprintf(buf, size, "ata(%s,%s,0x%x)", (atapi->PrimarySecondary == 1) ? "Sec" : "Pri", (atapi->SlaveMaster == 1) ? "Slave" : "Master", atapi->Lun); } case MSG_USB_DP: { USB_DEVICE_PATH *usb; usb = (USB_DEVICE_PATH *)devpath; return snprintf(buf, size, "usb(0x%02x,0x%02x)", usb->ParentPortNumber, usb->InterfaceNumber); } case MSG_SCSI_DP: { SCSI_DEVICE_PATH *scsi; scsi = (SCSI_DEVICE_PATH *)(void *)devpath; return snprintf(buf, size, "scsi(0x%02x,0x%02x)", scsi->Pun, scsi->Lun); } case MSG_SATA_DP: { SATA_DEVICE_PATH *sata; sata = (SATA_DEVICE_PATH *)(void *)devpath; return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)", sata->HBAPortNumber, sata->PortMultiplierPortNumber, sata->Lun); } default: return snprintf(buf, size, "msg(0x%02x)", devpath->SubType); } break; case HARDWARE_DEVICE_PATH: switch (devpath->SubType) { case HW_PCI_DP: { PCI_DEVICE_PATH *pci; pci = (PCI_DEVICE_PATH *)devpath; return snprintf(buf, size, "pci(0x%02x,0x%02x)", pci->Device, pci->Function); } default: return snprintf(buf, size, "hw(0x%02x)", devpath->SubType); } break; case ACPI_DEVICE_PATH: { ACPI_HID_DEVICE_PATH *acpi; acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath; if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { switch (EISA_ID_TO_NUM(acpi->HID)) { case 0x0a03: return snprintf(buf, size, "pciroot(0x%x)", acpi->UID); case 0x0a08: return snprintf(buf, size, "pcieroot(0x%x)", acpi->UID); case 0x0604: return snprintf(buf, size, "floppy(0x%x)", acpi->UID); case 0x0301: return snprintf(buf, size, "keyboard(0x%x)", acpi->UID); case 0x0501: return snprintf(buf, size, "serial(0x%x)", acpi->UID); case 0x0401: return snprintf(buf, size, "parallelport(0x%x)", acpi->UID); default: return snprintf(buf, size, "acpi(pnp%04x,0x%x)", EISA_ID_TO_NUM(acpi->HID), acpi->UID); } } return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID, acpi->UID); } case MEDIA_DEVICE_PATH: switch (devpath->SubType) { case MEDIA_CDROM_DP: { CDROM_DEVICE_PATH *cdrom; cdrom = (CDROM_DEVICE_PATH *)(void *)devpath; return snprintf(buf, size, "cdrom(%x)", cdrom->BootEntry); } case MEDIA_HARDDRIVE_DP: { HARDDRIVE_DEVICE_PATH *hd; hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; return snprintf(buf, size, "hd(%x)", hd->PartitionNumber); } default: return snprintf(buf, size, "media(0x%02x)", devpath->SubType); } case BBS_DEVICE_PATH: return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType); case END_DEVICE_PATH_TYPE: return (0); } return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type, devpath->SubType); } /* * devpath_strlcat appends a text description of devpath to buf but not more * than size - 1 characters followed by NUL-terminator. */ int devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath) { size_t len, used; const char *sep; sep = ""; used = 0; while (!IsDevicePathEnd(devpath)) { len = snprintf(buf, size - used, "%s", sep); used += len; if (used > size) return (used); buf += len; len = devpath_node_str(buf, size - used, devpath); used += len; if (used > size) return (used); buf += len; devpath = NextDevicePathNode(devpath); sep = ":"; } return (used); } /* * devpath_str is convenience method which returns the text description of * devpath using a static buffer, so it isn't thread safe! */ char * devpath_str(EFI_DEVICE_PATH *devpath) { static char buf[256]; devpath_strlcat(buf, sizeof(buf), devpath); return buf; } /* * load_loader attempts to load the loader image data. * * It tries each module and its respective devices, identified by mod->probe, * in order until a successful load occurs at which point it returns EFI_SUCCESS * and EFI_NOT_FOUND otherwise. * * Only devices which have preferred matching the preferred parameter are tried. */ static EFI_STATUS load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, size_t *bufsize, BOOLEAN preferred) { UINTN i; dev_info_t *dev; const boot_module_t *mod; for (i = 0; i < NUM_BOOT_MODULES; i++) { mod = boot_modules[i]; for (dev = mod->devices(); dev != NULL; dev = dev->next) { if (dev->preferred != preferred) continue; if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == EFI_SUCCESS) { *devinfop = dev; *modp = mod; return (EFI_SUCCESS); } } } return (EFI_NOT_FOUND); } /* * try_boot only returns if it fails to load the loader. If it succeeds * it simply boots, otherwise it returns the status of last EFI call. */ static EFI_STATUS try_boot(void) { size_t bufsize, loadersize, cmdsize; void *buf, *loaderbuf; char *cmd; dev_info_t *dev; const boot_module_t *mod; EFI_HANDLE loaderhandle; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); if (status != EFI_SUCCESS) { status = load_loader(&mod, &dev, &loaderbuf, &loadersize, FALSE); if (status != EFI_SUCCESS) { printf("Failed to load '%s'\n", PATH_LOADER_EFI); return (status); } } /* * Read in and parse the command line from /boot.config or /boot/config, * if present. We'll pass it the next stage via a simple ASCII * string. loader.efi has a hack for ASCII strings, so we'll use that to * keep the size down here. We only try to read the alternate file if * we get EFI_NOT_FOUND because all other errors mean that the boot_module * had troubles with the filesystem. We could return early, but we'll let * loading the actual kernel sort all that out. Since these files are * optional, we don't report errors in trying to read them. */ cmd = NULL; cmdsize = 0; status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); if (status == EFI_NOT_FOUND) status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); if (status == EFI_SUCCESS) { cmdsize = bufsize + 1; cmd = malloc(cmdsize); if (cmd == NULL) goto errout; memcpy(cmd, buf, bufsize); cmd[bufsize] = '\0'; free(buf); buf = NULL; } if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath), loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { printf("Failed to load image provided by %s, size: %zu, (%lu)\n", mod->name, loadersize, EFI_ERROR_CODE(status)); goto errout; } 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)); goto errout; } if (cmd != NULL) printf(" command args: %s\n", cmd); loaded_image->DeviceHandle = dev->devhandle; loaded_image->LoadOptionsSize = cmdsize; loaded_image->LoadOptions = cmd; DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); DSTALL(1000000); DPRINTF("."); DSTALL(1000000); DPRINTF("."); DSTALL(1000000); DPRINTF("."); DSTALL(1000000); DPRINTF("."); DSTALL(1000000); DPRINTF(".\n"); 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)); loaded_image->LoadOptionsSize = 0; loaded_image->LoadOptions = NULL; } errout: if (cmd != NULL) free(cmd); if (buf != NULL) free(buf); if (loaderbuf != NULL) free(loaderbuf); return (status); } /* * probe_handle determines if the passed handle represents a logical partition * if it does it uses each module in order to probe it and if successful it * returns EFI_SUCCESS. */ static EFI_STATUS probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred) { dev_info_t *devinfo; EFI_BLOCK_IO *blkio; EFI_DEVICE_PATH *devpath; EFI_STATUS status; UINTN i; /* Figure out if we're dealing with an actual partition. */ status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); if (status == EFI_UNSUPPORTED) return (status); if (status != EFI_SUCCESS) { DPRINTF("\nFailed to query DevicePath (%lu)\n", EFI_ERROR_CODE(status)); return (status); } DPRINTF("probing: %s\n", devpath_str(devpath)); status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); if (status == EFI_UNSUPPORTED) return (status); if (status != EFI_SUCCESS) { DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", EFI_ERROR_CODE(status)); return (status); } if (!blkio->Media->LogicalPartition) return (EFI_UNSUPPORTED); *preferred = device_paths_match(imgpath, devpath); /* Run through each module, see if it can load this partition */ for (i = 0; i < NUM_BOOT_MODULES; i++) { 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->preferred = *preferred; devinfo->next = NULL; status = boot_modules[i]->probe(devinfo); if (status == EFI_SUCCESS) return (EFI_SUCCESS); (void)BS->FreePool(devinfo); } return (EFI_UNSUPPORTED); } /* * probe_handle_status calls probe_handle and outputs the returned status * of the call. */ static void probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) { EFI_STATUS status; BOOLEAN preferred; preferred = FALSE; status = probe_handle(h, imgpath, &preferred); DPRINTF("probe: "); switch (status) { case EFI_UNSUPPORTED: printf("."); DPRINTF(" not supported\n"); break; case EFI_SUCCESS: if (preferred) { printf("%c", '*'); DPRINTF(" supported (preferred)\n"); } else { printf("%c", '+'); DPRINTF(" supported\n"); } break; default: printf("x"); DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status)); break; } DSTALL(500000); } EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) { EFI_HANDLE *handles; EFI_LOADED_IMAGE *img; EFI_DEVICE_PATH *imgpath; EFI_STATUS status; EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; /* Basic initialization*/ ST = Xsystab; IH = Ximage; BS = ST->BootServices; RS = ST->RuntimeServices; /* Set up the console, so printf works. */ status = BS->LocateProtocol(&ConsoleControlGUID, NULL, (VOID **)&ConsoleControl); if (status == EFI_SUCCESS) (void)ConsoleControl->SetMode(ConsoleControl, EfiConsoleControlScreenText); /* * Reset the console and find the best text mode. */ conout = ST->ConOut; conout->Reset(conout, TRUE); max_dim = best_mode = 0; for (i = 0; ; i++) { status = conout->QueryMode(conout, i, &cols, &rows); if (EFI_ERROR(status)) break; if (cols * rows > max_dim) { max_dim = cols * rows; best_mode = i; } } if (max_dim > 0) conout->SetMode(conout, best_mode); conout->EnableCursor(conout, TRUE); conout->ClearScreen(conout); printf("\n>> FreeBSD EFI boot block\n"); printf(" Loader path: %s\n\n", PATH_LOADER_EFI); printf(" Initializing modules:"); for (i = 0; i < NUM_BOOT_MODULES; i++) { printf(" %s", boot_modules[i]->name); if (boot_modules[i]->init != NULL) boot_modules[i]->init(); } putchar('\n'); /* 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)); 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)); } /* Scan all partitions, probing with all modules. */ nhandles = hsize / sizeof(*handles); printf(" Probing %zu block devices...", nhandles); DPRINTF("\n"); /* Determine the devpath of our image so we can prefer it. */ status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img); imgpath = NULL; if (status == EFI_SUCCESS) { status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID, (void **)&imgpath); if (status != EFI_SUCCESS) DPRINTF("Failed to get image DevicePath (%lu)\n", EFI_ERROR_CODE(status)); DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath)); } for (i = 0; i < nhandles; i++) probe_handle_status(handles[i], imgpath); printf(" done\n"); /* Status summary. */ for (i = 0; i < NUM_BOOT_MODULES; i++) { printf(" "); boot_modules[i]->status(); } try_boot(); /* If we get here, we're out of luck... */ panic("No bootable partitions found!"); } /* * add_device adds a device to the passed devinfo list. */ void add_device(dev_info_t **devinfop, dev_info_t *devinfo) { dev_info_t *dev; if (*devinfop == NULL) { *devinfop = devinfo; return; } for (dev = *devinfop; dev->next != NULL; dev = dev->next) ; dev->next = devinfo; } void panic(const char *fmt, ...) { va_list ap; printf("panic: "); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); while (1) {} } void putchar(int c) { CHAR16 buf[2]; if (c == '\n') { buf[0] = '\r'; buf[1] = 0; ST->ConOut->OutputString(ST->ConOut, buf); } buf[0] = c; buf[1] = 0; ST->ConOut->OutputString(ST->ConOut, buf); } Index: head/sys/boot/efi/libefi/libefi.c =================================================================== --- head/sys/boot/efi/libefi/libefi.c (revision 322937) +++ head/sys/boot/efi/libefi/libefi.c (revision 322938) @@ -1,49 +1,52 @@ /*- * Copyright (c) 2000 Doug Rabson * 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 __FBSDID("$FreeBSD$"); #include #include #include #include -extern EFI_SYSTEM_TABLE *ST; +EFI_HANDLE IH; +EFI_SYSTEM_TABLE *ST; +EFI_BOOT_SERVICES *BS; +EFI_RUNTIME_SERVICES *RS; void * efi_get_table(EFI_GUID *tbl) { EFI_GUID *id; int i; for (i = 0; i < ST->NumberOfTableEntries; i++) { id = &ST->ConfigurationTable[i].VendorGuid; if (!memcmp(id, tbl, sizeof(EFI_GUID))) return (ST->ConfigurationTable[i].VendorTable); } return (NULL); } Index: head/sys/boot/efi/loader/efi_main.c =================================================================== --- head/sys/boot/efi/loader/efi_main.c (revision 322937) +++ head/sys/boot/efi/loader/efi_main.c (revision 322938) @@ -1,186 +1,181 @@ /*- * Copyright (c) 2000 Doug Rabson * 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 __FBSDID("$FreeBSD$"); #include #include #include #include -EFI_HANDLE IH; -EFI_SYSTEM_TABLE *ST; -EFI_BOOT_SERVICES *BS; -EFI_RUNTIME_SERVICES *RS; - static EFI_PHYSICAL_ADDRESS heap; static UINTN heapsize; void exit(EFI_STATUS exit_code) { BS->FreePages(heap, EFI_SIZE_TO_PAGES(heapsize)); BS->Exit(IH, exit_code, 0, NULL); } static CHAR16 * arg_skipsep(CHAR16 *argp) { while (*argp == ' ' || *argp == '\t' || *argp == '\n') argp++; return (argp); } static CHAR16 * arg_skipword(CHAR16 *argp) { while (*argp && *argp != ' ' && *argp != '\t' && *argp != '\n') argp++; return (argp); } EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) { static EFI_GUID image_protocol = LOADED_IMAGE_PROTOCOL; static EFI_GUID console_control_protocol = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; EFI_CONSOLE_CONTROL_PROTOCOL *console_control = NULL; EFI_LOADED_IMAGE *img; CHAR16 *argp, *args, **argv; EFI_STATUS status; int argc, addprog; IH = image_handle; ST = system_table; BS = ST->BootServices; RS = ST->RuntimeServices; status = BS->LocateProtocol(&console_control_protocol, NULL, (VOID **)&console_control); if (status == EFI_SUCCESS) (void)console_control->SetMode(console_control, EfiConsoleControlScreenText); heapsize = 64 * 1024 * 1024; status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, EFI_SIZE_TO_PAGES(heapsize), &heap); if (status != EFI_SUCCESS) BS->Exit(IH, status, 0, NULL); setheap((void *)(uintptr_t)heap, (void *)(uintptr_t)(heap + heapsize)); /* Use exit() from here on... */ status = BS->HandleProtocol(IH, &image_protocol, (VOID**)&img); if (status != EFI_SUCCESS) exit(status); /* * Pre-process the (optional) load options. If the option string * is given as an ASCII string, we use a poor man's ASCII to * Unicode-16 translation. The size of the option string as given * to us includes the terminating null character. We assume the * string is an ASCII string if strlen() plus the terminating * '\0' is less than LoadOptionsSize. Even if all Unicode-16 * characters have the upper 8 bits non-zero, the terminating * null character will cause a one-off. * If the string is already in Unicode-16, we make a copy so that * we know we can always modify the string. */ if (img->LoadOptionsSize > 0 && img->LoadOptions != NULL) { if (img->LoadOptionsSize == strlen(img->LoadOptions) + 1) { args = malloc(img->LoadOptionsSize << 1); for (argc = 0; argc < (int)img->LoadOptionsSize; argc++) args[argc] = ((char*)img->LoadOptions)[argc]; } else { args = malloc(img->LoadOptionsSize); memcpy(args, img->LoadOptions, img->LoadOptionsSize); } } else args = NULL; /* * Use a quick and dirty algorithm to build the argv vector. We * first count the number of words. Then, after allocating the * vector, we split the string up. We don't deal with quotes or * other more advanced shell features. * The EFI shell will pass the name of the image as the first * word in the argument list. This does not happen if we're * loaded by the boot manager. This is not so easy to figure * out though. The ParentHandle is not always NULL, because * there can be a function (=image) that will perform the task * for the boot manager. */ /* Part 1: Figure out if we need to add our program name. */ addprog = (args == NULL || img->ParentHandle == NULL || img->FilePath == NULL) ? 1 : 0; if (!addprog) { addprog = (DevicePathType(img->FilePath) != MEDIA_DEVICE_PATH || DevicePathSubType(img->FilePath) != MEDIA_FILEPATH_DP || DevicePathNodeLength(img->FilePath) <= sizeof(FILEPATH_DEVICE_PATH)) ? 1 : 0; if (!addprog) { /* XXX todo. */ } } /* Part 2: count words. */ argc = (addprog) ? 1 : 0; argp = args; while (argp != NULL && *argp != 0) { argp = arg_skipsep(argp); if (*argp == 0) break; argc++; argp = arg_skipword(argp); } /* Part 3: build vector. */ argv = malloc((argc + 1) * sizeof(CHAR16*)); argc = 0; if (addprog) argv[argc++] = (CHAR16 *)L"loader.efi"; argp = args; while (argp != NULL && *argp != 0) { argp = arg_skipsep(argp); if (*argp == 0) break; argv[argc++] = argp; argp = arg_skipword(argp); /* Terminate the words. */ if (*argp != 0) *argp++ = 0; } argv[argc] = NULL; status = main(argc, argv); exit(status); return (status); }