summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2023-04-18 23:11:57 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2023-04-18 23:11:57 +0000
commitdd8aca2a546a0934d912d756a90f241b28cbcb4b (patch)
tree314303f0fd6baf2873f43c1867116e5b1da70791 /sys
parent99fe31a58cf3896de37e0a5da3ac0a24fc587909 (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.c7
-rw-r--r--sys/arch/arm64/stand/efiboot/efidev.c212
-rw-r--r--sys/arch/arm64/stand/efiboot/efidev.h15
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 *);