Copy apple-boot firmware to EFI system partition. This enables automatic
authortobhe <tobhe@openbsd.org>
Tue, 22 Nov 2022 09:53:46 +0000 (09:53 +0000)
committertobhe <tobhe@openbsd.org>
Tue, 22 Nov 2022 09:53:46 +0000 (09:53 +0000)
bootloader updates on Apple Silicon computers.  We rely on fw_update(8)
to place apple-boot.bin in /etc/firmware.  installboot(8) will pick it
up from there and copy it to $ESP/m1n1/boot.bin, if this directory
exists.  The m1n1 directory and original boot.bin are created by the
Asahi Linux installer as part of the initial UEFI environment.

The firmware package was manually tested by many.
Regress, installation and upgrade with and without apple-boot.bin tested by me.

Feedback and ok kettenis@ kn@

usr.sbin/installboot/efi_installboot.c

index 77e7130..643254f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: efi_installboot.c,v 1.7 2022/11/06 12:33:41 krw Exp $ */
+/*     $OpenBSD: efi_installboot.c,v 1.8 2022/11/22 09:53:46 tobhe Exp $       */
 /*     $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */
 
 /*
@@ -70,6 +70,7 @@
 
 static int     create_filesystem(struct disklabel *, char);
 static void    write_filesystem(struct disklabel *, char);
+static int     write_firmware(const char *, const char *);
 static int     findgptefisys(int, struct disklabel *);
 static int     findmbrfat(int, struct disklabel *);
 
@@ -308,7 +309,10 @@ write_filesystem(struct disklabel *dl, char part)
                        goto umount;
        }
 
-       rslt = 0;
+       dst[mntlen] = '\0';
+       rslt = write_firmware(root, dst);
+       if (rslt == -1)
+               warnx("unable to write firmware");
 
 umount:
        dst[mntlen] = '\0';
@@ -327,6 +331,60 @@ rmdir:
                exit(1);
 }
 
+static int
+write_firmware(const char *root, const char *mnt)
+{
+       char dst[PATH_MAX];
+       char fw[PATH_MAX];
+       char *src;
+       struct stat st;
+       int rslt;
+
+       strlcpy(dst, mnt, sizeof(dst));
+
+       /* Skip if no /etc/firmware exists */
+       rslt = snprintf(fw, sizeof(fw), "%s/%s", root, "etc/firmware");
+       if (rslt < 0 || rslt >= PATH_MAX) {
+               warnx("unable to build /etc/firmware path");
+               return -1;
+       }
+       if ((stat(fw, &st) != 0) || !S_ISDIR(st.st_mode))
+               return 0;
+
+       /* Copy apple-boot firmware to /m1n1/boot.bin if available */
+       src = fileprefix(fw, "/apple-boot.bin");
+       if (src == NULL)
+               return -1;
+       if (access(src, R_OK) == 0) {
+               if (strlcat(dst, "/m1n1", sizeof(dst)) >= sizeof(dst)) {
+                       rslt = -1;
+                       warnx("unable to build /m1n1 path");
+                       goto cleanup;
+               }
+               if ((stat(dst, &st) != 0) || !S_ISDIR(st.st_mode)) {
+                       rslt = 0;
+                       goto cleanup;
+               }
+               if (strlcat(dst, "/boot.bin", sizeof(dst)) >= sizeof(dst)) {
+                       rslt = -1;
+                       warnx("unable to build /m1n1/boot.bin path");
+                       goto cleanup;
+               }
+               if (verbose)
+                       fprintf(stderr, "%s %s to %s\n",
+                           (nowrite ? "would copy" : "copying"), src, dst);
+               if (!nowrite)
+                       rslt = filecopy(src, dst);
+                       if (rslt == -1)
+                               goto cleanup;
+       }
+       rslt = 0;
+
+ cleanup:
+       free(src);
+       return rslt;
+}
+
 /*
  * Returns 0 if the MBR with the provided partition array is a GPT protective
  * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only