Index: head/sys/boot/efi/boot1/Makefile =================================================================== --- head/sys/boot/efi/boot1/Makefile (revision 324708) +++ head/sys/boot/efi/boot1/Makefile (revision 324709) @@ -1,170 +1,159 @@ # $FreeBSD$ MAN= .include "../Makefile.inc" MK_SSP= no MK_FORTH= no PROG= boot1.sym INTERNALPROG= -WARNS?= 3 +WARNS?= 6 -# Include bcache code. -HAVE_BCACHE= yes - # We implement a slightly non-standard %S in that it always takes a # CHAR16 that's common in UEFI-land instead of a wchar_t. This only # seems to matter on arm64 where wchar_t defaults to an int instead # of a short. There's no good cast to use here so just ignore the # warnings for now. CWARNFLAGS.boot1.c+= -Wno-format # Disable warnings that are currently incompatible with the zfs boot code -CWARNFLAGS.zfs.c += -Wno-incompatible-pointer-types-discards-qualifiers -CWARNFLAGS.zfs.c += -Wno-missing-variable-declarations -CWARNFLAGS.zfs.c += -Wno-array-bounds -CWARNFLAGS.zfs.c += -Wno-cast-align -CWARNFLAGS.zfs.c += -Wno-cast-qual -CWARNFLAGS.zfs.c += -Wno-missing-prototypes -CWARNFLAGS.zfs.c += -Wno-sign-compare -CWARNFLAGS.zfs.c += -Wno-unused-parameter -CWARNFLAGS.zfs.c += -Wno-unused-function +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 +SRCS= boot1.c self_reloc.c start.S ufs_module.c .if ${MK_ZFS} != "no" -.PATH: ${.CURDIR}/../../../crypto/skein +SRCS+= zfs_module.c SRCS+= skein.c skein_block.c # Do not unroll skein loops, reduce code size CFLAGS+= -DSKEIN_LOOP=111 -.PATH: ${.CURDIR}/../../zfs -SRCS+= zfs.c +.PATH: ${.CURDIR}/../../../crypto/skein .endif .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201 CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized .endif -# Always add MI sources -.include "../../loader.mk" - -.PATH: ${.CURDIR}/arch/${MACHINE} - 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+= ${LIBEFI} ${LIBSA} LDADD+= ${LIBEFI} ${LIBSA} 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 -j set_Xcommand_set \ + -j .rela.dyn -j .reloc -j .eh_frame \ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} boot1.o: ${SASRC}/ufsread.c # The following inserts our objects into a template FAT file system # created by generate-fat.sh .include "${.CURDIR}/Makefile.fat" 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} xz -d -c ${.CURDIR}/fat-${MACHINE}.tmpl.xz > ${.TARGET} ${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 324708) +++ head/sys/boot/efi/boot1/boot1.c (revision 324709) @@ -1,737 +1,580 @@ /*- * 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 -#include -#include #include -#ifdef EFI_ZFS_BOOT -#include -#endif typedef CHAR16 efi_char; #include -#include - -#include "efi_drivers.h" -#include "efizfs.h" +#include "boot_module.h" #include "paths.h" static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3); -#ifdef EFI_DEBUG -#define DPRINTF(fmt, args...) printf(fmt, ##args) -#define DSTALL(d) BS->Stall(d) -#else -#define DPRINTF(fmt, ...) {} -#define DSTALL(d) {} -#endif -struct arch_switch archsw; /* MI/MD interface boundary */ - -static const efi_driver_t *efi_drivers[] = { - NULL -}; - -extern struct console efi_console; -#if defined(__amd64__) || defined(__i386__) -extern struct console comconsole; -extern struct console nullconsole; -#endif - +static const boot_module_t *boot_modules[] = +{ #ifdef EFI_ZFS_BOOT -uint64_t pool_guid; + &zfs_module, #endif - -struct fs_ops *file_system[] = { -#ifdef EFI_ZFS_BOOT - &zfs_fsops, -#endif - &dosfs_fsops, #ifdef EFI_UFS_BOOT - &ufs_fsops, + &ufs_module #endif - &cd9660_fsops, - &nfs_fsops, - &gzipfs_fsops, - &bzipfs_fsops, - NULL }; -struct devsw *devsw[] = { - &efipart_hddev, - &efipart_fddev, - &efipart_cddev, -#ifdef EFI_ZFS_BOOT - &zfs_dev, -#endif - NULL -}; - -struct console *consoles[] = { - &efi_console, - NULL -}; - -static EFI_LOADED_IMAGE *boot_image; -static EFI_DEVICE_PATH *imgpath; -static EFI_DEVICE_PATH *imgprefix; - -/* Definitions we don't actually need for boot, but we need to define - * to make the linker happy. - */ -struct file_format *file_formats[] = { NULL }; - -struct netif_driver *netif_drivers[] = { NULL }; - -static int -efi_autoload(void) -{ - printf("******** Boot block should not call autoload\n"); - return (-1); -} - -static ssize_t -efi_copyin(const void *src __unused, vm_offset_t dest __unused, - const size_t len __unused) -{ - printf("******** Boot block should not call copyin\n"); - return (-1); -} - -static ssize_t -efi_copyout(vm_offset_t src __unused, void *dest __unused, - const size_t len __unused) -{ - printf("******** Boot block should not call copyout\n"); - return (-1); -} - -static ssize_t -efi_readin(int fd __unused, vm_offset_t dest __unused, - const size_t len __unused) -{ - printf("******** Boot block should not call readin\n"); - return (-1); -} - +#define NUM_BOOT_MODULES nitems(boot_modules) /* The initial number of handles used to query EFI for partitions. */ #define NUM_HANDLES_INIT 24 +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; static EFI_GUID FreeBSDBootVarGUID = FREEBSD_BOOT_VAR_GUID; -static EFI_STATUS -do_load(const char *filepath, void **bufp, size_t *bufsize) +/* + * 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) { - struct stat st; - void *buf = NULL; - int fd, err; - size_t fsize, remaining; - ssize_t readsize; + void *out; - if ((fd = open(filepath, O_RDONLY)) < 0) { - return (ENOTSUP); - } + if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) + return (out); - if ((err = fstat(fd, &st)) != 0) { - goto close_file; - } + return (NULL); +} - fsize = st.st_size; - - if ((buf = malloc(fsize)) == NULL) { - err = ENOMEM; - goto close_file; - } - - remaining = fsize; - - do { - if ((readsize = read(fd, buf, fsize)) < 0) { - err = (-readsize); - goto free_buf; - } - - remaining -= readsize; - } while(remaining != 0); - - close(fd); - *bufsize = st.st_size; - *bufp = buf; - - close_file: - close(fd); - - return errno_to_efi_status(err); - - free_buf: - free(buf); - goto close_file; +void +Free(void *buf, const char *file __unused, int line __unused) +{ + if (buf != NULL) + (void)BS->FreePool(buf); } static EFI_STATUS efi_setenv_freebsd_wcs(const char *varname, CHAR16 *valstr) { CHAR16 *var = NULL; size_t len; EFI_STATUS rv; utf8_to_ucs2(varname, &var, &len); if (var == NULL) return (EFI_OUT_OF_RESOURCES); rv = RS->SetVariable(var, &FreeBSDBootVarGUID, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, (ucs2len(valstr) + 1) * sizeof(efi_char), valstr); free(var); return (rv); } -static int -probe_fs(const char *filepath) +/* + * 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) { - int fd; + size_t len; - if ((fd = open(filepath, O_RDONLY)) < 0) { - return (ENOTSUP); - } + if (imgpath == NULL || imgpath->Type != devpath->Type || + imgpath->SubType != devpath->SubType) + return (FALSE); - close(fd); + len = DevicePathNodeLength(imgpath); + if (len != DevicePathNodeLength(devpath)) + return (FALSE); - return (0); + return (memcmp(imgpath, devpath, (size_t)len) == 0); } -static int -probe_dev(struct devsw *dev, int unit, const char *filepath) +/* + * 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) { - struct devdesc currdev; - char *devname; - int err; - currdev.d_dev = dev; - currdev.d_type = currdev.d_dev->dv_type; - currdev.d_unit = unit; - currdev.d_opendata = NULL; - devname = efi_fmtdev(&currdev); + if (imgpath == NULL) + return (FALSE); - env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, - env_nounset); + while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) { + if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) && + IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) + return (TRUE); - err = probe_fs(filepath); + if (!nodes_match(imgpath, devpath)) + return (FALSE); - return (err); -} + imgpath = NextDevicePathNode(imgpath); + devpath = NextDevicePathNode(devpath); + } -static bool -check_preferred(EFI_HANDLE *h) -{ - EFI_DEVICE_PATH *path = efi_lookup_devpath(h); - bool out; - - if ((path = efi_lookup_devpath(h)) == NULL) - return (false); - - out = efi_devpath_is_prefix(imgpath, path) || - efi_devpath_is_prefix(imgprefix, path); - - return (out); + return (FALSE); } -bool -efi_zfs_is_preferred(EFI_HANDLE *h) +/* + * devpath_last returns the last non-path end node in devpath. + */ +static EFI_DEVICE_PATH * +devpath_last(EFI_DEVICE_PATH *devpath) { - return (check_preferred(h)); -} -static int -load_preferred(EFI_LOADED_IMAGE *img, const char *filepath, void **bufp, - size_t *bufsize, EFI_HANDLE *handlep) -{ - pdinfo_list_t *pdi_list; - pdinfo_t *dp, *pp; - char *devname; + while (!IsDevicePathEnd(NextDevicePathNode(devpath))) + devpath = NextDevicePathNode(devpath); -#ifdef EFI_ZFS_BOOT - /* Did efi_zfs_probe() detect the boot pool? */ - if (pool_guid != 0) { - struct zfs_devdesc currdev; - - currdev.d_dev = &zfs_dev; - currdev.d_unit = 0; - currdev.d_type = currdev.d_dev->dv_type; - currdev.d_opendata = NULL; - currdev.pool_guid = pool_guid; - currdev.root_guid = 0; - devname = efi_fmtdev(&currdev); - - env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, - env_nounset); - - if (probe_fs(filepath) == 0 && - do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { - *handlep = efizfs_get_handle_by_guid(pool_guid); - return (0); - } - } -#endif /* EFI_ZFS_BOOT */ - - /* We have device lists for hd, cd, fd, walk them all. */ - pdi_list = efiblk_get_pdinfo_list(&efipart_hddev); - STAILQ_FOREACH(dp, pdi_list, pd_link) { - struct disk_devdesc currdev; - - currdev.d_dev = &efipart_hddev; - currdev.d_type = currdev.d_dev->dv_type; - currdev.d_unit = dp->pd_unit; - currdev.d_opendata = NULL; - currdev.d_slice = -1; - currdev.d_partition = -1; - devname = efi_fmtdev(&currdev); - - env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, - env_nounset); - - if (check_preferred(dp->pd_handle) && - probe_fs(filepath) == 0 && - do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { - *handlep = dp->pd_handle; - return (0); - } - - /* Assuming GPT partitioning. */ - STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { - if (check_preferred(pp->pd_handle)) { - currdev.d_slice = pp->pd_unit; - currdev.d_partition = 255; - devname = efi_fmtdev(&currdev); - - env_setenv("currdev", EV_VOLATILE, devname, - efi_setcurrdev, env_nounset); - - if (probe_fs(filepath) == 0 && - do_load(filepath, bufp, bufsize) == - EFI_SUCCESS) { - *handlep = pp->pd_handle; - return (0); - } - } - } - } - - pdi_list = efiblk_get_pdinfo_list(&efipart_cddev); - STAILQ_FOREACH(dp, pdi_list, pd_link) { - if ((dp->pd_handle == img->DeviceHandle || - dp->pd_alias == img->DeviceHandle || - check_preferred(dp->pd_handle)) && - probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && - do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { - *handlep = dp->pd_handle; - return (0); - } - } - - pdi_list = efiblk_get_pdinfo_list(&efipart_fddev); - STAILQ_FOREACH(dp, pdi_list, pd_link) { - if ((dp->pd_handle == img->DeviceHandle || - check_preferred(dp->pd_handle)) && - probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && - do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { - *handlep = dp->pd_handle; - return (0); - } - } - - return (ENOENT); + return (devpath); } -static int -load_all(const char *filepath, void **bufp, size_t *bufsize, - EFI_HANDLE *handlep) +/* + * 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) { - pdinfo_list_t *pdi_list; - pdinfo_t *dp, *pp; - zfsinfo_list_t *zfsi_list; - zfsinfo_t *zi; - char *devname; + UINTN i; + dev_info_t *dev; + const boot_module_t *mod; -#ifdef EFI_ZFS_BOOT - zfsi_list = efizfs_get_zfsinfo_list(); - STAILQ_FOREACH(zi, zfsi_list, zi_link) { - struct zfs_devdesc currdev; + 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; - currdev.d_dev = &zfs_dev; - currdev.d_unit = 0; - currdev.d_type = currdev.d_dev->dv_type; - currdev.d_opendata = NULL; - currdev.pool_guid = zi->zi_pool_guid; - currdev.root_guid = 0; - devname = efi_fmtdev(&currdev); - - env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, - env_nounset); - - if (probe_fs(filepath) == 0 && - do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { - *handlep = zi->zi_handle; - - return (0); - } - } -#endif /* EFI_ZFS_BOOT */ - - /* We have device lists for hd, cd, fd, walk them all. */ - pdi_list = efiblk_get_pdinfo_list(&efipart_hddev); - STAILQ_FOREACH(dp, pdi_list, pd_link) { - struct disk_devdesc currdev; - - currdev.d_dev = &efipart_hddev; - currdev.d_type = currdev.d_dev->dv_type; - currdev.d_unit = dp->pd_unit; - currdev.d_opendata = NULL; - currdev.d_slice = -1; - currdev.d_partition = -1; - devname = efi_fmtdev(&currdev); - - env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, - env_nounset); - - if (probe_fs(filepath) == 0 && - do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { - *handlep = dp->pd_handle; - - return (0); - } - - /* Assuming GPT partitioning. */ - STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { - currdev.d_slice = pp->pd_unit; - currdev.d_partition = 255; - devname = efi_fmtdev(&currdev); - - env_setenv("currdev", EV_VOLATILE, devname, - efi_setcurrdev, env_nounset); - - if (probe_fs(filepath) == 0 && - do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { - *handlep = pp->pd_handle; - - return (0); + if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == + EFI_SUCCESS) { + *devinfop = dev; + *modp = mod; + return (EFI_SUCCESS); } } } - pdi_list = efiblk_get_pdinfo_list(&efipart_cddev); - STAILQ_FOREACH(dp, pdi_list, pd_link) { - if (probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && - do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { - *handlep = dp->pd_handle; - - return (0); - } - } - - pdi_list = efiblk_get_pdinfo_list(&efipart_fddev); - STAILQ_FOREACH(dp, pdi_list, pd_link) { - if (probe_dev(&efipart_fddev, dp->pd_unit, filepath) == 0 && - do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { - *handlep = dp->pd_handle; - - return (0); - } - } - - return (ENOENT); -} - -static EFI_STATUS -load_loader(EFI_HANDLE *handlep, void **bufp, size_t *bufsize) -{ - /* Try the preferred handles first, then all the handles */ - if (load_preferred(boot_image, PATH_LOADER_EFI, bufp, bufsize, - handlep) == 0) { - return (0); - } - - if (load_all(PATH_LOADER_EFI, bufp, bufsize, handlep) == 0) { - return (0); - } - 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; - EFI_HANDLE fshandle; + dev_info_t *dev; + const boot_module_t *mod; EFI_HANDLE loaderhandle; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; - EFI_DEVICE_PATH *fspath; - status = load_loader(&fshandle, &loaderbuf, &loadersize); - - if (status != EFI_SUCCESS) { - return (status); - } - - fspath = NULL; - if (status == EFI_SUCCESS) { - status = BS->OpenProtocol(fshandle, &DevicePathGUID, - (void **)&fspath, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); + if (status != EFI_SUCCESS) { + status = load_loader(&mod, &dev, &loaderbuf, &loadersize, + FALSE); if (status != EFI_SUCCESS) { - DPRINTF("Failed to get image DevicePath (%lu)\n", - EFI_ERROR_CODE(status)); - } - DPRINTF("filesystem device path: %s\n", devpath_str(fspath)); + 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 = do_load(PATH_DOTCONFIG, &buf, &bufsize); + status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); if (status == EFI_NOT_FOUND) - status = do_load(PATH_CONFIG, &buf, &bufsize); + 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, efi_devpath_last_node(fspath), + if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath), loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { - printf("Failed to load image, size: %zu, (%lu)\n", - loadersize, EFI_ERROR_CODE(status)); + printf("Failed to load image provided by %s, size: %zu, (%lu)\n", + mod->name, loadersize, EFI_ERROR_CODE(status)); goto errout; } - if ((status = BS->OpenProtocol(loaderhandle, &LoadedImageGUID, - (VOID**)&loaded_image, IH, NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL)) != EFI_SUCCESS) { - printf("Failed to query LoadedImage (%lu)\n", - EFI_ERROR_CODE(status)); + 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 = fshandle; + 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 (%lu)\n", - EFI_ERROR_CODE(status)); + 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); } -EFI_STATUS -main(int argc __unused, CHAR16 *argv[] __unused) +/* + * 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) { - EFI_STATUS status; + dev_info_t *devinfo; + EFI_BLOCK_IO *blkio; + EFI_DEVICE_PATH *devpath; + EFI_STATUS status; + UINTN i; - SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; - UINTN i, max_dim, best_mode, cols, rows; - CHAR16 *text; + /* Figure out if we're dealing with an actual partition. */ + status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); + if (status == EFI_UNSUPPORTED) + return (status); - archsw.arch_autoload = efi_autoload; - archsw.arch_getdev = efi_getdev; - archsw.arch_copyin = efi_copyin; - archsw.arch_copyout = efi_copyout; - archsw.arch_readin = efi_readin; -#ifdef EFI_ZFS_BOOT - /* Note this needs to be set before ZFS init. */ - archsw.arch_zfs_probe = efi_zfs_probe; + if (status != EFI_SUCCESS) { + DPRINTF("\nFailed to query DevicePath (%lu)\n", + EFI_ERROR_CODE(status)); + return (status); + } +#ifdef EFI_DEBUG + { + CHAR16 *text = efi_devpath_name(devpath); + DPRINTF("probing: %S\n", text); + efi_free_devpath_name(text); + } #endif + status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); + if (status == EFI_UNSUPPORTED) + return (status); - /* Init the time source */ - efi_time_init(); - cons_probe(); + 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++) { + devinfo = malloc(sizeof(*devinfo)); + if (devinfo == NULL) { + DPRINTF("\nFailed to allocate devinfo\n"); + 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); + free(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; + CHAR16 *text; + + /* 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++) { + 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) + if (max_dim > 0) conout->SetMode(conout, best_mode); - conout->EnableCursor(conout, TRUE); conout->ClearScreen(conout); - /* Print this here, so people know it's at least starting. */ printf("\n>> FreeBSD EFI boot block\n"); printf(" Loader path: %s\n\n", PATH_LOADER_EFI); - - /* Get the image path and trim it to get the disk on which we - * found this loader. - */ - if ((status = BS->OpenProtocol(IH, &LoadedImageGUID, - (VOID**)&boot_image, IH, NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL)) != EFI_SUCCESS) { - panic("Failed to query LoadedImage (%lu)\n", - EFI_ERROR_CODE(status)); + 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'); /* Determine the devpath of our image so we can prefer it. */ - status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&boot_image); + status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img); imgpath = NULL; if (status == EFI_SUCCESS) { - text = efi_devpath_name(boot_image->FilePath); + text = efi_devpath_name(img->FilePath); printf(" Load Path: %S\n", text); efi_setenv_freebsd_wcs("Boot1Path", text); efi_free_devpath_name(text); - status = BS->HandleProtocol(boot_image->DeviceHandle, &DevicePathGUID, + status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID, (void **)&imgpath); if (status != EFI_SUCCESS) { DPRINTF("Failed to get image DevicePath (%lu)\n", EFI_ERROR_CODE(status)); } else { text = efi_devpath_name(imgpath); printf(" Load Device: %S\n", text); efi_setenv_freebsd_wcs("Boot1Dev", text); efi_free_devpath_name(text); } } - /* The loaded image device path ends with a partition, then a - * file path. Trim them both to get the actual disk. - */ - if ((imgprefix = efi_devpath_trim(imgpath)) == NULL || - (imgprefix = efi_devpath_trim(imgprefix)) == NULL) { - panic("Couldn't trim device path"); - } + /* Get all the device handles */ + hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); + handles = malloc(hsize); + if (handles == NULL) { + printf("Failed to allocate %d handles\n", NUM_HANDLES_INIT); + } - /* - * Initialize the block cache. Set the upper limit. - */ - bcache_init(32768, 512); - - printf("\n Initializing modules:"); - - for (i = 0; efi_drivers[i] != NULL; i++) { - printf(" %s", efi_drivers[i]->name); - if (efi_drivers[i]->init != NULL) - efi_drivers[i]->init(); + status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, + &hsize, handles); + switch (status) { + case EFI_SUCCESS: + break; + case EFI_BUFFER_TOO_SMALL: + free(handles); + handles = malloc(hsize); + if (handles == NULL) + efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n", + NUM_HANDLES_INIT); + status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, + NULL, &hsize, handles); + if (status != EFI_SUCCESS) + efi_panic(status, "Failed to get device handles\n"); + break; + default: + efi_panic(status, "Failed to get device handles\n"); + break; } - for (i = 0; devsw[i] != NULL; i++) { - if (devsw[i]->dv_init != NULL) { - printf(" %s", devsw[i]->dv_name); - (devsw[i]->dv_init)(); - } - } + /* Scan all partitions, probing with all modules. */ + nhandles = hsize / sizeof(*handles); + printf(" Probing %zu block devices...", nhandles); + DPRINTF("\n"); - putchar('\n'); + 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... */ efi_panic(EFI_LOAD_ERROR, "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; +} + +/* * OK. We totally give up. Exit back to EFI with a sensible status so * it can try the next option on the list. */ static void efi_panic(EFI_STATUS s, const char *fmt, ...) { - va_list ap; + va_list ap; - printf("panic: "); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); + printf("panic: "); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); - BS->Exit(IH, s, 0, NULL); + BS->Exit(IH, s, 0, NULL); +} + +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/boot1/boot_module.h =================================================================== --- head/sys/boot/efi/boot1/boot_module.h (nonexistent) +++ head/sys/boot/efi/boot1/boot_module.h (revision 324709) @@ -0,0 +1,109 @@ +/*- + * 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 + +#include +#include +#include + +#ifdef EFI_DEBUG +#define DPRINTF(fmt, args...) printf(fmt, ##args) +#define DSTALL(d) BS->Stall(d) +#else +#define DPRINTF(fmt, ...) {} +#define DSTALL(d) {} +#endif + +/* EFI device info */ +typedef struct dev_info +{ + EFI_BLOCK_IO *dev; + EFI_DEVICE_PATH *devpath; + EFI_HANDLE *devhandle; + void *devdata; + BOOLEAN preferred; + 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)(void); + + /* + * 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 the specified file. + * + * 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 *filepath, dev_info_t *devinfo, + void **buf, size_t *bufsize); + + /* status outputs information about the probed devices. */ + void (*status)(void); + + /* valid devices as found by probe. */ + dev_info_t *(*devices)(void); +} boot_module_t; + +/* Standard boot modules. */ +#ifdef EFI_UFS_BOOT +extern const boot_module_t ufs_module; +#endif +#ifdef EFI_ZFS_BOOT +extern const boot_module_t zfs_module; +#endif + +/* Functions available to modules. */ +extern void add_device(dev_info_t **devinfop, dev_info_t *devinfo); +extern int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); +#endif Property changes on: head/sys/boot/efi/boot1/boot_module.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/sys/boot/efi/boot1/ufs_module.c =================================================================== --- head/sys/boot/efi/boot1/ufs_module.c (nonexistent) +++ head/sys/boot/efi/boot1/ufs_module.c (revision 324709) @@ -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 +#include +#include +#include +#include + +#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: %ju, size: %d, " + "status: %lu\n", devinfo->dev, + devinfo->dev->Media->MediaId, (uintmax_t)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 +load(const char *filepath, dev_info_t *dev, void **bufp, size_t *bufsize) +{ + ufs_ino_t ino; + EFI_STATUS status; + size_t size; + ssize_t read; + void *buf; + +#ifdef EFI_DEBUG + { + CHAR16 *text = efi_devpath_name(dev->devpath); + DPRINTF("Loading '%s' from %S\n", filepath, text); + efi_free_devpath_name(text); + } +#endif + if (init_dev(dev) < 0) { + DPRINTF("Failed to init device\n"); + return (EFI_UNSUPPORTED); + } + + if ((ino = lookup(filepath)) == 0) { + DPRINTF("Failed to lookup '%s' (file not found?)\n", filepath); + return (EFI_NOT_FOUND); + } + + if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) { + printf("Failed to read size of '%s' ino: %d\n", filepath, ino); + return (EFI_INVALID_PARAMETER); + } + + if ((status = BS->AllocatePool(EfiLoaderData, size, &buf)) != + EFI_SUCCESS) { + printf("Failed to allocate read buffer %zu for '%s' (%lu)\n", + size, filepath, EFI_ERROR_CODE(status)); + return (status); + } + + read = fsread(ino, buf, size); + if ((size_t)read != size) { + printf("Failed to read '%s' (%zd != %zu)\n", filepath, read, + size); + (void)BS->FreePool(buf); + return (EFI_INVALID_PARAMETER); + } + + DPRINTF("Load complete\n"); + + *bufp = buf; + *bufsize = size; + + return (EFI_SUCCESS); +} + +static void +status(void) +{ + 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); + } +} + +static dev_info_t * +_devices(void) +{ + + return (devices); +} + +const boot_module_t ufs_module = +{ + .name = "UFS", + .probe = probe, + .load = load, + .status = status, + .devices = _devices +}; Property changes on: head/sys/boot/efi/boot1/ufs_module.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 Index: head/sys/boot/efi/boot1/zfs_module.c =================================================================== --- head/sys/boot/efi/boot1/zfs_module.c (nonexistent) +++ head/sys/boot/efi/boot1/zfs_module.c (revision 324709) @@ -0,0 +1,248 @@ +/*- + * 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$ + */ +#include +#include +#include +#include +#include +#include +#include + +#include "boot_module.h" + +#include "libzfs.h" +#include "zfsimpl.c" + +static dev_info_t *devices; + +uint64_t +ldi_get_size(void *priv) +{ + dev_info_t *devinfo = priv; + + return (devinfo->dev->Media->BlockSize * + (devinfo->dev->Media->LastBlock + 1)); +} + +static int +vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) +{ + dev_info_t *devinfo; + uint64_t lba; + size_t size, remainder, rb_size, blksz; + char *bouncebuf = NULL, *rb_buf; + EFI_STATUS status; + + devinfo = (dev_info_t *)priv; + lba = off / devinfo->dev->Media->BlockSize; + remainder = off % devinfo->dev->Media->BlockSize; + + rb_buf = buf; + rb_size = bytes; + + /* + * If we have remainder from off, we need to add remainder part. + * Since buffer must be multiple of the BlockSize, round it all up. + */ + size = roundup2(bytes + remainder, devinfo->dev->Media->BlockSize); + blksz = size; + if (remainder != 0 || size != bytes) { + rb_size = devinfo->dev->Media->BlockSize; + bouncebuf = malloc(rb_size); + if (bouncebuf == NULL) { + printf("vdev_read: out of memory\n"); + return (-1); + } + rb_buf = bouncebuf; + blksz = rb_size - remainder; + } + + while (bytes > 0) { + status = devinfo->dev->ReadBlocks(devinfo->dev, + devinfo->dev->Media->MediaId, lba, rb_size, rb_buf); + if (EFI_ERROR(status)) + goto error; + if (bytes < blksz) + blksz = bytes; + if (bouncebuf != NULL) + memcpy(buf, rb_buf + remainder, blksz); + buf = (void *)((uintptr_t)buf + blksz); + bytes -= blksz; + lba++; + remainder = 0; + blksz = rb_size; + } + + free(bouncebuf); + return (0); + +error: + free(bouncebuf); + DPRINTF("vdev_read: failed dev: %p, id: %u, lba: %ju, size: %zu," + " rb_size: %zu, status: %lu\n", devinfo->dev, + devinfo->dev->Media->MediaId, (uintmax_t)lba, bytes, rb_size, + EFI_ERROR_CODE(status)); + return (-1); +} + +static EFI_STATUS +probe(dev_info_t *dev) +{ + spa_t *spa; + dev_info_t *tdev; + EFI_STATUS status; + + /* ZFS consumes the dev on success so we need a copy. */ + if ((status = BS->AllocatePool(EfiLoaderData, sizeof(*dev), + (void**)&tdev)) != EFI_SUCCESS) { + DPRINTF("Failed to allocate tdev (%lu)\n", + EFI_ERROR_CODE(status)); + return (status); + } + memcpy(tdev, dev, sizeof(*dev)); + + if (vdev_probe(vdev_read, tdev, &spa) != 0) { + (void)BS->FreePool(tdev); + return (EFI_UNSUPPORTED); + } + + dev->devdata = spa; + add_device(&devices, dev); + + return (EFI_SUCCESS); +} + +static EFI_STATUS +load(const char *filepath, dev_info_t *devinfo, void **bufp, size_t *bufsize) +{ + spa_t *spa; + struct zfsmount zfsmount; + dnode_phys_t dn; + struct stat st; + int err; + void *buf; + EFI_STATUS status; + + spa = devinfo->devdata; + +#ifdef EFI_DEBUG + { + CHAR16 *text = efi_devpath_name(devinfo->devpath); + DPRINTF("load: '%s' spa: '%s', devpath: %S\n", filepath, + spa->spa_name, text); + efi_free_devpath_name(text); + } +#endif + if ((err = zfs_spa_init(spa)) != 0) { + DPRINTF("Failed to load pool '%s' (%d)\n", spa->spa_name, err); + return (EFI_NOT_FOUND); + } + + if ((err = zfs_mount(spa, 0, &zfsmount)) != 0) { + DPRINTF("Failed to mount pool '%s' (%d)\n", spa->spa_name, err); + return (EFI_NOT_FOUND); + } + + if ((err = zfs_lookup(&zfsmount, filepath, &dn)) != 0) { + if (err == ENOENT) { + DPRINTF("Failed to find '%s' on pool '%s' (%d)\n", + filepath, spa->spa_name, err); + return (EFI_NOT_FOUND); + } + printf("Failed to lookup '%s' on pool '%s' (%d)\n", filepath, + spa->spa_name, err); + return (EFI_INVALID_PARAMETER); + } + + if ((err = zfs_dnode_stat(spa, &dn, &st)) != 0) { + printf("Failed to stat '%s' on pool '%s' (%d)\n", filepath, + spa->spa_name, err); + return (EFI_INVALID_PARAMETER); + } + + if ((status = BS->AllocatePool(EfiLoaderData, (UINTN)st.st_size, &buf)) + != EFI_SUCCESS) { + printf("Failed to allocate load buffer %jd for pool '%s' for '%s' " + "(%lu)\n", (intmax_t)st.st_size, spa->spa_name, filepath, EFI_ERROR_CODE(status)); + return (EFI_INVALID_PARAMETER); + } + + if ((err = dnode_read(spa, &dn, 0, buf, st.st_size)) != 0) { + printf("Failed to read node from %s (%d)\n", spa->spa_name, + err); + (void)BS->FreePool(buf); + return (EFI_INVALID_PARAMETER); + } + + *bufsize = st.st_size; + *bufp = buf; + + return (EFI_SUCCESS); +} + +static void +status(void) +{ + spa_t *spa; + + spa = STAILQ_FIRST(&zfs_pools); + if (spa == NULL) { + printf("%s found no pools\n", zfs_module.name); + return; + } + + printf("%s found the following pools:", zfs_module.name); + STAILQ_FOREACH(spa, &zfs_pools, spa_link) + printf(" %s", spa->spa_name); + + printf("\n"); +} + +static void +init(void) +{ + + zfs_init(); +} + +static dev_info_t * +_devices(void) +{ + + return (devices); +} + +const boot_module_t zfs_module = +{ + .name = "ZFS", + .init = init, + .probe = probe, + .load = load, + .status = status, + .devices = _devices +}; Property changes on: head/sys/boot/efi/boot1/zfs_module.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 Index: head/sys/boot/efi/libefi/efi_main.c =================================================================== --- head/sys/boot/efi/libefi/efi_main.c (revision 324708) +++ head/sys/boot/efi/libefi/efi_main.c (nonexistent) @@ -1,188 +0,0 @@ -/*- - * 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 - -static EFI_PHYSICAL_ADDRESS heap; -static UINTN heapsize; - -void -efi_exit(EFI_STATUS exit_code) -{ - - BS->FreePages(heap, EFI_SIZE_TO_PAGES(heapsize)); - BS->Exit(IH, exit_code, 0, NULL); -} - -void -exit(int status) -{ - - efi_exit(EFI_LOAD_ERROR); -} - -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 efi_exit() from here on... */ - - status = BS->HandleProtocol(IH, &image_protocol, (VOID**)&img); - if (status != EFI_SUCCESS) - efi_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); - efi_exit(status); - return (status); -} Property changes on: head/sys/boot/efi/libefi/efi_main.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/boot/efi/libefi/Makefile =================================================================== --- head/sys/boot/efi/libefi/Makefile (revision 324708) +++ head/sys/boot/efi/libefi/Makefile (revision 324709) @@ -1,61 +1,60 @@ # $FreeBSD$ .include .if ${MK_FORTH} != "no" .include "../../ficl.mk" .endif LIB= efi INTERNALLIB= WARNS?= 2 -SRCS= delay.c devpath.c efi_console.c efichar.c efinet.c efipart.c env.c \ - errno.c handles.c wchar.c libefi.c efi_driver_utils.c efizfs.c \ - devicename.c efi_main.c +SRCS= delay.c devpath.c efi_console.c efichar.c efinet.c efipart.c env.c errno.c \ + handles.c wchar.c libefi.c efi_driver_utils.c efizfs.c devicename.c .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" SRCS+= time.c .elif ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" SRCS+= time_event.c .endif # We implement a slightly non-standard %S in that it always takes a # CHAR16 that's common in UEFI-land instead of a wchar_t. This only # seems to matter on arm64 where wchar_t defaults to an int instead # of a short. There's no good cast to use here so just ignore the # warnings for now. CWARNFLAGS.efinet.c+= -Wno-format CWARNFLAGS.efipart.c+= -Wno-format CWARNFLAGS.env.c+= -Wno-format .if ${MACHINE_CPUARCH} == "aarch64" CFLAGS+= -mgeneral-regs-only .endif .if ${MACHINE_ARCH} == "amd64" CFLAGS+= -fPIC -mno-red-zone .endif CFLAGS+= -I${SYSDIR} CFLAGS+= -I${.CURDIR}/../include CFLAGS+= -I${.CURDIR}/../include/${MACHINE} .if ${MK_ZFS} != "no" CFLAGS+= -I${.CURDIR}/../../zfs CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs CFLAGS+= -I${.CURDIR}/../../../crypto/skein CFLAGS+= -DEFI_ZFS_BOOT .endif # Pick up the bootstrap header for some interface items CFLAGS+= -I${.CURDIR}/../../common # Handle FreeBSD specific %b and %D printf format specifiers CFLAGS+= ${FORMAT_EXTENSIONS} # Do not use TERM_EMU on arm and arm64 as it doesn't behave well with serial console .if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "aarch64" CFLAGS+= -DTERM_EMU .endif CFLAGS+= -DLIBEFI .include Index: head/sys/boot/efi/loader/Makefile =================================================================== --- head/sys/boot/efi/loader/Makefile (revision 324708) +++ head/sys/boot/efi/loader/Makefile (revision 324709) @@ -1,162 +1,163 @@ # $FreeBSD$ MAN= .include MK_SSP= no PROG= loader.sym INTERNALPROG= WARNS?= 3 LOADER_NET_SUPPORT?= yes LOADER_MSDOS_SUPPORT?= yes LOADER_UFS_SUPPORT?= yes LOADER_CD9660_SUPPORT?= no LOADER_EXT2FS_SUPPORT?= no # architecture-specific loader code SRCS= autoload.c \ bootinfo.c \ conf.c \ copy.c \ + efi_main.c \ main.c \ self_reloc.c \ smbios.c \ vers.c .if ${MK_ZFS} != "no" SRCS+= zfs.c .PATH: ${.CURDIR}/../../zfs SRCS+= skein.c skein_block.c # Do not unroll skein loops, reduce code size CFLAGS+= -DSKEIN_LOOP=111 .PATH: ${.CURDIR}/../../../crypto/skein # Disable warnings that are currently incompatible with the zfs boot code CWARNFLAGS.zfs.c+= -Wno-sign-compare CWARNFLAGS.zfs.c+= -Wno-array-bounds CWARNFLAGS.zfs.c+= -Wno-missing-prototypes .endif .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201 CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized .endif # We implement a slightly non-standard %S in that it always takes a # CHAR16 that's common in UEFI-land instead of a wchar_t. This only # seems to matter on arm64 where wchar_t defaults to an int instead # of a short. There's no good cast to use here so just ignore the # warnings for now. CWARNFLAGS.main.c+= -Wno-format .PATH: ${.CURDIR}/arch/${MACHINE} # For smbios.c .PATH: ${.CURDIR}/../../i386/libi386 .include "${.CURDIR}/arch/${MACHINE}/Makefile.inc" CFLAGS+= -I${.CURDIR} CFLAGS+= -I${.CURDIR}/arch/${MACHINE} CFLAGS+= -I${.CURDIR}/../include CFLAGS+= -I${.CURDIR}/../include/${MACHINE} CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. CFLAGS+= -I${.CURDIR}/../../i386/libi386 .if ${MK_ZFS} != "no" CFLAGS+= -I${.CURDIR}/../../zfs CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs CFLAGS+= -I${.CURDIR}/../../../crypto/skein CFLAGS+= -DEFI_ZFS_BOOT .endif CFLAGS+= -DNO_PCI -DEFI .if !defined(BOOT_HIDE_SERIAL_NUMBERS) # Export serial numbers, UUID, and asset tag from loader. CFLAGS+= -DSMBIOS_SERIAL_NUMBERS .if defined(BOOT_LITTLE_ENDIAN_UUID) # Use little-endian UUID format as defined in SMBIOS 2.6. CFLAGS+= -DSMBIOS_LITTLE_ENDIAN_UUID .elif defined(BOOT_NETWORK_ENDIAN_UUID) # Use network-endian UUID format for backward compatibility. CFLAGS+= -DSMBIOS_NETWORK_ENDIAN_UUID .endif .endif LOADER_FDT_SUPPORT?= no .if ${MK_FDT} != "no" && ${LOADER_FDT_SUPPORT} != "no" CFLAGS+= -I${.CURDIR}/../../fdt CFLAGS+= -I${.OBJDIR}/../../fdt CFLAGS+= -DLOADER_FDT_SUPPORT LIBEFI_FDT= ${.OBJDIR}/../../efi/fdt/libefi_fdt.a LIBFDT= ${.OBJDIR}/../../fdt/libfdt.a .endif # Include bcache code. HAVE_BCACHE= yes .if defined(EFI_STAGING_SIZE) CFLAGS+= -DEFI_STAGING_SIZE=${EFI_STAGING_SIZE} .endif # Always add MI sources .include "../../loader.mk" FILES+= loader.efi FILESMODE_loader.efi= ${BINMODE} LDSCRIPT= ${.CURDIR}/arch/${MACHINE}/ldscript.${MACHINE} LDFLAGS+= -Wl,-T${LDSCRIPT},-Bsymbolic,-znotext -shared CLEANFILES+= loader.efi NEWVERSWHAT= "EFI loader" ${MACHINE} 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 loader.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 -j set_Xcommand_set \ -j set_Xficl_compile_set \ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} LIBEFI= ${.OBJDIR}/../libefi/libefi.a DPADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSA} \ ${LDSCRIPT} LDADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSA} .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/loader/efi_main.c =================================================================== --- head/sys/boot/efi/loader/efi_main.c (nonexistent) +++ head/sys/boot/efi/loader/efi_main.c (revision 324709) @@ -0,0 +1,188 @@ +/*- + * 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 + +static EFI_PHYSICAL_ADDRESS heap; +static UINTN heapsize; + +void +efi_exit(EFI_STATUS exit_code) +{ + + BS->FreePages(heap, EFI_SIZE_TO_PAGES(heapsize)); + BS->Exit(IH, exit_code, 0, NULL); +} + +void +exit(int status) +{ + + efi_exit(EFI_LOAD_ERROR); +} + +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 efi_exit() from here on... */ + + status = BS->HandleProtocol(IH, &image_protocol, (VOID**)&img); + if (status != EFI_SUCCESS) + efi_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); + efi_exit(status); + return (status); +} Property changes on: head/sys/boot/efi/loader/efi_main.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