From 7c8e0a7886348edfb1c5a23bfe3b7e57dd8aa62c Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Mon, 27 Nov 2023 23:12:52 +0000 Subject: [PATCH] Support booting with EFI. --- build-aux/iso-grub-cfg.sh | 2 +- build-aux/ports.conf | 4 +- ports/grub-i386-efi/grub-i386-efi.port | 7 ++ ports/grub-i386-pc/grub-i386-pc.port | 8 ++ ports/grub-x86_64-efi/grub-x86_64-efi.port | 8 ++ ports/grub/grub.patch | 137 ++++++++++++++++++++- ports/grub/grub.port | 6 +- ports/grub/grub.post-install | 3 + sysinstall/sysinstall.c | 63 ++++++++-- 9 files changed, 222 insertions(+), 16 deletions(-) create mode 100644 ports/grub-i386-efi/grub-i386-efi.port create mode 100644 ports/grub-i386-pc/grub-i386-pc.port create mode 100644 ports/grub-x86_64-efi/grub-x86_64-efi.port diff --git a/build-aux/iso-grub-cfg.sh b/build-aux/iso-grub-cfg.sh index 6f526761..49d24153 100755 --- a/build-aux/iso-grub-cfg.sh +++ b/build-aux/iso-grub-cfg.sh @@ -325,7 +325,7 @@ esac cat << EOF hook_kernel_pre echo -n "Loading /$kernel ($(human_size $kernel)) ... " - multiboot /$kernel \$no_random_seed \$enable_network_drivers \$chain "\$@" + multiboot /$kernel --firmware=\$grub_platform \$no_random_seed \$enable_network_drivers \$chain "\$@" echo done hook_kernel_post # TODO: Injecting configuration doesn't work for mounted cdroms. diff --git a/build-aux/ports.conf b/build-aux/ports.conf index d27b3a99..7fdf6e6d 100644 --- a/build-aux/ports.conf +++ b/build-aux/ports.conf @@ -1,3 +1,3 @@ -set_minimal="cut dash e2fsprogs grep grub libssl mdocml sed signify tar wget xargs xz" -set_basic="$set_minimal binutils bison bzip2 diffutils ed flex gawk gcc git gzip irssi libcurl libcurses libstdc++ m4 make nano ntpd patch perl pkg-config python ssh texinfo vim xorriso" +set_minimal="cut dash dosfstools e2fsprogs grep grub grub-i386-pc grub-i386-efi grub-x86_64-efi libssl mdocml sed signify tar wget xargs xz" +set_basic="$set_minimal binutils bison bzip2 diffutils ed flex gawk gcc git gzip irssi libcurl libcurses libstdc++ m4 make mtools nano ntpd patch perl pkg-config python ssh texinfo vim xorriso" sets="basic minimal" diff --git a/ports/grub-i386-efi/grub-i386-efi.port b/ports/grub-i386-efi/grub-i386-efi.port new file mode 100644 index 00000000..ab7d0a71 --- /dev/null +++ b/ports/grub-i386-efi/grub-i386-efi.port @@ -0,0 +1,7 @@ +NAME=grub-i386-efi +EDITION=2 +BUILD_LIBRARIES='libiconv? libintl? libfreetype? liblzma?' +SOURCE_PORT=grub +BUILD_SYSTEM=configure +CONFIGURE_ARGS='--disable-werror --program-prefix= --with-platform=efi --target=i686-sortix' +MAKE_ARGS='-C grub-core' diff --git a/ports/grub-i386-pc/grub-i386-pc.port b/ports/grub-i386-pc/grub-i386-pc.port new file mode 100644 index 00000000..493b4cd9 --- /dev/null +++ b/ports/grub-i386-pc/grub-i386-pc.port @@ -0,0 +1,8 @@ +NAME=grub-i386-pc +EDITION=2 +RENAMES="grub@1: grub-i386-pc@2" +BUILD_LIBRARIES='libiconv? libintl? libfreetype? liblzma?' +SOURCE_PORT=grub +BUILD_SYSTEM=configure +CONFIGURE_ARGS='--disable-werror --program-prefix= --with-platform=pc' +MAKE_ARGS='-C grub-core' diff --git a/ports/grub-x86_64-efi/grub-x86_64-efi.port b/ports/grub-x86_64-efi/grub-x86_64-efi.port new file mode 100644 index 00000000..4bc808b5 --- /dev/null +++ b/ports/grub-x86_64-efi/grub-x86_64-efi.port @@ -0,0 +1,8 @@ +NAME=grub-x86_64-efi +EDITION=2 +BUILD_LIBRARIES='libiconv? libintl? libfreetype? liblzma?' +SOURCE_PORT=grub +BUILD_SYSTEM=configure +# TODO: Unfortunately 32-bit sortix gcc fails due to no 64-bit support. +CONFIGURE_ARGS='--disable-werror --program-prefix= --with-platform=efi --target=x86_64-sortix' +MAKE_ARGS='-C grub-core' diff --git a/ports/grub/grub.patch b/ports/grub/grub.patch index 813397d2..738957fd 100644 --- a/ports/grub/grub.patch +++ b/ports/grub/grub.patch @@ -253,6 +253,36 @@ diff -Paur --no-dereference -- grub.upstream/grub-core/lib/libgcrypt-grub/cipher { k[i >> 2][i & 3] = key[i]; } +diff -Paur --no-dereference -- grub.upstream/grub-core/osdep/basic/platform.c grub/grub-core/osdep/basic/platform.c +--- grub.upstream/grub-core/osdep/basic/platform.c ++++ grub/grub-core/osdep/basic/platform.c +@@ -18,9 +18,25 @@ + + #include + ++#ifdef __sortix__ ++#include ++ ++#include ++#endif ++ + const char * + grub_install_get_default_x86_platform (void) +-{ ++{ ++#ifdef __sortix__ ++ char firmware[16]; ++ if (!kernelinfo("firmware", firmware, sizeof(firmware)) && ++ !strcmp(firmware, "efi")) ++#ifdef __i386__ ++ return "i386-efi"; ++#else ++ return "x86_64-efi"; ++#endif ++#endif + return "i386-pc"; + } + diff -Paur --no-dereference -- grub.upstream/grub-core/osdep/getroot.c grub/grub-core/osdep/getroot.c --- grub.upstream/grub-core/osdep/getroot.c +++ grub/grub-core/osdep/getroot.c @@ -564,6 +594,41 @@ diff -Paur --no-dereference -- grub.upstream/grub-core/osdep/sortix/random.c gru + arc4random_buf(out, len); + return 0; +} +diff -Paur --no-dereference -- grub.upstream/grub-core/osdep/unix/config.c grub/grub-core/osdep/unix/config.c +--- grub.upstream/grub-core/osdep/unix/config.c ++++ grub/grub-core/osdep/unix/config.c +@@ -35,8 +35,7 @@ + { + static char *value = NULL; + if (!value) +- value = grub_util_path_concat (3, GRUB_SYSCONFDIR, +- "default", "grub"); ++ value = grub_util_path_concat (2, GRUB_SYSCONFDIR, "grub"); + return value; + } + +@@ -78,6 +77,10 @@ + if (v && v[0] == 'y' && v[1] == '\0') + cfg->is_cryptodisk_enabled = 1; + ++ v = getenv ("GRUB_REMOVABLE"); ++ if (v && grub_strcmp (v, "true") == 0) ++ cfg->is_removable = 1; ++ + v = getenv ("GRUB_DISTRIBUTOR"); + if (v) + cfg->grub_distributor = xstrdup (v); +@@ -105,8 +108,8 @@ + *ptr++ = *iptr; + } + +- strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" " +- "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\""); ++ strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_REMOVABLE=%s\\nGRUB_DISTRIBUTOR=%s\\n\" " ++ "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_REMOVABLE\" \"$GRUB_DISTRIBUTOR\""); + + argv[2] = script; + argv[3] = '\0'; diff -Paur --no-dereference -- grub.upstream/grub-core/osdep/unix/getroot.c grub/grub-core/osdep/unix/getroot.c --- grub.upstream/grub-core/osdep/unix/getroot.c +++ grub/grub-core/osdep/unix/getroot.c @@ -640,6 +705,17 @@ diff -Paur --no-dereference -- grub.upstream/grub-core/osdep/unix/platform.c gru bootnum = line + sizeof ("Boot") - 1; bootnum[4] = '\0'; if (!verbosity) +diff -Paur --no-dereference -- grub.upstream/include/grub/emu/config.h grub/include/grub/emu/config.h +--- grub.upstream/include/grub/emu/config.h ++++ grub/include/grub/emu/config.h +@@ -36,6 +36,7 @@ + struct grub_util_config + { + int is_cryptodisk_enabled; ++ int is_removable; + char *grub_distributor; + }; + diff -Paur --no-dereference -- grub.upstream/include/grub/emu/getroot.h grub/include/grub/emu/getroot.h --- grub.upstream/include/grub/emu/getroot.h +++ grub/include/grub/emu/getroot.h @@ -670,6 +746,27 @@ diff -Paur --no-dereference -- grub.upstream/util/bash-completion.d/Makefile.in bashcompletion_DATA = $(bash_completion_script) all: all-am +diff -Paur --no-dereference -- grub.upstream/util/config.c grub/util/config.c +--- grub.upstream/util/config.c ++++ grub/util/config.c +@@ -42,6 +42,17 @@ + cfg->is_cryptodisk_enabled = 1; + continue; + } ++ if (grub_strncmp (ptr, "GRUB_REMOVABLE=", ++ sizeof ("GRUB_REMOVABLE=") - 1) == 0) ++ { ++ ptr += sizeof ("GRUB_REMOVABLE=") - 1; ++ if (*ptr == '"' || *ptr == '\'') ++ ptr++; ++ if (grub_strncmp (ptr, "true", sizeof ("true") - 1) == 0) ++ cfg->is_removable = 1; ++ continue; ++ } ++ + if (grub_strncmp (ptr, "GRUB_DISTRIBUTOR=", + sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0) + { diff -Paur --no-dereference -- grub.upstream/util/getroot.c grub/util/getroot.c --- grub.upstream/util/getroot.c +++ grub/util/getroot.c @@ -724,6 +821,44 @@ diff -Paur --no-dereference -- grub.upstream/util/grub-fstest.c grub/util/grub-f root = alloc_root; } } +diff -Paur --no-dereference -- grub.upstream/util/grub-install.c grub/util/grub-install.c +--- grub.upstream/util/grub-install.c ++++ grub/util/grub-install.c +@@ -848,6 +848,9 @@ + + grub_util_load_config (&config); + ++ if (config.is_removable) ++ removable = 1; ++ + if (!bootloader_id && config.grub_distributor) + { + char *ptr; +@@ -860,7 +863,7 @@ + if (!bootloader_id || bootloader_id[0] == '\0') + { + free (bootloader_id); +- bootloader_id = xstrdup ("grub"); ++ bootloader_id = xstrdup ("sortix"); + } + + if (!grub_install_source_directory) +@@ -1803,6 +1806,7 @@ + break; + + case GRUB_INSTALL_PLATFORM_I386_EFI: ++#ifndef __sortix__ + if (!efidir_is_mac) + { + char *dst = grub_util_path_concat (2, efidir, "grub.efi"); +@@ -1810,6 +1814,7 @@ + grub_install_copy_file (imgfile, dst, 1); + free (dst); + } ++#endif + /* Fallthrough. */ + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + if (efidir_is_mac) diff -Paur --no-dereference -- grub.upstream/util/grub-mkconfig.in grub/util/grub-mkconfig.in --- grub.upstream/util/grub-mkconfig.in +++ grub/util/grub-mkconfig.in @@ -924,7 +1059,7 @@ diff -Paur --no-dereference -- grub.upstream/util/grub.d/10_sortix.in grub/util/ + insmod part_$PARTMAP + insmod $FS + search --no-floppy --fs-uuid --set=root $HINTS_STRING $FS_UUID -+ multiboot $BOOT_REL/sortix.bin $GRUB_CMDLINE_SORTIX ++ multiboot $BOOT_REL/sortix.bin --firmware=\$grub_platform $GRUB_CMDLINE_SORTIX + module $OLD_BOOT_REL/random.seed --random-seed + module $BOOT_REL/sortix.initrd +} diff --git a/ports/grub/grub.port b/ports/grub/grub.port index 957735ed..021e9e9e 100644 --- a/ports/grub/grub.port +++ b/ports/grub/grub.port @@ -1,4 +1,6 @@ NAME=grub +EDITION=2 +RENAMES="grub@1: grub@2" BUILD_LIBRARIES='libiconv? libintl? libfreetype? liblzma?' VERSION=1.0-rc1 DISTNAME=sortix-grub-$VERSION @@ -8,6 +10,6 @@ SHA256SUM=82ac8faf257fb3476969a0b79a0b5fd53d4cdefb2e2aa5941381477e38c5f9c5 UPSTREAM_SITE=https://pub.sortix.org/sortix/toolchain UPSTREAM_ARCHIVE=$ARCHIVE BUILD_SYSTEM=configure -CONFIGURE_ARGS='--disable-werror --program-prefix=' +CONFIGURE_ARGS='--disable-werror --program-prefix= --with-platform=none' POST_INSTALL=../grub.post-install -VERSION_REGEX='([0-9]+\.[0-9]+(\.[0-9]+)*(-rc[0-9]+)?)' +VERSION_REGEX='([0-9]+\.[0-9]+(\.[0-9]+)*(-rc[0-9]+)?) diff --git a/ports/grub/grub.post-install b/ports/grub/grub.post-install index ffa35618..3a7464d4 100755 --- a/ports/grub/grub.post-install +++ b/ports/grub/grub.post-install @@ -7,3 +7,6 @@ if [ ! -e "$TIX_INSTALL_DIR$PREFIX/share/grub/unicode.pf2" ]; then [ -e /usr/share/grub/unicode.pf2 ] && cp /usr/share/grub/unicode.pf2 "$TIX_INSTALL_DIR$PREFIX/share/grub/unicode.pf2" fi +rm -rf "$TIX_INSTALL_DIR$PREFIX/lib/grub/"*"-none" +rmdir --ignore-fail-on-non-empty "$TIX_INSTALL_DIR$PREFIX/lib/grub" +rmdir --ignore-fail-on-non-empty "$TIX_INSTALL_DIR$PREFIX/lib" diff --git a/sysinstall/sysinstall.c b/sysinstall/sysinstall.c index 3bfe8242..24e3eb1e 100644 --- a/sysinstall/sysinstall.c +++ b/sysinstall/sysinstall.c @@ -69,11 +69,6 @@ const char* prompt_man_page = "installation"; static struct partition_table* search_bios_boot_pt(struct filesystem* root_fs) { - char firmware[64]; - if ( kernelinfo("firmware", firmware, sizeof(firmware)) != 0 ) - return NULL; - if ( strcmp(firmware, "bios") != 0 ) - return NULL; struct blockdevice* bdev = root_fs->bdev; while ( bdev->p ) bdev = bdev->p->parent_bdev; @@ -194,6 +189,10 @@ static bool should_install_bootloader_bdev(struct blockdevice* bdev) static bool should_install_bootloader(void) { + char firmware[16]; + if ( !kernelinfo("firmware", firmware, sizeof(firmware)) && + !strcmp(firmware, "efi") ) + return true; bool any_systems = false; for ( size_t i = 0; i < hds_count; i++ ) { @@ -354,6 +353,9 @@ static void grub_hash_password(char* buffer, size_t buffer_size, const char* pw) static const char* const ignore_kernel_options[] = { + "--firmware=bios", + "--firmware=efi", + "--firmware=pc", "--no-random-seed", "--random-seed", NULL, @@ -511,7 +513,12 @@ int main(void) err(2, "chdir: %s", etc); struct utsname uts; - uname(&uts); + if ( uname(&uts) < 0 ) + err(1, "uname"); + + char firmware[16]; + if ( kernelinfo("firmware", firmware, sizeof(firmware)) != 0 ) + err(1, "kernelinfo"); struct conf conf; conf_init(&conf); @@ -572,6 +579,7 @@ int main(void) missing_program("fsck.ext2") | missing_program("grub-install") | missing_program("man") | + (!strcmp(firmware, "efi") && missing_program("mkfs.fat")) | missing_program("sed") | missing_program("xargs") ) { @@ -909,6 +917,7 @@ int main(void) mktable_tip, devices_tip); struct filesystem* root_filesystem = NULL; struct filesystem* boot_filesystem = NULL; + struct filesystem* esp_filesystem = NULL; struct filesystem* bootloader_filesystem = NULL; bool not_first = false; while ( true ) @@ -951,6 +960,7 @@ int main(void) } root_filesystem = NULL; boot_filesystem = NULL; + esp_filesystem = NULL; bool cant_mount = false; for ( size_t i = 0; i < mountpoints_used; i++ ) { @@ -976,6 +986,8 @@ int main(void) root_filesystem = mnt->fs; if ( !strcmp(mnt->entry.fs_file, "/boot") ) boot_filesystem = mnt->fs; + if ( !strcmp(mnt->entry.fs_file, "/boot/efi") ) + esp_filesystem = mnt->fs; } if ( cant_mount ) continue; @@ -983,12 +995,13 @@ int main(void) bootloader_filesystem = boot_filesystem ? boot_filesystem : root_filesystem; assert(bootloader_filesystem); if ( !strcasecmp(accept_grub, "yes") && + !strcmp(firmware, "bios") && missing_bios_boot_partition(bootloader_filesystem) ) { const char* where = boot_filesystem ? "/boot" : "root"; const char* dev = device_path_of_blockdevice(bootloader_filesystem->bdev); assert(dev); - textf("You are a installing BIOS bootloader and the %s " + textf("You are installing a BIOS bootloader and the %s " "filesystem is located on a GPT partition, but you haven't " "made a BIOS boot partition on the %s GPT disk. Pick " "biosboot during mkpart and make a 1 MiB partition.\n", @@ -1007,10 +1020,41 @@ int main(void) continue; text("Proceeding, but expect the installation to fail.\n"); } + else if ( !strcasecmp(accept_grub, "yes") && + !strcmp(firmware, "efi") && + !esp_filesystem ) + { + textf("You are installing an EFI bootloader, but you haven't made " + "an EFI System Partition. Pick efi during mkpart and make a " + "partition and mount it as /boot/efi.\n"); + char return_to_disked[10]; + while ( true ) + { + // TODO: Document autoinstall key. + prompt(return_to_disked, sizeof(return_to_disked), + "missing_esp_partition", + "Return to disked to make an EFI partition?", "yes"); + if ( strcasecmp(accept_grub, "no") == 0 || + strcasecmp(accept_grub, "yes") == 0 ) + break; + } + if ( !strcasecmp(return_to_disked, "yes") ) + continue; + text("Proceeding, but expect the installation to fail.\n"); + } + // TODO: Verify the ESP is actually FAT and has the correct ID/GUID. + break; } text("\n"); + if ( !strcmp(firmware, "efi") ) + { + // TODO: Ask for GRUB_DISTRIBUTOR when FAT LFN is implemented and make + // GRUB_REMOVABLE optional. + install_configurationf("grub", "w", "GRUB_REMOVABLE=true\n"); + } + textf("We are now ready to install %s %s. Take a moment to verify " "everything is in order.\n", BRAND_DISTRIBUTION_NAME, VERSIONSTR); text("\n"); @@ -1022,7 +1066,7 @@ int main(void) const char* where = mnt->entry.fs_file; printf(" %-16s use as %s\n", devname, where); } - if ( strcasecmp(accept_grub, "yes") == 0 ) + if ( strcasecmp(accept_grub, "yes") == 0 && !strcmp(firmware, "bios") ) { struct partition* bbp = search_bios_boot_partition(bootloader_filesystem); if ( bbp ) @@ -1118,8 +1162,7 @@ int main(void) { printf(" - Installing bootloader...\n"); execute((const char*[]) { "chroot", "-d", ".", "grub-install", - device_path_of_blockdevice(bootloader_filesystem->bdev), NULL }, - "_eqQ"); + NULL }, "_eqQ"); printf(" - Configuring bootloader...\n"); execute((const char*[]) { "chroot", "-d", ".", "update-grub", NULL }, "_eqQ");