1*db15c72aSkettenis /* $OpenBSD: efi_installboot.c,v 1.12 2024/11/08 10:43:07 kettenis Exp $ */ 2db32265bSvisa /* $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */ 3db32265bSvisa 4db32265bSvisa /* 5db32265bSvisa * Copyright (c) 2011 Joel Sing <jsing@openbsd.org> 6db32265bSvisa * Copyright (c) 2010 Otto Moerbeek <otto@openbsd.org> 7db32265bSvisa * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com> 8db32265bSvisa * Copyright (c) 1997 Michael Shalayeff 9db32265bSvisa * Copyright (c) 1994 Paul Kranenburg 10db32265bSvisa * All rights reserved. 11db32265bSvisa * 12db32265bSvisa * Redistribution and use in source and binary forms, with or without 13db32265bSvisa * modification, are permitted provided that the following conditions 14db32265bSvisa * are met: 15db32265bSvisa * 1. Redistributions of source code must retain the above copyright 16db32265bSvisa * notice, this list of conditions and the following disclaimer. 17db32265bSvisa * 2. Redistributions in binary form must reproduce the above copyright 18db32265bSvisa * notice, this list of conditions and the following disclaimer in the 19db32265bSvisa * documentation and/or other materials provided with the distribution. 20db32265bSvisa * 3. All advertising materials mentioning features or use of this software 21db32265bSvisa * must display the following acknowledgement: 22db32265bSvisa * This product includes software developed by Paul Kranenburg. 23db32265bSvisa * 4. The name of the author may not be used to endorse or promote products 24db32265bSvisa * derived from this software without specific prior written permission 25db32265bSvisa * 26db32265bSvisa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27db32265bSvisa * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28db32265bSvisa * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29db32265bSvisa * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30db32265bSvisa * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31db32265bSvisa * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32db32265bSvisa * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33db32265bSvisa * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34db32265bSvisa * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35db32265bSvisa * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36db32265bSvisa */ 37db32265bSvisa 38db32265bSvisa #include <sys/param.h> /* DEV_BSIZE */ 39db32265bSvisa #include <sys/disklabel.h> 40db32265bSvisa #include <sys/dkio.h> 41db32265bSvisa #include <sys/ioctl.h> 42db32265bSvisa #include <sys/mount.h> 43db32265bSvisa #include <sys/stat.h> 44db32265bSvisa 45db32265bSvisa #include <err.h> 46db32265bSvisa #include <errno.h> 47db32265bSvisa #include <fcntl.h> 48db32265bSvisa #include <stdlib.h> 49db32265bSvisa #include <stdio.h> 50db32265bSvisa #include <stdint.h> 51db32265bSvisa #include <string.h> 52db32265bSvisa #include <unistd.h> 53db32265bSvisa #include <util.h> 54db32265bSvisa #include <uuid.h> 55db32265bSvisa 56db32265bSvisa #include "installboot.h" 57db32265bSvisa 584a5d5189Svisa #if defined(__aarch64__) 594a5d5189Svisa #define BOOTEFI_SRC "BOOTAA64.EFI" 604a5d5189Svisa #define BOOTEFI_DST "bootaa64.efi" 614a5d5189Svisa #elif defined(__arm__) 624a5d5189Svisa #define BOOTEFI_SRC "BOOTARM.EFI" 634a5d5189Svisa #define BOOTEFI_DST "bootarm.efi" 644a5d5189Svisa #elif defined(__riscv) 654a5d5189Svisa #define BOOTEFI_SRC "BOOTRISCV64.EFI" 664a5d5189Svisa #define BOOTEFI_DST "bootriscv64.efi" 674a5d5189Svisa #else 684a5d5189Svisa #error "unhandled architecture" 694a5d5189Svisa #endif 704a5d5189Svisa 71db32265bSvisa static int create_filesystem(struct disklabel *, char); 72db32265bSvisa static void write_filesystem(struct disklabel *, char); 738fb3e437Stobhe static int write_firmware(const char *, const char *); 74db32265bSvisa static int findgptefisys(int, struct disklabel *); 75db32265bSvisa static int findmbrfat(int, struct disklabel *); 76db32265bSvisa 77db32265bSvisa void 78db32265bSvisa md_init(void) 79db32265bSvisa { 8022942c2fSkn stages = 1; 8122942c2fSkn stage1 = "/usr/mdec/" BOOTEFI_SRC; 82db32265bSvisa } 83db32265bSvisa 84db32265bSvisa void 85db32265bSvisa md_loadboot(void) 86db32265bSvisa { 87db32265bSvisa } 88db32265bSvisa 89db32265bSvisa void 90db32265bSvisa md_prepareboot(int devfd, char *dev) 91db32265bSvisa { 92db32265bSvisa struct disklabel dl; 93db32265bSvisa int part; 94db32265bSvisa 95db32265bSvisa /* Get and check disklabel. */ 96db32265bSvisa if (ioctl(devfd, DIOCGDINFO, &dl) == -1) 97db32265bSvisa err(1, "disklabel: %s", dev); 98db32265bSvisa if (dl.d_magic != DISKMAGIC) 99db32265bSvisa errx(1, "bad disklabel magic=0x%08x", dl.d_magic); 100db32265bSvisa 101db32265bSvisa /* Warn on unknown disklabel types. */ 102db32265bSvisa if (dl.d_type == 0) 103db32265bSvisa warnx("disklabel type unknown"); 104db32265bSvisa 105db32265bSvisa part = findgptefisys(devfd, &dl); 10614cbb8d0Skn if (part != -1) { 10714cbb8d0Skn create_filesystem(&dl, (char)part); 10814cbb8d0Skn return; 10914cbb8d0Skn } 11014cbb8d0Skn 111db32265bSvisa part = findmbrfat(devfd, &dl); 112db32265bSvisa if (part != -1) { 11314cbb8d0Skn create_filesystem(&dl, (char)part); 11414cbb8d0Skn return; 115db32265bSvisa } 116db32265bSvisa } 117db32265bSvisa 118db32265bSvisa void 119db32265bSvisa md_installboot(int devfd, char *dev) 120db32265bSvisa { 121db32265bSvisa struct disklabel dl; 122db32265bSvisa int part; 123db32265bSvisa 124db32265bSvisa /* Get and check disklabel. */ 125db32265bSvisa if (ioctl(devfd, DIOCGDINFO, &dl) == -1) 126db32265bSvisa err(1, "disklabel: %s", dev); 127db32265bSvisa if (dl.d_magic != DISKMAGIC) 128db32265bSvisa errx(1, "bad disklabel magic=0x%08x", dl.d_magic); 129db32265bSvisa 130db32265bSvisa /* Warn on unknown disklabel types. */ 131db32265bSvisa if (dl.d_type == 0) 132db32265bSvisa warnx("disklabel type unknown"); 133db32265bSvisa 134db32265bSvisa part = findgptefisys(devfd, &dl); 135db32265bSvisa if (part != -1) { 136db32265bSvisa write_filesystem(&dl, (char)part); 137db32265bSvisa return; 138db32265bSvisa } 139db32265bSvisa 140db32265bSvisa part = findmbrfat(devfd, &dl); 141db32265bSvisa if (part != -1) { 142db32265bSvisa write_filesystem(&dl, (char)part); 143db32265bSvisa return; 144db32265bSvisa } 145db32265bSvisa } 146db32265bSvisa 147db32265bSvisa static int 148db32265bSvisa create_filesystem(struct disklabel *dl, char part) 149db32265bSvisa { 1507a17f38cSkrw static const char *newfsfmt = "/sbin/newfs -t msdos %s >/dev/null"; 151db32265bSvisa struct msdosfs_args args; 152db32265bSvisa char cmd[60]; 153db32265bSvisa int rslt; 154db32265bSvisa 155acd6e620Skn /* Newfs <duid>.<part> as msdos filesystem. */ 156db32265bSvisa memset(&args, 0, sizeof(args)); 157db32265bSvisa rslt = asprintf(&args.fspec, 158db32265bSvisa "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 159db32265bSvisa dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], 160db32265bSvisa dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], 161db32265bSvisa part); 162db32265bSvisa if (rslt == -1) { 163db32265bSvisa warn("bad special device"); 164db32265bSvisa return rslt; 165db32265bSvisa } 166db32265bSvisa 167db32265bSvisa rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec); 168db32265bSvisa if (rslt >= sizeof(cmd)) { 169db32265bSvisa warnx("can't build newfs command"); 170993e4236Skrw free(args.fspec); 171db32265bSvisa rslt = -1; 172db32265bSvisa return rslt; 173db32265bSvisa } 174db32265bSvisa 175db32265bSvisa if (verbose) 176db32265bSvisa fprintf(stderr, "%s %s\n", 177db32265bSvisa (nowrite ? "would newfs" : "newfsing"), args.fspec); 178db32265bSvisa if (!nowrite) { 179db32265bSvisa rslt = system(cmd); 180db32265bSvisa if (rslt == -1) { 181db32265bSvisa warn("system('%s') failed", cmd); 182993e4236Skrw free(args.fspec); 183db32265bSvisa return rslt; 184db32265bSvisa } 185db32265bSvisa } 186db32265bSvisa 187993e4236Skrw free(args.fspec); 188db32265bSvisa return 0; 189db32265bSvisa } 190db32265bSvisa 191db32265bSvisa static void 192db32265bSvisa write_filesystem(struct disklabel *dl, char part) 193db32265bSvisa { 1947a17f38cSkrw static const char *fsckfmt = "/sbin/fsck -t msdos %s >/dev/null"; 195db32265bSvisa struct msdosfs_args args; 196*db15c72aSkettenis struct statfs sf; 197db32265bSvisa char cmd[60]; 198db32265bSvisa char dst[PATH_MAX]; 199db32265bSvisa char *src; 200db32265bSvisa size_t mntlen, pathlen, srclen; 201db32265bSvisa int rslt; 202db32265bSvisa 203db32265bSvisa src = NULL; 204db32265bSvisa 205db32265bSvisa /* Create directory for temporary mount point. */ 206db32265bSvisa strlcpy(dst, "/tmp/installboot.XXXXXXXXXX", sizeof(dst)); 207db32265bSvisa if (mkdtemp(dst) == NULL) 208db32265bSvisa err(1, "mkdtemp('%s') failed", dst); 209db32265bSvisa mntlen = strlen(dst); 210db32265bSvisa 211db32265bSvisa /* Mount <duid>.<part> as msdos filesystem. */ 212db32265bSvisa memset(&args, 0, sizeof(args)); 213db32265bSvisa rslt = asprintf(&args.fspec, 214db32265bSvisa "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 215db32265bSvisa dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], 216db32265bSvisa dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], 217db32265bSvisa part); 218db32265bSvisa if (rslt == -1) { 219db32265bSvisa warn("bad special device"); 220db32265bSvisa goto rmdir; 221db32265bSvisa } 222db32265bSvisa 223db32265bSvisa args.export_info.ex_root = -2; 224db32265bSvisa args.export_info.ex_flags = 0; 225db32265bSvisa args.flags = MSDOSFSMNT_LONGNAME; 226db32265bSvisa 227db32265bSvisa if (mount(MOUNT_MSDOS, dst, 0, &args) == -1) { 228db32265bSvisa /* Try fsck'ing it. */ 229db32265bSvisa rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec); 230db32265bSvisa if (rslt >= sizeof(cmd)) { 231db32265bSvisa warnx("can't build fsck command"); 232db32265bSvisa rslt = -1; 233db32265bSvisa goto rmdir; 234db32265bSvisa } 235db32265bSvisa rslt = system(cmd); 236db32265bSvisa if (rslt == -1) { 237db32265bSvisa warn("system('%s') failed", cmd); 238db32265bSvisa goto rmdir; 239db32265bSvisa } 240db32265bSvisa if (mount(MOUNT_MSDOS, dst, 0, &args) == -1) { 241db32265bSvisa /* Try newfs'ing it. */ 242db32265bSvisa rslt = create_filesystem(dl, part); 243db32265bSvisa if (rslt == -1) 244db32265bSvisa goto rmdir; 245db32265bSvisa rslt = mount(MOUNT_MSDOS, dst, 0, &args); 246db32265bSvisa if (rslt == -1) { 247db32265bSvisa warn("unable to mount EFI System partition"); 248db32265bSvisa goto rmdir; 249db32265bSvisa } 250db32265bSvisa } 251db32265bSvisa } 252db32265bSvisa 253db32265bSvisa /* Create "/efi/boot" directory in <duid>.<part>. */ 254db32265bSvisa if (strlcat(dst, "/efi", sizeof(dst)) >= sizeof(dst)) { 255db32265bSvisa rslt = -1; 256db32265bSvisa warn("unable to build /efi directory"); 257db32265bSvisa goto umount; 258db32265bSvisa } 259db32265bSvisa rslt = mkdir(dst, 0755); 260db32265bSvisa if (rslt == -1 && errno != EEXIST) { 261db32265bSvisa warn("mkdir('%s') failed", dst); 262db32265bSvisa goto umount; 263db32265bSvisa } 264db32265bSvisa if (strlcat(dst, "/boot", sizeof(dst)) >= sizeof(dst)) { 265db32265bSvisa rslt = -1; 266db32265bSvisa warn("unable to build /boot directory"); 267db32265bSvisa goto umount; 268db32265bSvisa } 269db32265bSvisa rslt = mkdir(dst, 0755); 270db32265bSvisa if (rslt == -1 && errno != EEXIST) { 271db32265bSvisa warn("mkdir('%s') failed", dst); 272db32265bSvisa goto umount; 273db32265bSvisa } 274db32265bSvisa 2754a5d5189Svisa /* Copy EFI bootblocks to /efi/boot/. */ 276db32265bSvisa pathlen = strlen(dst); 2774a5d5189Svisa if (strlcat(dst, "/" BOOTEFI_DST, sizeof(dst)) >= sizeof(dst)) { 278db32265bSvisa rslt = -1; 2794a5d5189Svisa warn("unable to build /%s path", BOOTEFI_DST); 280db32265bSvisa goto umount; 281db32265bSvisa } 2824a5d5189Svisa src = fileprefix(root, "/usr/mdec/" BOOTEFI_SRC); 283db32265bSvisa if (src == NULL) { 284db32265bSvisa rslt = -1; 285db32265bSvisa goto umount; 286db32265bSvisa } 287db32265bSvisa srclen = strlen(src); 288db32265bSvisa if (verbose) 289db32265bSvisa fprintf(stderr, "%s %s to %s\n", 290db32265bSvisa (nowrite ? "would copy" : "copying"), src, dst); 291db32265bSvisa if (!nowrite) { 292db32265bSvisa rslt = filecopy(src, dst); 293db32265bSvisa if (rslt == -1) 294db32265bSvisa goto umount; 295db32265bSvisa } 296db32265bSvisa 2974a5d5189Svisa /* Write /efi/boot/startup.nsh. */ 2984a5d5189Svisa dst[pathlen] = '\0'; 2994a5d5189Svisa if (strlcat(dst, "/startup.nsh", sizeof(dst)) >= sizeof(dst)) { 3004a5d5189Svisa rslt = -1; 3014a5d5189Svisa warn("unable to build /startup.nsh path"); 3024a5d5189Svisa goto umount; 3034a5d5189Svisa } 3044a5d5189Svisa if (verbose) 3054a5d5189Svisa fprintf(stderr, "%s %s\n", 3064a5d5189Svisa (nowrite ? "would write" : "writing"), dst); 3074a5d5189Svisa if (!nowrite) { 3084a5d5189Svisa rslt = fileprintf(dst, "%s\n", BOOTEFI_DST); 3094a5d5189Svisa if (rslt == -1) 3104a5d5189Svisa goto umount; 3114a5d5189Svisa } 3124a5d5189Svisa 313*db15c72aSkettenis /* Skip installing a 2nd copy if we have a small filesystem. */ 314*db15c72aSkettenis if (statfs(dst, &sf) || sf.f_blocks < 2048) { 315*db15c72aSkettenis rslt = 0; 316*db15c72aSkettenis goto firmware; 317*db15c72aSkettenis } 318*db15c72aSkettenis 319fbfcabeaSkettenis /* Create "/efi/openbsd" directory in <duid>.<part>. */ 320fbfcabeaSkettenis dst[mntlen] = '\0'; 321fbfcabeaSkettenis if (strlcat(dst, "/efi/openbsd", sizeof(dst)) >= sizeof(dst)) { 322fbfcabeaSkettenis rslt = -1; 323fbfcabeaSkettenis warn("unable to build /efi/openbsd directory"); 324fbfcabeaSkettenis goto umount; 325fbfcabeaSkettenis } 326fbfcabeaSkettenis rslt = mkdir(dst, 0755); 327fbfcabeaSkettenis if (rslt == -1 && errno != EEXIST) { 328fbfcabeaSkettenis warn("mkdir('%s') failed", dst); 329fbfcabeaSkettenis goto umount; 330fbfcabeaSkettenis } 331fbfcabeaSkettenis 332fbfcabeaSkettenis /* Copy EFI bootblocks to /efi/openbsd/. */ 333fbfcabeaSkettenis if (strlcat(dst, "/" BOOTEFI_DST, sizeof(dst)) >= sizeof(dst)) { 334fbfcabeaSkettenis rslt = -1; 335fbfcabeaSkettenis warn("unable to build /%s path", BOOTEFI_DST); 336fbfcabeaSkettenis goto umount; 337fbfcabeaSkettenis } 338fbfcabeaSkettenis src = fileprefix(root, "/usr/mdec/" BOOTEFI_SRC); 339fbfcabeaSkettenis if (src == NULL) { 340fbfcabeaSkettenis rslt = -1; 341fbfcabeaSkettenis goto umount; 342fbfcabeaSkettenis } 343fbfcabeaSkettenis srclen = strlen(src); 344fbfcabeaSkettenis if (verbose) 345fbfcabeaSkettenis fprintf(stderr, "%s %s to %s\n", 346fbfcabeaSkettenis (nowrite ? "would copy" : "copying"), src, dst); 347fbfcabeaSkettenis if (!nowrite) { 348fbfcabeaSkettenis rslt = filecopy(src, dst); 349fbfcabeaSkettenis if (rslt == -1) 350fbfcabeaSkettenis goto umount; 351fbfcabeaSkettenis } 352fbfcabeaSkettenis 353*db15c72aSkettenis firmware: 3548fb3e437Stobhe dst[mntlen] = '\0'; 3558fb3e437Stobhe rslt = write_firmware(root, dst); 3568fb3e437Stobhe if (rslt == -1) 3578fb3e437Stobhe warnx("unable to write firmware"); 358db32265bSvisa 359db32265bSvisa umount: 360db32265bSvisa dst[mntlen] = '\0'; 361db32265bSvisa if (unmount(dst, MNT_FORCE) == -1) 362db32265bSvisa err(1, "unmount('%s') failed", dst); 363db32265bSvisa 364db32265bSvisa rmdir: 365db32265bSvisa free(args.fspec); 366db32265bSvisa dst[mntlen] = '\0'; 367db32265bSvisa if (rmdir(dst) == -1) 368db32265bSvisa err(1, "rmdir('%s') failed", dst); 369db32265bSvisa 370db32265bSvisa free(src); 371db32265bSvisa 372db32265bSvisa if (rslt == -1) 373db32265bSvisa exit(1); 374db32265bSvisa } 375db32265bSvisa 3768fb3e437Stobhe static int 3778fb3e437Stobhe write_firmware(const char *root, const char *mnt) 3788fb3e437Stobhe { 3798fb3e437Stobhe char dst[PATH_MAX]; 3808fb3e437Stobhe char fw[PATH_MAX]; 3818fb3e437Stobhe char *src; 3828fb3e437Stobhe struct stat st; 3838fb3e437Stobhe int rslt; 3848fb3e437Stobhe 3858fb3e437Stobhe strlcpy(dst, mnt, sizeof(dst)); 3868fb3e437Stobhe 3878fb3e437Stobhe /* Skip if no /etc/firmware exists */ 3888fb3e437Stobhe rslt = snprintf(fw, sizeof(fw), "%s/%s", root, "etc/firmware"); 3898fb3e437Stobhe if (rslt < 0 || rslt >= PATH_MAX) { 3908fb3e437Stobhe warnx("unable to build /etc/firmware path"); 3918fb3e437Stobhe return -1; 3928fb3e437Stobhe } 3938fb3e437Stobhe if ((stat(fw, &st) != 0) || !S_ISDIR(st.st_mode)) 3948fb3e437Stobhe return 0; 3958fb3e437Stobhe 3968fb3e437Stobhe /* Copy apple-boot firmware to /m1n1/boot.bin if available */ 3978fb3e437Stobhe src = fileprefix(fw, "/apple-boot.bin"); 3988fb3e437Stobhe if (src == NULL) 3998fb3e437Stobhe return -1; 4008fb3e437Stobhe if (access(src, R_OK) == 0) { 4018fb3e437Stobhe if (strlcat(dst, "/m1n1", sizeof(dst)) >= sizeof(dst)) { 4028fb3e437Stobhe rslt = -1; 4038fb3e437Stobhe warnx("unable to build /m1n1 path"); 4048fb3e437Stobhe goto cleanup; 4058fb3e437Stobhe } 4068fb3e437Stobhe if ((stat(dst, &st) != 0) || !S_ISDIR(st.st_mode)) { 4078fb3e437Stobhe rslt = 0; 4088fb3e437Stobhe goto cleanup; 4098fb3e437Stobhe } 4108fb3e437Stobhe if (strlcat(dst, "/boot.bin", sizeof(dst)) >= sizeof(dst)) { 4118fb3e437Stobhe rslt = -1; 4128fb3e437Stobhe warnx("unable to build /m1n1/boot.bin path"); 4138fb3e437Stobhe goto cleanup; 4148fb3e437Stobhe } 4158fb3e437Stobhe if (verbose) 4168fb3e437Stobhe fprintf(stderr, "%s %s to %s\n", 4178fb3e437Stobhe (nowrite ? "would copy" : "copying"), src, dst); 418dcbdaee6Skn if (!nowrite) { 4198fb3e437Stobhe rslt = filecopy(src, dst); 4208fb3e437Stobhe if (rslt == -1) 4218fb3e437Stobhe goto cleanup; 4228fb3e437Stobhe } 423dcbdaee6Skn } 4248fb3e437Stobhe rslt = 0; 4258fb3e437Stobhe 4268fb3e437Stobhe cleanup: 4278fb3e437Stobhe free(src); 4288fb3e437Stobhe return rslt; 4298fb3e437Stobhe } 4308fb3e437Stobhe 431db32265bSvisa /* 432db32265bSvisa * Returns 0 if the MBR with the provided partition array is a GPT protective 433db32265bSvisa * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only 434db32265bSvisa * one MBR partition, an EFI partition that either covers the whole disk or as 435db32265bSvisa * much of it as is possible with a 32bit size field. 436db32265bSvisa * 437db32265bSvisa * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!** 438db32265bSvisa */ 439db32265bSvisa static int 440db32265bSvisa gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) 441db32265bSvisa { 442db32265bSvisa struct dos_partition *dp2; 443db32265bSvisa int efi, found, i; 444db32265bSvisa u_int32_t psize; 445db32265bSvisa 446db32265bSvisa found = efi = 0; 447db32265bSvisa for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) { 448db32265bSvisa if (dp2->dp_typ == DOSPTYP_UNUSED) 449db32265bSvisa continue; 450db32265bSvisa found++; 451db32265bSvisa if (dp2->dp_typ != DOSPTYP_EFI) 452db32265bSvisa continue; 453db32265bSvisa if (letoh32(dp2->dp_start) != GPTSECTOR) 454db32265bSvisa continue; 455db32265bSvisa psize = letoh32(dp2->dp_size); 456db32265bSvisa if (psize <= (dsize - GPTSECTOR) || psize == UINT32_MAX) 457db32265bSvisa efi++; 458db32265bSvisa } 459db32265bSvisa if (found == 1 && efi == 1) 460db32265bSvisa return (0); 461db32265bSvisa 462db32265bSvisa return (1); 463db32265bSvisa } 464db32265bSvisa 465db32265bSvisa int 466db32265bSvisa findgptefisys(int devfd, struct disklabel *dl) 467db32265bSvisa { 468db32265bSvisa struct gpt_partition gp[NGPTPARTITIONS]; 469db32265bSvisa struct gpt_header gh; 470db32265bSvisa struct dos_partition dp[NDOSPART]; 471db32265bSvisa struct uuid efisys_uuid; 472db32265bSvisa const char efisys_uuid_code[] = GPT_UUID_EFI_SYSTEM; 473db32265bSvisa off_t off; 474db32265bSvisa ssize_t len; 475db32265bSvisa u_int64_t start; 476db32265bSvisa int i; 477db32265bSvisa uint32_t orig_csum, new_csum; 478db32265bSvisa uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec; 479db32265bSvisa u_int8_t *secbuf; 480db32265bSvisa 481db32265bSvisa /* Prepare EFI System UUID */ 482db32265bSvisa uuid_dec_be(efisys_uuid_code, &efisys_uuid); 483db32265bSvisa 484db32265bSvisa if ((secbuf = malloc(dl->d_secsize)) == NULL) 485db32265bSvisa err(1, NULL); 486db32265bSvisa 487db32265bSvisa /* Check that there is a protective MBR. */ 488db32265bSvisa len = pread(devfd, secbuf, dl->d_secsize, 0); 489db32265bSvisa if (len != dl->d_secsize) 490db32265bSvisa err(4, "can't read mbr"); 491db32265bSvisa memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp)); 492db32265bSvisa if (gpt_chk_mbr(dp, DL_GETDSIZE(dl))) { 493db32265bSvisa free(secbuf); 494db32265bSvisa return (-1); 495db32265bSvisa } 496db32265bSvisa 497db32265bSvisa /* Check GPT Header. */ 498db32265bSvisa off = dl->d_secsize; /* Read header from sector 1. */ 499db32265bSvisa len = pread(devfd, secbuf, dl->d_secsize, off); 500db32265bSvisa if (len != dl->d_secsize) 501db32265bSvisa err(4, "can't pread gpt header"); 502db32265bSvisa 503db32265bSvisa memcpy(&gh, secbuf, sizeof(gh)); 504db32265bSvisa free(secbuf); 505db32265bSvisa 506db32265bSvisa /* Check signature */ 507db32265bSvisa if (letoh64(gh.gh_sig) != GPTSIGNATURE) 508db32265bSvisa return (-1); 509db32265bSvisa 510db32265bSvisa if (letoh32(gh.gh_rev) != GPTREVISION) 511db32265bSvisa return (-1); 512db32265bSvisa 513db32265bSvisa ghsize = letoh32(gh.gh_size); 514db32265bSvisa if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) 515db32265bSvisa return (-1); 516db32265bSvisa 517db32265bSvisa /* Check checksum */ 518db32265bSvisa orig_csum = gh.gh_csum; 519db32265bSvisa gh.gh_csum = 0; 520db32265bSvisa new_csum = crc32((unsigned char *)&gh, ghsize); 521db32265bSvisa gh.gh_csum = orig_csum; 522db32265bSvisa if (letoh32(orig_csum) != new_csum) 523db32265bSvisa return (-1); 524db32265bSvisa 525db32265bSvisa off = letoh64(gh.gh_part_lba) * dl->d_secsize; 526db32265bSvisa ghpartsize = letoh32(gh.gh_part_size); 527db32265bSvisa ghpartspersec = dl->d_secsize / ghpartsize; 528db32265bSvisa ghpartnum = letoh32(gh.gh_part_num); 529db32265bSvisa if ((secbuf = malloc(dl->d_secsize)) == NULL) 530db32265bSvisa err(1, NULL); 531db32265bSvisa for (i = 0; i < (ghpartnum + ghpartspersec - 1) / ghpartspersec; i++) { 532db32265bSvisa len = pread(devfd, secbuf, dl->d_secsize, off); 533db32265bSvisa if (len != dl->d_secsize) { 534db32265bSvisa free(secbuf); 535db32265bSvisa return (-1); 536db32265bSvisa } 537db32265bSvisa memcpy(gp + i * ghpartspersec, secbuf, 538db32265bSvisa ghpartspersec * sizeof(struct gpt_partition)); 539db32265bSvisa off += dl->d_secsize; 540db32265bSvisa } 541db32265bSvisa free(secbuf); 542db32265bSvisa new_csum = crc32((unsigned char *)&gp, ghpartnum * ghpartsize); 543db32265bSvisa if (new_csum != letoh32(gh.gh_part_csum)) 544db32265bSvisa return (-1); 545db32265bSvisa 546db32265bSvisa start = 0; 547db32265bSvisa for (i = 0; i < ghpartnum && start == 0; i++) { 548db32265bSvisa if (memcmp(&gp[i].gp_type, &efisys_uuid, 549db32265bSvisa sizeof(struct uuid)) == 0) 550db32265bSvisa start = letoh64(gp[i].gp_lba_start); 551db32265bSvisa } 552db32265bSvisa 553db32265bSvisa if (start) { 554db32265bSvisa for (i = 0; i < MAXPARTITIONS; i++) { 555db32265bSvisa if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 && 556db32265bSvisa DL_GETPOFFSET(&dl->d_partitions[i]) == start) 557db32265bSvisa return ('a' + i); 558db32265bSvisa } 559db32265bSvisa } 560db32265bSvisa 561db32265bSvisa return (-1); 562db32265bSvisa } 563db32265bSvisa 564db32265bSvisa int 565db32265bSvisa findmbrfat(int devfd, struct disklabel *dl) 566db32265bSvisa { 567db32265bSvisa struct dos_partition dp[NDOSPART]; 568db32265bSvisa ssize_t len; 569db32265bSvisa u_int64_t start = 0; 570db32265bSvisa int i; 571db32265bSvisa u_int8_t *secbuf; 572db32265bSvisa 573db32265bSvisa if ((secbuf = malloc(dl->d_secsize)) == NULL) 574db32265bSvisa err(1, NULL); 575db32265bSvisa 576db32265bSvisa /* Read MBR. */ 577db32265bSvisa len = pread(devfd, secbuf, dl->d_secsize, 0); 578db32265bSvisa if (len != dl->d_secsize) 579db32265bSvisa err(4, "can't read mbr"); 580db32265bSvisa memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp)); 581db32265bSvisa 582db32265bSvisa for (i = 0; i < NDOSPART; i++) { 583db32265bSvisa if (dp[i].dp_typ == DOSPTYP_UNUSED) 584db32265bSvisa continue; 585db32265bSvisa if (dp[i].dp_typ == DOSPTYP_FAT16L || 586db32265bSvisa dp[i].dp_typ == DOSPTYP_FAT32L || 587db32265bSvisa dp[i].dp_typ == DOSPTYP_EFISYS) 588db32265bSvisa start = dp[i].dp_start; 589db32265bSvisa } 590db32265bSvisa 591db32265bSvisa free(secbuf); 592db32265bSvisa 593db32265bSvisa if (start) { 594db32265bSvisa for (i = 0; i < MAXPARTITIONS; i++) { 595db32265bSvisa if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 && 596db32265bSvisa DL_GETPOFFSET(&dl->d_partitions[i]) == start) 597db32265bSvisa return ('a' + i); 598db32265bSvisa } 599db32265bSvisa } 600db32265bSvisa 601db32265bSvisa return (-1); 602db32265bSvisa } 603