Index: lib/libstand/Makefile =================================================================== --- lib/libstand/Makefile +++ lib/libstand/Makefile @@ -41,7 +41,7 @@ .PATH: ${LIBC_SRC}/string SRCS+= bcmp.c bcopy.c bzero.c ffs.c fls.c \ memccpy.c memchr.c memcmp.c memcpy.c memmove.c memset.c \ - qdivrem.c strcat.c strchr.c strcmp.c strcpy.c \ + qdivrem.c strcat.c strchr.c strcmp.c strcpy.c stpcpy.c stpncpy.c \ strcspn.c strlcat.c strlcpy.c strlen.c strncat.c strncmp.c strncpy.c \ strpbrk.c strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c .if ${MACHINE_CPUARCH} == "arm" Index: lib/libstand/stand.h =================================================================== --- lib/libstand/stand.h +++ lib/libstand/stand.h @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD$ - * From $NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $ + * From $NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $ */ /*- @@ -131,7 +131,7 @@ #define SEEK_CUR 1 /* set file offset to current plus offset */ #define SEEK_END 2 /* set file offset to EOF plus offset */ -/* +/* * Device switch */ struct devsw { @@ -166,9 +166,10 @@ #define DEVT_NONE 0 #define DEVT_DISK 1 #define DEVT_NET 2 -#define DEVT_CD 3 +#define DEVT_CD 3 #define DEVT_ZFS 4 #define DEVT_FD 5 +#define DEVT_EFI 6 int d_unit; void *d_opendata; }; @@ -280,7 +281,7 @@ extern void srandom(u_long seed); extern u_long random(void); - + /* imports from stdlib, locally modified */ extern long strtol(const char *, char **, int); extern unsigned long strtoul(const char *, char **, int); @@ -369,9 +370,9 @@ extern int null_readdir(struct open_file *f, struct dirent *d); -/* - * Machine dependent functions and data, must be provided or stubbed by - * the consumer +/* + * Machine dependent functions and data, must be provided or stubbed by + * the consumer */ extern int getchar(void); extern int ischar(void); Index: sys/boot/efi/include/efilib.h =================================================================== --- sys/boot/efi/include/efilib.h +++ sys/boot/efi/include/efilib.h @@ -32,9 +32,10 @@ #include #include +#include extern EFI_HANDLE IH; -extern EFI_SYSTEM_TABLE *ST; +extern EFI_SYSTEM_TABLE *ST; extern EFI_BOOT_SERVICES *BS; extern EFI_RUNTIME_SERVICES *RS; @@ -42,7 +43,9 @@ extern struct devsw efipart_cddev; extern struct devsw efipart_hddev; extern struct devsw efinet_dev; +extern struct devsw efifs_dev; extern struct netif_driver efinetif; +extern struct fs_ops efifs_fsops; /* EFI block device data, included here to help efi_zfs_probe() */ typedef STAILQ_HEAD(pdinfo_list, pdinfo) pdinfo_list_t; @@ -79,6 +82,7 @@ void efi_free_devpath_name(CHAR16 *); int efi_status_to_errno(EFI_STATUS); +EFI_STATUS errno_to_efi_status(int errno); void efi_time_init(void); void efi_time_fini(void); @@ -87,12 +91,18 @@ void exit(EFI_STATUS status); void delay(int usecs); +int efifs_parsedev(struct devdesc *, const char *, const char **); + /* EFI environment initialization. */ void efi_init_environment(void); /* CHAR16 utility functions. */ -int wcscmp(CHAR16 *, CHAR16 *); +int wcscmp(const CHAR16 *, const CHAR16 *); +size_t wcslen(const CHAR16 *s); void cpy8to16(const char *, CHAR16 *, size_t); void cpy16to8(const CHAR16 *, char *, size_t); +time_t from_efi_time(EFI_TIME *efi_time); +void to_efi_time(EFI_TIME *efi_time, time_t time); + #endif /* _LOADER_EFILIB_H */ Index: sys/boot/efi/include/efiprot.h =================================================================== --- sys/boot/efi/include/efiprot.h +++ sys/boot/efi/include/efiprot.h @@ -27,6 +27,8 @@ --*/ +#include + // // Device Path protocol // @@ -555,4 +557,80 @@ CHAR8 *SupportedLanguages; } EFI_UNICODE_COLLATION_INTERFACE; +// +// Driver Binding protocol +// + +#define DRIVER_BINDING_PROTOCOL \ + { 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71} } + +INTERFACE_DECL(_EFI_DRIVER_BINDING); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH *RemainingPath + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_START) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH *RemainingPath + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_STOP) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +typedef struct _EFI_DRIVER_BINDING { + EFI_DRIVER_BINDING_SUPPORTED Supported; + EFI_DRIVER_BINDING_START Start; + EFI_DRIVER_BINDING_STOP Stop; + UINT32 Version; + EFI_HANDLE ImageHandle; + EFI_HANDLE DriverBindingHandle; +} EFI_DRIVER_BINDING; + +// +// Component Name Protocol 2 +// + +#define COMPONENT_NAME2_PROTOCOL \ + { 0x6a7a5cff, 0xe8d9, 0x4f70, {0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14 } } + +INTERFACE_DECL(_EFI_COMPONENT_NAME2); + +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME_GET_DRIVER_NAME) ( + IN struct _EFI_COMPONENT_NAME2 *This, + IN CHAR8 * Language, + OUT CHAR16 **DriverName + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) ( + IN struct _EFI_COMPONENT_NAME2 *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +typedef struct _EFI_COMPONENT_NAME2 { + EFI_COMPONENT_NAME_GET_DRIVER_NAME GetDriverName; + EFI_COMPONENT_NAME_GET_CONTROLLER_NAME GetControllerName; + CHAR8 **SupportedLanguages; +} EFI_COMPONENT_NAME2; + #endif Index: sys/boot/efi/libefi/Makefile =================================================================== --- sys/boot/efi/libefi/Makefile +++ sys/boot/efi/libefi/Makefile @@ -12,7 +12,7 @@ WARNS?= 2 SRCS= delay.c devpath.c efi_console.c efinet.c efipart.c env.c errno.c \ - handles.c wchar.c libefi.c + handles.c wchar.c libefi.c efifs.c .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" SRCS+= time.c Index: sys/boot/efi/libefi/devpath.c =================================================================== --- sys/boot/efi/libefi/devpath.c +++ sys/boot/efi/libefi/devpath.c @@ -30,6 +30,8 @@ #include #include +#include "efidevp.h" + static EFI_GUID ImageDevicePathGUID = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; Index: sys/boot/efi/libefi/efifs.c =================================================================== --- /dev/null +++ sys/boot/efi/libefi/efifs.c @@ -0,0 +1,550 @@ +/*- + * Copyright (c) 2017 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 + +static EFI_GUID FileInfoGUID = EFI_FILE_INFO_ID;; +static EFI_GUID SimpleFileSystemProtocolGUID = SIMPLE_FILE_SYSTEM_PROTOCOL; +static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; + +static int efifs_open(const char *path, struct open_file *f); +static int efifs_write(struct open_file *f, void *buf, size_t size, size_t *resid); +static int efifs_close(struct open_file *f); +static int efifs_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t efifs_seek(struct open_file *f, off_t offset, int where); +static int efifs_stat(struct open_file *f, struct stat *sb); +static int efifs_readdir(struct open_file *f, struct dirent *d); + +static int efifs_dev_init(void); +static int efifs_dev_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int efifs_dev_open(struct open_file *, ...); +static int efifs_dev_close(struct open_file *); +static int efifs_dev_print(int); + +struct devsw efifs_dev = { + .dv_name = "EFI", + .dv_type = DEVT_EFI, + .dv_init = efifs_dev_init, + .dv_strategy = efifs_dev_strategy, + .dv_open = efifs_dev_open, + .dv_close = efifs_dev_close, + .dv_ioctl = noioctl, + .dv_print = efifs_dev_print, + .dv_cleanup = NULL +}; + +struct fs_ops efifs_fsops = { + "EFI", + efifs_open, + efifs_close, + efifs_read, + efifs_write, + efifs_seek, + efifs_stat, + efifs_readdir +}; + +static int +efifs_dev_init(void) +{ + EFI_HANDLE *hin, *handles; + EFI_STATUS status; + UINTN sz; + u_int n, nin, unit; + int err; + + sz = 0; + hin = NULL; + status = BS->LocateHandle(ByProtocol, + &SimpleFileSystemProtocolGUID, 0, &sz, 0); + if (status == EFI_BUFFER_TOO_SMALL) { + hin = (EFI_HANDLE *)malloc(sz); + handles = (EFI_HANDLE *)malloc(sz); + status = BS->LocateHandle(ByProtocol, + &SimpleFileSystemProtocolGUID, 0, &sz, hin); + if (EFI_ERROR(status)) + free(hin); + } + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + nin = sz / sizeof(EFI_HANDLE); + unit = 0; + + for (n = 0; n < nin; n++) { + status = BS->OpenProtocol(hin[n], &SimpleFileSystemProtocolGUID, + NULL, IH, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (EFI_ERROR(status)) + continue; + + handles[unit++] = hin[n]; + } + + efi_register_handles(&efifs_dev, handles, NULL, unit); + + free(handles); + free(hin); + + return (err); +} + + +static int +efifs_dev_print(int verbose) +{ + char line[80]; + CHAR16 *name16; + EFI_DEVICE_PATH *devpath; + EFI_HANDLE h; + EFI_STATUS status; + u_int unit; + + pager_output("efifs devices:"); + + for (unit = 0, h = efi_find_handle(&efifs_dev, 0); + h != NULL; h = efi_find_handle(&efifs_dev, ++unit)) { + sprintf(line, " %s%d:", efifs_dev.dv_name, unit); + pager_output(line); + pager_output(" EFI_SIMPLE_FILE_SYSTEM"); + + status = BS->HandleProtocol(h, &DevicePathGUID, + (void **)&devpath); + if (!EFI_ERROR(status)) { + name16 = efi_devpath_name(devpath); + char buf[wcslen(name16) + 1]; + cpy16to8(name16, buf, wcslen(name16)); + + /* Print out the device path if we have one */ + pager_output(" on "); + pager_output(buf); + } + pager_output("\n"); + } + return (0); +} + +static int +efifs_dev_open(struct open_file *f, ...) +{ + va_list args; + struct devdesc *dev; + EFI_FILE_IO_INTERFACE *fsiface; + EFI_HANDLE h; + EFI_STATUS status; + + va_start(args, f); + dev = va_arg(args, struct devdesc*); + va_end(args); + + h = efi_find_handle(&efifs_dev, dev->d_unit); + + if (h == NULL) { + return (EINVAL); + } + + status = BS->OpenProtocol(h, &SimpleFileSystemProtocolGUID, + (void**)&fsiface, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR(status)) { + return (efi_status_to_errno(status)); + } + + dev->d_opendata = fsiface; + + return (0); +} + +static int +efifs_dev_close(struct open_file *f) +{ + struct devdesc *dev; + EFI_HANDLE h; + EFI_STATUS status; + + dev = (struct devdesc *)(f->f_devdata); + h = efi_find_handle(&efifs_dev, dev->d_unit); + + if (h == NULL) + return (EINVAL); + + if (dev->d_opendata == NULL) + return (EINVAL); + + status = BS->CloseProtocol(h, &SimpleFileSystemProtocolGUID, IH, NULL); + + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + dev->d_opendata = NULL; + return (0); +} + + +/* Raw I/O isn't supported on EFI FS devices, as they talk through + * SIMPLE_FILE_SYSTEM_INTERFACE. + */ +static int +efifs_dev_strategy(void *devdata __unused, int rw __unused, daddr_t blk __unused, + size_t size __unused, char *buf __unused, + size_t *rsize __unused) +{ + return ENOTSUP; +} + +/* + * Open a file. + */ +static int +efifs_open(const char *upath, struct open_file *f) +{ + struct devdesc *dev; + EFI_FILE_IO_INTERFACE *fsiface; + EFI_FILE_HANDLE root; + EFI_STATUS status; + CHAR16 path[strlen(upath) + 1]; + + if (f->f_dev != &efifs_dev) { + return (EINVAL); + } + + dev = (struct devdesc *)(f->f_devdata); + fsiface = dev->d_opendata; + + if (!strcmp(upath, "") || !strcmp(upath, "/")) { + return (fsiface->OpenVolume(fsiface, + (EFI_FILE_HANDLE*)&(f->f_fsdata))); + } else { + if (upath[0] == '/') { + upath++; + } + + status = fsiface->OpenVolume(fsiface, &root); + + if (EFI_ERROR(status)) { + return (efi_status_to_errno(status)); + } + + cpy8to16(upath, path, strlen(upath)); + + for(int i = 0; path[i] != 0; i++) { + if (path[i] == '/') { + path[i] = '\\'; + } + } + + status = root->Open(root, (EFI_FILE_HANDLE*)&(f->f_fsdata), + path, EFI_FILE_MODE_READ, 0); + root->Close(root); + + if (EFI_ERROR(status)) { + return (efi_status_to_errno(status)); + } + + return 0; + } +} + +static int +efifs_close(struct open_file *f) +{ + EFI_FILE_HANDLE file = (EFI_FILE_HANDLE)f->f_fsdata; + EFI_STATUS status; + + status = file->Close(file); + + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + return (0); +} + +static int +efifs_read(struct open_file *f, void *start, size_t size, size_t *resid /* out */) +{ + EFI_FILE_HANDLE file = (EFI_FILE_HANDLE)f->f_fsdata; + UINTN readsize = size; + EFI_STATUS status; + + status = file->Read(file, &readsize, start); + + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + if (resid) + *resid = size - readsize; + + return (0); +} + +static int +efifs_write(struct open_file *f, void *start, size_t size, + size_t *resid /* out */) +{ + EFI_FILE_HANDLE file = (EFI_FILE_HANDLE)f->f_fsdata; + UINTN writesize = size; + EFI_STATUS status; + + status = file->Write(file, &writesize, start); + + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + if (resid) + *resid = size - writesize; + + return (0); +} + +static off_t +efifs_seek(struct open_file *f, off_t offset, int where) +{ + EFI_FILE_HANDLE file = (EFI_FILE_HANDLE)f->f_fsdata; + UINT64 pos; + EFI_STATUS status; + + switch (where) { + case SEEK_SET: + status = file->SetPosition(file, offset); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + break; + case SEEK_CUR: + status = file->GetPosition(file, &pos); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + status = file->SetPosition(file, pos + offset); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + break; + case SEEK_END: + status = file->SetPosition(file, 0xffffffffffffffff); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + default: + errno = EINVAL; + return (-1); + } + + status = file->GetPosition(file, &pos); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + return (pos); +} + +/* SIMPLE_FILE_SYSTEM_PROTOCOL is geared towards FAT, so we can't + * reproduce stat with absolute fidelity. + */ +static int +efifs_stat(struct open_file *f, struct stat *sb) +{ + EFI_FILE_HANDLE file; + UINTN size = 0; + EFI_FILE_INFO *finfo; + EFI_STATUS status; + + file = (EFI_FILE_HANDLE)f->f_fsdata; + status = file->GetInfo(file, &FileInfoGUID, &size, NULL); + + if (status != EFI_BUFFER_TOO_SMALL) { + errno = (efi_status_to_errno(status)); + return -1; + } + + finfo = malloc(size); + status = file->GetInfo(file, &FileInfoGUID, &size, finfo); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + /* We can't properly fill these in... */ + sb->st_ino = 0; + sb->st_nlink = 0; + sb->st_uid = 0; + sb->st_gid = 0; + sb->st_blksize = 512; + /* Build the mode field */ + if (finfo->Attribute & EFI_FILE_DIRECTORY) { + sb->st_mode = S_IFDIR; + } else { + sb->st_mode = S_IFREG; + } + + if (finfo->Attribute & EFI_FILE_MODE_READ) { + sb->st_mode = S_IRUSR | S_IXUSR | S_IRGRP | + S_IXGRP | S_IROTH | S_IXOTH; + } + + if (finfo->Attribute & EFI_FILE_MODE_READ) { + sb->st_mode = S_IWUSR | S_IWGRP | S_IWOTH; + } + /* This may or may not be supported, depending on the FS driver */ + sb->st_blocks = finfo->PhysicalSize / 512; + /* These fields we can get right */ + sb->st_size = finfo->FileSize; + sb->st_atime = from_efi_time(&(finfo->LastAccessTime)); + sb->st_mtime = from_efi_time(&(finfo->ModificationTime)); + sb->st_ctime = from_efi_time(&(finfo->CreateTime)); + + free(finfo); + + return (0); +} + +static int +efifs_readdir(struct open_file *f, struct dirent *d) +{ + EFI_FILE_HANDLE dir; + EFI_FILE_HANDLE entry; + UINTN size = 0; + EFI_FILE_INFO *finfo; + EFI_STATUS status; + + dir = (EFI_FILE_HANDLE)f->f_fsdata; + status = dir->Read(dir, &size, NULL); + + if (status != EFI_BUFFER_TOO_SMALL) { + errno = (efi_status_to_errno(status)); + return -1; + } + + if (size == 0) { + return (ENOENT); + } + + finfo = malloc(size); + status = dir->Read(dir, &size, finfo); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + cpy16to8(finfo->FileName, d->d_name, MAXNAMLEN); + d->d_namlen = strlen(d->d_name); + d->d_reclen = sizeof(struct dirent); + /* We can't faithfully reproduce this due to the limitations + * of the SIMPLE_FILE_SYSTEM interface */ + d->d_fileno = 0; + + /* The FAT-style interface here forces us to open the file to + * get its attributes. + */ + status = dir->Open(dir, &entry, finfo->FileName, + EFI_FILE_MODE_READ, 0); + free(finfo); + + if (EFI_ERROR(status)) { + errno = (efi_status_to_errno(status)); + return -1; + } + + size = 0; + status = entry->GetInfo(entry, &FileInfoGUID, &size, NULL); + + if (status != EFI_BUFFER_TOO_SMALL) { + errno = (efi_status_to_errno(status)); + return -1; + } + + finfo = malloc(size); + status = entry->GetInfo(entry, &FileInfoGUID, &size, finfo); + + if (status != EFI_SUCCESS) { + free(finfo); + errno = (efi_status_to_errno(status)); + return -1; + } + + /* There is some information loss here due to the FAT-based + * EFI_SIMPLE_FILE_SYSTEM interface + */ + if (finfo->Attribute & EFI_FILE_DIRECTORY) { + d->d_type = DT_DIR; + } else { + d->d_type = DT_REG; + } + + free(finfo); + entry->Close(entry); + + return (0); +} + +int +efifs_parsedev(struct devdesc *dev, const char *devspec, const char **path) +{ + int unit; + const char *np; + char *cp; + + np = devspec; + unit = -1; + if (*np != '\0' && *np != ':') { + unit = strtol(np, &cp, 10); + + if (cp == np) + return (EUNIT); + } else + return (EINVAL); + + if (*cp != '\0' && *cp != ':') + return (EINVAL); + + dev->d_unit = unit; + + if (path != NULL) + *path = (*cp == '\0') ? cp: cp + 1; + + return (0); +} Index: sys/boot/efi/libefi/errno.c =================================================================== --- sys/boot/efi/libefi/errno.c +++ sys/boot/efi/libefi/errno.c @@ -30,6 +30,69 @@ #include #include +EFI_STATUS +errno_to_efi_status(int errno) +{ + EFI_STATUS status; + + switch (errno) { + case EPERM: + status = EFI_ACCESS_DENIED; + break; + + case EOVERFLOW: + status = EFI_BUFFER_TOO_SMALL; + break; + + case EIO: + status = EFI_DEVICE_ERROR; + break; + + case EINVAL: + status = EFI_INVALID_PARAMETER; + break; + + case ESTALE: + status = EFI_MEDIA_CHANGED; + break; + + case ENXIO: + status = EFI_NO_MEDIA; + break; + + case ENOENT: + status = EFI_NOT_FOUND; + break; + + case ENOMEM: + status = EFI_OUT_OF_RESOURCES; + break; + + case ENOTSUP: + case ENODEV: + status = EFI_UNSUPPORTED; + break; + + case ENOSPC: + status = EFI_VOLUME_FULL; + break; + + case EACCES: + status = EFI_WRITE_PROTECTED; + break; + + case 0: + status = EFI_SUCCESS; + break; + + default: + status = EFI_DEVICE_ERROR; + break; + } + + return (status); +} + int efi_status_to_errno(EFI_STATUS status) { Index: sys/boot/efi/libefi/time.c =================================================================== --- sys/boot/efi/libefi/time.c +++ sys/boot/efi/libefi/time.c @@ -58,6 +58,41 @@ #define SECSPERHOUR ( 60*60 ) #define SECSPERDAY (24 * SECSPERHOUR) +/* +// These arrays give the cumulative number of days up to the first of the +// month number used as the index (1 -> 12) for regular and leap years. +// The value at index 13 is for the whole year. +*/ +static const time_t CumulativeDays[2][14] = { + {0, + 0, + 31, + 31 + 28, + 31 + 28 + 31, + 31 + 28 + 31 + 30, + 31 + 28 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }, + {0, + 0, + 31, + 31 + 29, + 31 + 29 + 31, + 31 + 29 + 31 + 30, + 31 + 29 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }}; + void efi_time_init(void) { @@ -68,45 +103,46 @@ { } -static time_t -efi_time(EFI_TIME *ETime) +void +to_efi_time(EFI_TIME *efi_time, time_t time) { - /* - // These arrays give the cumulative number of days up to the first of the - // month number used as the index (1 -> 12) for regular and leap years. - // The value at index 13 is for the whole year. - */ - static time_t CumulativeDays[2][14] = { - {0, - 0, - 31, - 31 + 28, - 31 + 28 + 31, - 31 + 28 + 31 + 30, - 31 + 28 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }, - {0, - 0, - 31, - 31 + 29, - 31 + 29 + 31, - 31 + 29 + 31 + 30, - 31 + 29 + 31 + 30 + 31, - 31 + 29 + 31 + 30 + 31 + 30, - 31 + 29 + 31 + 30 + 31 + 30 + 31, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }}; - - time_t UTime; + if (time >= 0) { + for (efi_time->Year = 1970; + time > CumulativeDays[isleap(efi_time->Year)][13] * SECSPERDAY; + time -= CumulativeDays[isleap(efi_time->Year)][13] * SECSPERDAY, + efi_time->Year++); + + for (efi_time->Month = 0; + time > CumulativeDays[isleap(efi_time->Year)][efi_time->Month] * + SECSPERDAY; + efi_time->Month++); + + time -= CumulativeDays[isleap(efi_time->Year)][efi_time->Month - 1] * + SECSPERDAY; + + for (efi_time->Day = 0; time > SECSPERDAY; + time -= SECSPERDAY, efi_time->Day++); + + for (efi_time->Hour = 0; time > SECSPERHOUR; + time -= SECSPERHOUR, efi_time->Hour++); + + for (efi_time->Minute = 0; time > 60; + time -= 60, efi_time->Minute++); + + efi_time->Second = time; + efi_time->Nanosecond = 0; + efi_time->TimeZone = 0; + efi_time->Daylight = 0; + } else { + memset(efi_time, 0, sizeof(EFI_TIME)); + } +} + +time_t +from_efi_time(EFI_TIME *ETime) +{ + + time_t UTime; int Year; /* @@ -196,7 +232,7 @@ // Convert to UNIX time (ie seconds since the epoch */ - tp->tv_sec = efi_time( &EfiTime ); + tp->tv_sec = from_efi_time( &EfiTime ); tp->tv_usec = 0; /* EfiTime.Nanosecond * 1000; */ /* Index: sys/boot/efi/libefi/wchar.c =================================================================== --- sys/boot/efi/libefi/wchar.c +++ sys/boot/efi/libefi/wchar.c @@ -36,7 +36,7 @@ */ int -wcscmp(CHAR16 *a, CHAR16 *b) +wcscmp(const CHAR16 *a, const CHAR16 *b) { while (*a && *b && *a == *b) { @@ -46,6 +46,16 @@ return *a - *b; } +size_t +wcslen(const CHAR16 *s) +{ + size_t len; + + for(len = 0; s[len] != '\0'; len++); + + return len; +} + /* * cpy8to16 copies a traditional C string into a CHAR16 string and * 0 terminates it. len is the size of *dst in bytes. Index: sys/boot/efi/loader/conf.c =================================================================== --- sys/boot/efi/loader/conf.c +++ sys/boot/efi/loader/conf.c @@ -36,6 +36,7 @@ #endif struct devsw *devsw[] = { + &efifs_dev, &efipart_fddev, &efipart_cddev, &efipart_hddev, @@ -47,10 +48,10 @@ }; struct fs_ops *file_system[] = { + &efifs_fsops, #ifdef EFI_ZFS_BOOT &zfs_fsops, #endif - &dosfs_fsops, &ufs_fsops, &cd9660_fsops, &tftp_fsops, Index: sys/boot/efi/loader/devicename.c =================================================================== --- sys/boot/efi/loader/devicename.c +++ sys/boot/efi/loader/devicename.c @@ -138,6 +138,18 @@ } break; #endif + case DEVT_EFI: + idev = malloc(sizeof(struct devdesc)); + if (idev == NULL) + return (ENOMEM); + + err = efifs_parsedev((struct devdesc*)idev, np, path); + if (err != 0) { + free(idev); + return (err); + } + break; + default: idev = malloc(sizeof(struct devdesc)); if (idev == NULL) Index: sys/boot/efi/loader/main.c =================================================================== --- sys/boot/efi/loader/main.c +++ sys/boot/efi/loader/main.c @@ -82,7 +82,7 @@ EFI_HANDLE *hin, *hin_end, *walker; UINTN sz; int retval = 0; - + /* * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and * do the typical dance to get the right sized buffer. @@ -139,7 +139,7 @@ } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH && DevicePathSubType(path) == MSG_USB_CLASS_DP) { USB_CLASS_DEVICE_PATH *usb; - + usb = (USB_CLASS_DEVICE_PATH *)(void *)path; if (usb->DeviceClass == 3 && /* HID */ usb->DeviceSubClass == 1 && /* Boot devices */ Index: sys/boot/zfs/zfs.c =================================================================== --- sys/boot/zfs/zfs.c +++ sys/boot/zfs/zfs.c @@ -863,7 +863,7 @@ ctr++; continue; } - + snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); snprintf(envval, sizeof(envval), "%s", zfs_be->name); rv = setenv(envname, envval, 1); @@ -896,7 +896,7 @@ } } - + for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) { snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); (void)unsetenv(envname);