Index | Thread | Search

From:
David Gwynne <david@gwynne.id.au>
Subject:
port booting kernels from efi system partitions to amd64
To:
tech@openbsd.org
Date:
Wed, 30 Apr 2025 12:16:15 +1000

Download raw body.

Thread
  • David Gwynne:

    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 *);