diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2023-04-18 23:11:57 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2023-04-18 23:11:57 +0000 |
commit | dd8aca2a546a0934d912d756a90f241b28cbcb4b (patch) | |
tree | 314303f0fd6baf2873f43c1867116e5b1da70791 /sys | |
parent | 99fe31a58cf3896de37e0a5da3ac0a24fc587909 (diff) |
add support for loading files from the EFI System Partition.
this means you can put a bsd.rd next to BOOTAA64.EFI and go "boot
esp0a:bsd.rd" (assuming bsd.rd is in the root of the boot partition).
cool! krw@
ok kettenis@ patrick@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/arm64/stand/efiboot/conf.c | 7 | ||||
-rw-r--r-- | sys/arch/arm64/stand/efiboot/efidev.c | 212 | ||||
-rw-r--r-- | sys/arch/arm64/stand/efiboot/efidev.h | 15 |
3 files changed, 230 insertions, 4 deletions
diff --git a/sys/arch/arm64/stand/efiboot/conf.c b/sys/arch/arm64/stand/efiboot/conf.c index 6677db033c6..3e489c817a8 100644 --- a/sys/arch/arm64/stand/efiboot/conf.c +++ b/sys/arch/arm64/stand/efiboot/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.44 2023/02/15 14:13:38 kettenis Exp $ */ +/* $OpenBSD: conf.c,v 1.45 2023/04/18 23:11:56 dlg Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -46,7 +46,7 @@ #include "efipxe.h" #include "softraid_arm64.h" -const char version[] = "1.16"; +const char version[] = "1.17"; int debug = 0; struct fs_ops file_system[] = { @@ -58,10 +58,13 @@ struct fs_ops file_system[] = { ufs_stat, ufs_readdir, ufs_fchmod }, { ufs2_open, ufs2_close, ufs2_read, ufs2_write, ufs2_seek, ufs2_stat, ufs2_readdir, ufs2_fchmod }, + { esp_open, esp_close, esp_read, esp_write, esp_seek, + esp_stat, esp_readdir, } }; int nfsys = nitems(file_system); struct devsw devsw[] = { + { "esp", espstrategy, espopen, espclose, espioctl }, { "tftp", tftpstrategy, tftpopen, tftpclose, tftpioctl }, { "sd", efistrategy, efiopen, eficlose, efiioctl }, { "sr", srstrategy, sropen, srclose, srioctl }, diff --git a/sys/arch/arm64/stand/efiboot/efidev.c b/sys/arch/arm64/stand/efiboot/efidev.c index 0b92bef1ee2..cb2ada5c907 100644 --- a/sys/arch/arm64/stand/efiboot/efidev.c +++ b/sys/arch/arm64/stand/efiboot/efidev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: efidev.c,v 1.11 2022/09/01 13:45:26 krw Exp $ */ +/* $OpenBSD: efidev.c,v 1.12 2023/04/18 23:11:56 dlg Exp $ */ /* * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> @@ -565,3 +565,213 @@ efiioctl(struct open_file *f, u_long cmd, void *data) { return 0; } + +/* + * load a file from the EFI System Partition + */ + +static EFI_GUID lip_guid = LOADED_IMAGE_PROTOCOL; +static EFI_GUID sfsp_guid = SIMPLE_FILE_SYSTEM_PROTOCOL; +static EFI_GUID fi_guid = EFI_FILE_INFO_ID; + +int +esp_open(char *path, struct open_file *f) +{ + extern EFI_HANDLE IH; + extern EFI_BOOT_SERVICES *BS; + + EFI_LOADED_IMAGE *li = NULL; + EFI_FILE_IO_INTERFACE *ESPVolume; + CHAR16 *fname; + EFI_FILE_HANDLE VH, FH; + UINTN pathlen, i; + EFI_STATUS status; + + if (strcmp("esp", f->f_dev->dv_name) != 0) + return ENXIO; + + if (IH == NULL) + return ENXIO; + + /* get the loaded image protocol interface */ + status = BS->HandleProtocol(IH, &lip_guid, (void **)&li); + if (status != EFI_SUCCESS) + return ENXIO; + + /* get a fs handle */ + status = BS->HandleProtocol(li->DeviceHandle, &sfsp_guid, + (void *)&ESPVolume); + if (status != EFI_SUCCESS) + return ENXIO; + + status = ESPVolume->OpenVolume(ESPVolume, &VH); + if (status != EFI_SUCCESS) + return ENOENT; + + pathlen = strlen(path) + 1; + fname = alloc(pathlen * sizeof(*fname)); + if (fname == NULL) + return ENOMEM; + + /* No AsciiStrToUnicodeStrS */ + for (i = 0; i < pathlen; i++) + fname[i] = path[i]; + + status = VH->Open(VH, &FH, fname, EFI_FILE_MODE_READ, + EFI_FILE_READ_ONLY /*| EFI_FILE_HIDDEN*/ | EFI_FILE_SYSTEM); + free(fname, pathlen * sizeof(*fname)); + if (status != EFI_SUCCESS) + return ENOENT; + + f->f_fsdata = FH; + return (0); +} + +int +esp_close(struct open_file *f) +{ + EFI_FILE_HANDLE FH = f->f_fsdata; + FH->Close(FH); + return 0; +} + +int +esp_read(struct open_file *f, void *addr, size_t size, size_t *resid) +{ + EFI_FILE_HANDLE FH = f->f_fsdata; + UINT64 readlen = size; + EFI_STATUS status; + + status = FH->Read(FH, &readlen, addr); + if (status != EFI_SUCCESS) + return (EIO); + + *resid = size - readlen; + return (0); +} + +int +esp_write(struct open_file *f, void *start, size_t size, size_t *resid) +{ + return (EROFS); +} + +off_t +esp_seek(struct open_file *f, off_t offset, int where) +{ + EFI_FILE_HANDLE FH = f->f_fsdata; + UINT64 position; + EFI_STATUS status; + + switch(where) { + case SEEK_CUR: + status = FH->GetPosition(FH, &position); + if (status != EFI_SUCCESS) { + errno = EIO; + return ((off_t)-1); + } + + position += offset; + break; + case SEEK_SET: + position = offset; + break; + case SEEK_END: + position = 0xFFFFFFFFFFFFFFFF; + break; + default: + errno = EINVAL; + return ((off_t)-1); + } + + status = FH->SetPosition(FH, position); + if (status != EFI_SUCCESS) { + errno = EIO; + return ((off_t)-1); + } + + return (0); +} + +int +esp_stat(struct open_file *f, struct stat *sb) +{ + + EFI_FILE_HANDLE FH = f->f_fsdata; + EFI_FILE_INFO fi; + EFI_FILE_INFO *fip = &fi; + UINTN filen = sizeof(fi); + EFI_STATUS status; + ssize_t rv = -1; + + sb->st_mode = 0444; + sb->st_nlink = 1; + sb->st_uid = 0; + sb->st_gid = 0; + + status = FH->GetInfo(FH, &fi_guid, &filen, fip); + switch (status) { + case EFI_SUCCESS: + sb->st_size = fip->FileSize; + return (0); + case EFI_BUFFER_TOO_SMALL: + break; + default: + return (EIO); + } + + fip = alloc(filen); + if (fip == NULL) + return (ENOMEM); + + status = FH->GetInfo(FH, &fi_guid, &filen, fip); + if (status != EFI_SUCCESS) + goto done; + + sb->st_size = fip->FileSize; + +done: + free(fip, filen); + return (rv); +} + +int +esp_readdir(struct open_file *f, char *name) +{ + return EOPNOTSUPP; +} + +int +espopen(struct open_file *f, ...) +{ + u_int unit; + va_list ap; + + va_start(ap, f); + unit = va_arg(ap, u_int); + va_end(ap); + + if (unit != 0) + return 1; + + return 0; +} + +int +espclose(struct open_file *f) +{ + return 0; +} + +int +espioctl(struct open_file *f, u_long cmd, void *data) +{ + return EOPNOTSUPP; +} + +int +espstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, + size_t *rsize) +{ + return EOPNOTSUPP; +} diff --git a/sys/arch/arm64/stand/efiboot/efidev.h b/sys/arch/arm64/stand/efiboot/efidev.h index 6f8ee047b90..c57b03369f7 100644 --- a/sys/arch/arm64/stand/efiboot/efidev.h +++ b/sys/arch/arm64/stand/efiboot/efidev.h @@ -1,4 +1,4 @@ -/* $OpenBSD: efidev.h,v 1.3 2020/12/09 18:10:18 krw Exp $ */ +/* $OpenBSD: efidev.h,v 1.4 2023/04/18 23:11:56 dlg Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -34,3 +34,16 @@ int efiopen(struct open_file *, ...); int efistrategy(void *, int, daddr_t, size_t, void *, size_t *); int eficlose(struct open_file *); int efiioctl(struct open_file *, u_long, void *); + +int esp_open(char *, struct open_file *); +int esp_close(struct open_file *); +int esp_read(struct open_file *, void *, size_t, size_t *); +int esp_write(struct open_file *, void *, size_t, size_t *); +off_t esp_seek(struct open_file *, off_t, int); +int esp_stat(struct open_file *, struct stat *); +int esp_readdir(struct open_file *, char *); + +int espopen(struct open_file *, ...); +int espclose(struct open_file *); +int espioctl(struct open_file *, u_long, void *); +int espstrategy(void *, int, daddr_t, size_t, void *, size_t *); |