Module Name: src Committed By: martin Date: Fri Jun 30 17:22:17 UTC 2023
Modified Files: src/sys/arch/i386/stand/bootxx [netbsd-9]: boot1.c Log Message: Pull up following revision(s) (requested by manu in ticket #1658): sys/arch/i386/stand/bootxx/boot1.c: revision 1.22 Primary bootstrap is now able to read a GPT inside RAIDframe. Previously, primary bootstrap was able to boot on RAID-1 RAIDframe set with the limitation that the FFS filesystem had to start at bloc 0 in the RAID. That allowed inner RAID partitionning with a disklabel, but not with a GPT. When booting on a RAID-1 RAIDframe, primary bootstrap now first try a filesystem at bloc 0 of the RAID as before. On failure, it tries to read a GPT and load secondary bootstrap from, by priority; 1) the first partition with the bootme attribute set 2) the first partition of type FFS, LFS, CCD or CGD 3) the first partition present in the GPT To generate a diff of this commit: cvs rdiff -u -r1.20 -r1.20.64.1 src/sys/arch/i386/stand/bootxx/boot1.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/i386/stand/bootxx/boot1.c diff -u src/sys/arch/i386/stand/bootxx/boot1.c:1.20 src/sys/arch/i386/stand/bootxx/boot1.c:1.20.64.1 --- src/sys/arch/i386/stand/bootxx/boot1.c:1.20 Thu Jan 6 01:08:48 2011 +++ src/sys/arch/i386/stand/bootxx/boot1.c Fri Jun 30 17:22:17 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: boot1.c,v 1.20 2011/01/06 01:08:48 jakllsch Exp $ */ +/* $NetBSD: boot1.c,v 1.20.64.1 2023/06/30 17:22:17 martin Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -30,15 +30,17 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: boot1.c,v 1.20 2011/01/06 01:08:48 jakllsch Exp $"); +__RCSID("$NetBSD: boot1.c,v 1.20.64.1 2023/06/30 17:22:17 martin Exp $"); #include <lib/libsa/stand.h> #include <lib/libkern/libkern.h> #include <biosdisk_ll.h> #include <sys/param.h> +#include <sys/uuid.h> #include <sys/bootblock.h> #include <sys/disklabel.h> +#include <sys/disklabel_gpt.h> #include <dev/raidframe/raidframevar.h> /* For RF_PROTECTED_SECTORS */ #define XSTR(x) #x @@ -49,6 +51,9 @@ static daddr_t bios_sector; static struct biosdisk_ll d; const char *boot1(uint32_t, uint64_t *); +#ifndef NO_GPT +static daddr_t gpt_lookup(daddr_t); +#endif extern void putstr(const char *); extern struct disklabel ptn_disklabel; @@ -90,6 +95,17 @@ boot1(uint32_t biosdev, uint64_t *sector fd = ob(); if (fd != -1) goto done; + +#ifndef NO_GPT + /* + * Test for a GPT inside the RAID + */ + bios_sector += gpt_lookup(bios_sector); + fd = ob(); + if (fd != -1) + goto done; +#endif + /* * Nothing at the start of the MBR partition, fallback on * partition 'a' from the disklabel in this MBR partition. @@ -145,3 +161,146 @@ blkdevstrategy(void *devdata, int flag, return 0; } + +#ifndef NO_GPT +static int +is_unused(struct gpt_ent *ent) +{ + const struct uuid unused = GPT_ENT_TYPE_UNUSED; + + return (memcmp(ent->ent_type, &unused, sizeof(unused)) == 0); +} + +static int +is_bootable(struct gpt_ent *ent) +{ + /* GPT_ENT_TYPE_NETBSD_RAID omitted as we are already in a RAID */ + const struct uuid bootable[] = { + GPT_ENT_TYPE_NETBSD_FFS, + GPT_ENT_TYPE_NETBSD_LFS, + GPT_ENT_TYPE_NETBSD_CCD, + GPT_ENT_TYPE_NETBSD_CGD, + }; + int i; + + for (i = 0; i < sizeof(bootable) / sizeof(*bootable); i++) { + if (memcmp(ent->ent_type, &bootable[i], + sizeof(struct uuid)) == 0) + return 1; + } + + return 0; +} + +static daddr_t +gpt_lookup(daddr_t sector) +{ + char buf[BIOSDISK_DEFAULT_SECSIZE]; + struct mbr_sector *pmbr; + const char gpt_hdr_sig[] = GPT_HDR_SIG; + struct gpt_hdr *hdr; + struct gpt_ent *ent; + uint32_t nents; + uint32_t entsz; + uint32_t entries_per_sector; + uint32_t sectors_per_entry; + uint64_t firstpart_lba = 0; + uint64_t bootable_lba = 0; + uint64_t bootme_lba = 0; + int i, j; + + /* + * Look for a PMBR + */ + if (readsects(&d, sector, 1, buf, 1) != 0) + return 0; + + pmbr = (struct mbr_sector *)buf; + + if (pmbr->mbr_magic != htole16(MBR_MAGIC)) + return 0; + + if (pmbr->mbr_parts[0].mbrp_type != MBR_PTYPE_PMBR) + return 0; + + sector++; /* skip PMBR */ + + /* + * Look for a GPT header + * Space is scarce, we do not check CRC. + */ + if (readsects(&d, sector, 1, buf, 1) != 0) + return 0; + + hdr = (struct gpt_hdr *)buf; + + if (memcmp(gpt_hdr_sig, hdr->hdr_sig, sizeof(hdr->hdr_sig)) != 0) + return 0; + + if (hdr->hdr_revision != htole32(GPT_HDR_REVISION)) + return 0; + + if (le32toh(hdr->hdr_size) > BIOSDISK_DEFAULT_SECSIZE) + return 0; + + nents = le32toh(hdr->hdr_entries); + entsz = le32toh(hdr->hdr_entsz); + + sector++; /* skip GPT header */ + + /* + * Read partition table + * + * According to UEFI specification section 5.3.2, entries + * are 128 * (2^n) bytes long. The most common scenario is + * 128 bytes (n = 0) where there are 4 entries per sector. + * If n > 2, then entries spans multiple sectors, but they + * remain sector-aligned. + */ + entries_per_sector = BIOSDISK_DEFAULT_SECSIZE / entsz; + if (entries_per_sector == 0) + entries_per_sector = 1; + + sectors_per_entry = entsz / BIOSDISK_DEFAULT_SECSIZE; + if (sectors_per_entry == 0) + sectors_per_entry = 1; + + for (i = 0; i < nents; i += entries_per_sector) { + if (readsects(&d, sector, 1, buf, 1) != 0) + return 0; + + sector += sectors_per_entry; + + for (j = 0; j < entries_per_sector; j++) { + ent = (struct gpt_ent *)&buf[j * entsz]; + + if (is_unused(ent)) + continue; + + /* First bootme wins, we can stop there */ + if (ent->ent_attr & GPT_ENT_ATTR_BOOTME) { + bootme_lba = le64toh(ent->ent_lba_start); + goto out; + } + + if (firstpart_lba == 0) + firstpart_lba = le64toh(ent->ent_lba_start); + + if (is_bootable(ent) && bootable_lba == 0) + bootable_lba = le64toh(ent->ent_lba_start); + } + } + +out: + if (bootme_lba) + return bootme_lba; + + if (bootable_lba) + return bootable_lba; + + if (firstpart_lba) + return firstpart_lba; + + return 0; +} +#endif /* ! NO_GPT */