Port-amd64 archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[PATCH] BIOS boot vs EFI system partition mountpoint



I'd like to have a standard mount point for the EFI system partition
on platforms with EFI boot.  On NetBSD/arm, this is /boot (which is
also shared with non-EFI boot on some Arm boards), and on NetBSD/riscv
it'll probably be the same eventually.

Currently on x86, BIOS boot requires a secondary bootloader at /boot
in the root file system.  EFI boot doesn't require any secondary
bootloader, so /boot could also be the ESP mountpoint in principle,
but it would pose a conflict for a hybrid image that boots with
_either_ BIOS or EFI and has the ESP mounted.

I propose to change NetBSD/x86 BIOS boot so it looks for the secondary
bootloader at /biosboot instead of /boot, but falls back to /boot.
That way, a hybrid image can have /biosboot as well as the ESP mounted
at /boot, and we can have /boot as the standard mount point for ESP on
platforms with EFI boot.

The attached patch changes bootxx_* -- except bootxx_fat12/fat16[*] --
to try /biosboot first and then fall back to /boot, and patches
sysinst to install the BIOS bootloader at /biosboot instead of /boot.
I've tested BIOS and EFI boot under qemu with the same image.

OK?


[*] I suspect tbootxx_fat12/fat16 have tighter space constraints.
    It's possible, even if there are space constraints, that we could
    fit logic to try /biosboot first and then /boot.  But they are
    also hand-written assembly, I don't know how to test them, and I
    doubt they're relevant on any hybrid images anyway, so I didn't
    change them.
From 693c3b6ff4b505958b73d73600b9002a830b71af Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 18 Aug 2022 13:53:53 +0000
Subject: [PATCH] x86: Move the secondary BIOS bootloader from /boot to
 /biosboot.

This way /boot can be freed up as a standard mount point for the EFI
system partition, like evbarm uses.

The bootxx_* primary BIOS bootloaders will try /biosboot first to
find the secondary bootloader, and fall back to /boot if it does not
exist, so that existing file systems will continue to function.

Exception: bootxx_fat12/fat16 currently don't try /biosboot, but I
don't think they are relevant on any hybrid images for systems that
might use BIOS or UEFI boot, and I suspect they may be size-
constrained.
---
 share/man/man8/man8.x86/boot.8     | 54 ++++++++++++++++++++++++++----
 sys/arch/i386/stand/bootxx/boot1.c | 38 +++++++++++++++------
 usr.sbin/sysinst/arch/i386/md.c    |  4 +--
 3 files changed, 76 insertions(+), 20 deletions(-)

diff --git a/share/man/man8/man8.x86/boot.8 b/share/man/man8/man8.x86/boot.8
index b2b9029153fc..b48eec53b296 100644
--- a/share/man/man8/man8.x86/boot.8
+++ b/share/man/man8/man8.x86/boot.8
@@ -51,7 +51,7 @@ can use any of the following boot procedures, depending on what the hardware and
 .Tn BIOS
 support:
 .Bl -tag -width "x86/pxeboot(8)"
-.It boot
+.It biosboot
 bootstrap
 .Nx
 from the system
@@ -82,7 +82,27 @@ and
 Normally, the system will reboot itself at power-up or after crashes.
 An automatic consistency check of the file systems will be performed,
 and unless this fails, the system will resume multi-user operations.
