add support for loading files from the EFI System Partition.
authordlg <dlg@openbsd.org>
Tue, 18 Apr 2023 23:11:56 +0000 (23:11 +0000)
committerdlg <dlg@openbsd.org>
Tue, 18 Apr 2023 23:11:56 +0000 (23:11 +0000)
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@

sys/arch/arm64/stand/efiboot/conf.c
sys/arch/arm64/stand/efiboot/efidev.c
sys/arch/arm64/stand/efiboot/efidev.h

index 6677db0..3e489c8 100644 (file)
@@ -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 },
index 0b92bef..cb2ada5 100644 (file)
@@ -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;
+}
index 6f8ee04..c57b033 100644 (file)
@@ -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 *);