Download raw body.
port booting kernels from efi system partitions to amd64
i originally wrote this for arm64, but i used it to test out openbsd
on an amd64 box recently and thought it could be useful for other
people too.
this lets you put and a kernel (eg, bsd.rd) on the efi system
partition and boot it. it can be handy to bootstrap the installer
on an existing system.
ok?
Index: conf.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/efiboot/conf.c,v
diff -u -p -r1.44 conf.c
--- conf.c 4 Jun 2024 21:48:20 -0000 1.44
+++ conf.c 30 Apr 2025 02:12:07 -0000
@@ -40,7 +40,7 @@
#include "efidev.h"
#include "efipxe.h"
-const char version[] = "3.67";
+const char version[] = "3.68";
#ifdef EFI_DEBUG
int debug = 0;
@@ -72,6 +72,8 @@ struct fs_ops file_system[] = {
ufs2_stat, ufs2_readdir, ufs2_fchmod },
{ cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek,
cd9660_stat, cd9660_readdir },
+ { esp_open, esp_close, esp_read, esp_write, esp_seek,
+ esp_stat, esp_readdir, }
#ifdef notdef
{ fat_open, fat_close, fat_read, fat_write, fat_seek,
fat_stat, fat_readdir },
@@ -82,6 +84,7 @@ struct fs_ops file_system[] = {
int nfsys = nitems(file_system);
struct devsw devsw[] = {
+ { "ESP", espstrategy, espopen, espclose, espioctl },
{ "TFTP", tftpstrategy, tftpopen, tftpclose, tftpioctl },
{ "EFI", efistrategy, efiopen, eficlose, efiioctl },
};
Index: efidev.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/efiboot/efidev.c,v
diff -u -p -r1.42 efidev.c
--- efidev.c 26 Oct 2023 14:08:48 -0000 1.42
+++ efidev.c 30 Apr 2025 02:12:07 -0000
@@ -765,3 +765,209 @@ efi_dump_diskinfo(void)
(ed->blkio->Media->RemovableMedia)? "Removable" : "");
}
}
+
+/*
+ * 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: efidev.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/efiboot/efidev.h,v
diff -u -p -r1.4 efidev.h
--- efidev.h 9 Dec 2020 18:10:18 -0000 1.4
+++ efidev.h 30 Apr 2025 02:12:07 -0000
@@ -36,3 +36,16 @@ int efistrategy(void *, int, daddr_t,
int eficlose(struct open_file *);
int efiioctl(struct open_file *, u_long, void *);
void efi_dump_diskinfo(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 *);
port booting kernels from efi system partitions to amd64