-.Ss Cold starts
+.Ss UEFI boot
+Modern x86 systems use the Unified Extensible Firmware Interface to
+boot
+.Pq Sq efiboot .
+The machine's firmware will open the EFI system partition in a GPT
+.Pq Xr gpt 8
+and execute
+.Nx Ns 's
+boot loader at
+.Pa EFI/boot/bootia32.efi
+.Pq i386
+or
+.Pa EFI/boot/bootx64.efi
+.Pq amd64 .
+With UEFI boot there is no MBR boot block and no separate primary and
+secondary boot loader;
+.Pa bootia32.efi
+or
+.Pa bootx64.efi
+will load and execute the kernel directly.
+.Ss Cold starts with legacy BIOS boot
 The 386
 .Tn "PC AT"
 clones attempt to boot the floppy disk drive A (otherwise known as drive
@@ -778,8 +798,13 @@ So you can only boot from unit 0.
 .El
 .Sh FILES
 .Bl -tag -width /usr/mdec/bootxx_fstype -compact
+.It Pa /biosboot
+secondary boot program code loaded by the primary bootstrap for BIOS
+boot
+(not needed for EFI boot)
 .It Pa /boot
-boot program code loaded by the primary bootstrap
+EFI system partition mount point, or legacy location of secondary boot
+program for BIOS boot
 .It Pa /boot.cfg
 optional configuration file
 .It Pa /netbsd
@@ -787,7 +812,10 @@ system code
 .It Pa /netbsd.gz
 gzip-compressed system code
 .It Pa /usr/mdec/boot
-master copy of the boot program (copy to /boot)
+.\" XXX should rename to /usr/mdec/biosboot
+master copy of the secondary boot program for BIOS boot \(em copy to
+.Pa /biosboot
+to use
 .It Pa /usr/mdec/bootxx_fstype
 primary bootstrap for file system type fstype, copied to the start of
 the
@@ -802,7 +830,7 @@ bootstraps for
 and
 .Nx Ns /amd64 ,
 which should be copied to the
-.Pa /EFI/boot
+.Pa EFI/boot
 directory in a
 .Tn FAT
 formatted partition of type
@@ -817,10 +845,15 @@ section).
 .Nx
 .Tn UEFI
 bootstrap reads its configuration from the
-.Pa /EFI/NetBSD/boot.cfg
+.Pa EFI/NetBSD/boot.cfg
 file in the
 .Tn EFI
-partition.
+partition;
+if that file does not exist, it reads
+.Pa /boot.cfg
+in the
+.Nx
+file system instead.
 .El
 .Sh SEE ALSO
 .Xr ddb 4 ,
@@ -839,6 +872,13 @@ partition.
 .Xr x86/multiboot 8 ,
 .Xr x86/pxeboot 8 ,
 .Xr boothowto 9
+.Rs
+.%Q UEFI Forum, Inc.
+.%T Unified Extensible Firmware Interface (UEFI) Specification
+.%N Version 2.9
+.%D March 2021
+.%U https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf
+.Re
 .Sh BUGS
 The kernel file name must be specified before, not after, the boot options.
 Any
diff --git a/sys/arch/i386/stand/bootxx/boot1.c b/sys/arch/i386/stand/bootxx/boot1.c
index f563eb46aa18..91f456af4a32 100644
--- a/sys/arch/i386/stand/bootxx/boot1.c
+++ b/sys/arch/i386/stand/bootxx/boot1.c
@@ -54,9 +54,25 @@ extern void putstr(const char *);
 extern struct disklabel ptn_disklabel;
 
 static int
-ob(void)
+ob1(const char *p, struct stat *st)
 {
-	return open("boot", 0);
+	int fd;
+
+	if ((fd = open(p, 0)) == -1)
+		return -1;
+	if (fstat(fd, st) == -1)
+		return -1;
+	return fd;
+}
+
+static int
+ob(struct stat *st)
+{
+	int fd;
+
+	if ((fd = ob1("biosboot", st)) != -1)
+		return fd;
+	return ob1("boot", st);
 }
 
 const char *
@@ -77,7 +93,7 @@ boot1(uint32_t biosdev, uint64_t *sector)
 	 * We default to the filesystem at the start of the
 	 * MBR partition
 	 */
-	fd = ob();
+	fd = ob(&sb);
 	if (fd != -1)
 		goto done;
 	/*
@@ -87,7 +103,7 @@ boot1(uint32_t biosdev, uint64_t *sector)
 	 * magic number is absent.)
 	 */
 	bios_sector += RF_PROTECTED_SECTORS;
-	fd = ob();
+	fd = ob(&sb);
 	if (fd != -1)
 		goto done;
 	/*
@@ -103,23 +119,23 @@ boot1(uint32_t biosdev, uint64_t *sector)
 	if (ptn_disklabel.d_partitions[0].p_fstype == FS_RAID)
 		bios_sector += RF_PROTECTED_SECTORS;
 
-	fd = ob();
-
+	fd = ob(&sb);
 done:
-	if (fd == -1 || fstat(fd, &sb) == -1)
-		return "Can't open /boot\r\n";
+	if (fd == -1)
+		return "Can't open biosboot\r\n";
+	/* XXX if (!S_ISREG(sb.st_mode)) ... */
 
 	biosdev = (uint32_t)sb.st_size;
 #if 0
 	if (biosdev > SECONDARY_MAX_LOAD)
-		return "/boot too large\r\n";
+		return "biosboot too large\r\n";
 #endif
 
 	if (read(fd, (void *)SECONDARY_LOAD_ADDRESS, biosdev) != biosdev)
-		return "/boot load failed\r\n";
+		return "biosboot load failed\r\n";
 
 	if (*(uint32_t *)(SECONDARY_LOAD_ADDRESS + 4) != X86_BOOT_MAGIC_2)
-		return "Invalid /boot file format\r\n";
+		return "Invalid biosboot file format\r\n";
 
 	/* We need to jump to the secondary bootstrap in realmode */
 	return 0;
diff --git a/usr.sbin/sysinst/arch/i386/md.c b/usr.sbin/sysinst/arch/i386/md.c
index 1078e76edaca..f04347e6aa46 100644
--- a/usr.sbin/sysinst/arch/i386/md.c
+++ b/usr.sbin/sysinst/arch/i386/md.c
@@ -283,9 +283,9 @@ update_bios_boot(struct install_partition_desc *install, bool use_target_files)
 	}
 
 	if (use_target_files)
-		ret = cp_within_target("/usr/mdec/boot", "/", 0);
+		ret = cp_within_target("/usr/mdec/boot", "/biosboot", 0);
 	else
-		ret = cp_to_target("/usr/mdec/boot", "/");
+		ret = cp_to_target("/usr/mdec/boot", "/biosboot");
 	if (ret)
 		return ret;
 	if (pm && pm->no_part)


Home | Main Index | Thread Index | Old Index