1 1.22 manu /* $NetBSD: boot1.c,v 1.22 2023/06/29 14:18:58 manu Exp $ */ 2 1.1 dsl 3 1.1 dsl /*- 4 1.1 dsl * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 1.1 dsl * All rights reserved. 6 1.1 dsl * 7 1.1 dsl * This code is derived from software contributed to The NetBSD Foundation 8 1.1 dsl * by David Laight. 9 1.1 dsl * 10 1.1 dsl * Redistribution and use in source and binary forms, with or without 11 1.1 dsl * modification, are permitted provided that the following conditions 12 1.1 dsl * are met: 13 1.1 dsl * 1. Redistributions of source code must retain the above copyright 14 1.1 dsl * notice, this list of conditions and the following disclaimer. 15 1.1 dsl * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 dsl * notice, this list of conditions and the following disclaimer in the 17 1.1 dsl * documentation and/or other materials provided with the distribution. 18 1.1 dsl * 19 1.1 dsl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 dsl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 dsl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 dsl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 dsl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 dsl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 dsl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 dsl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 dsl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 dsl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 dsl * POSSIBILITY OF SUCH DAMAGE. 30 1.1 dsl */ 31 1.1 dsl 32 1.1 dsl #include <sys/cdefs.h> 33 1.22 manu __RCSID("$NetBSD: boot1.c,v 1.22 2023/06/29 14:18:58 manu Exp $"); 34 1.1 dsl 35 1.1 dsl #include <lib/libsa/stand.h> 36 1.1 dsl #include <lib/libkern/libkern.h> 37 1.1 dsl #include <biosdisk_ll.h> 38 1.1 dsl 39 1.1 dsl #include <sys/param.h> 40 1.22 manu #include <sys/uuid.h> 41 1.1 dsl #include <sys/bootblock.h> 42 1.5 dsl #include <sys/disklabel.h> 43 1.22 manu #include <sys/disklabel_gpt.h> 44 1.3 dsl #include <dev/raidframe/raidframevar.h> /* For RF_PROTECTED_SECTORS */ 45 1.1 dsl 46 1.2 dsl #define XSTR(x) #x 47 1.2 dsl #define STR(x) XSTR(x) 48 1.2 dsl 49 1.20 jakllsch static daddr_t bios_sector; 50 1.1 dsl 51 1.6 dsl static struct biosdisk_ll d; 52 1.1 dsl 53 1.20 jakllsch const char *boot1(uint32_t, uint64_t *); 54 1.22 manu #ifndef NO_GPT 55 1.22 manu static daddr_t gpt_lookup(daddr_t); 56 1.22 manu #endif 57 1.1 dsl extern void putstr(const char *); 58 1.1 dsl 59 1.5 dsl extern struct disklabel ptn_disklabel; 60 1.5 dsl 61 1.10 christos static int 62 1.10 christos ob(void) 63 1.10 christos { 64 1.10 christos return open("boot", 0); 65 1.10 christos } 66 1.10 christos 67 1.1 dsl const char * 68 1.20 jakllsch boot1(uint32_t biosdev, uint64_t *sector) 69 1.1 dsl { 70 1.18 dsl struct stat sb; 71 1.1 dsl int fd; 72 1.1 dsl 73 1.6 dsl bios_sector = *sector; 74 1.1 dsl d.dev = biosdev; 75 1.1 dsl 76 1.18 dsl putstr("\r\nNetBSD/x86 " STR(FS) " Primary Bootstrap\r\n"); 77 1.1 dsl 78 1.1 dsl if (set_geometry(&d, NULL)) 79 1.1 dsl return "set_geometry\r\n"; 80 1.1 dsl 81 1.10 christos /* 82 1.10 christos * We default to the filesystem at the start of the 83 1.10 christos * MBR partition 84 1.10 christos */ 85 1.10 christos fd = ob(); 86 1.10 christos if (fd != -1) 87 1.12 oster goto done; 88 1.10 christos /* 89 1.10 christos * Maybe the filesystem is enclosed in a raid set. 90 1.10 christos * add in size of raidframe header and try again. 91 1.10 christos * (Maybe this should only be done if the filesystem 92 1.10 christos * magic number is absent.) 93 1.10 christos */ 94 1.10 christos bios_sector += RF_PROTECTED_SECTORS; 95 1.10 christos fd = ob(); 96 1.10 christos if (fd != -1) 97 1.12 oster goto done; 98 1.22 manu 99 1.22 manu #ifndef NO_GPT 100 1.22 manu /* 101 1.22 manu * Test for a GPT inside the RAID 102 1.22 manu */ 103 1.22 manu bios_sector += gpt_lookup(bios_sector); 104 1.22 manu fd = ob(); 105 1.22 manu if (fd != -1) 106 1.22 manu goto done; 107 1.22 manu #endif 108 1.22 manu 109 1.10 christos /* 110 1.10 christos * Nothing at the start of the MBR partition, fallback on 111 1.10 christos * partition 'a' from the disklabel in this MBR partition. 112 1.10 christos */ 113 1.11 christos if (ptn_disklabel.d_magic != DISKMAGIC || 114 1.11 christos ptn_disklabel.d_magic2 != DISKMAGIC || 115 1.11 christos ptn_disklabel.d_partitions[0].p_fstype == FS_UNUSED) 116 1.12 oster goto done; 117 1.10 christos bios_sector = ptn_disklabel.d_partitions[0].p_offset; 118 1.10 christos *sector = bios_sector; 119 1.10 christos if (ptn_disklabel.d_partitions[0].p_fstype == FS_RAID) 120 1.5 dsl bios_sector += RF_PROTECTED_SECTORS; 121 1.5 dsl 122 1.10 christos fd = ob(); 123 1.10 christos 124 1.12 oster done: 125 1.19 christos if (fd == -1 || fstat(fd, &sb) == -1) 126 1.11 christos return "Can't open /boot\r\n"; 127 1.1 dsl 128 1.11 christos biosdev = (uint32_t)sb.st_size; 129 1.1 dsl #if 0 130 1.11 christos if (biosdev > SECONDARY_MAX_LOAD) 131 1.11 christos return "/boot too large\r\n"; 132 1.1 dsl #endif 133 1.1 dsl 134 1.11 christos if (read(fd, (void *)SECONDARY_LOAD_ADDRESS, biosdev) != biosdev) 135 1.11 christos return "/boot load failed\r\n"; 136 1.1 dsl 137 1.1 dsl if (*(uint32_t *)(SECONDARY_LOAD_ADDRESS + 4) != X86_BOOT_MAGIC_2) 138 1.11 christos return "Invalid /boot file format\r\n"; 139 1.1 dsl 140 1.1 dsl /* We need to jump to the secondary bootstrap in realmode */ 141 1.1 dsl return 0; 142 1.1 dsl } 143 1.1 dsl 144 1.1 dsl int 145 1.1 dsl blkdevstrategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize) 146 1.1 dsl { 147 1.1 dsl if (flag != F_READ) 148 1.1 dsl return EROFS; 149 1.1 dsl 150 1.8 junyoung if (size & (BIOSDISK_DEFAULT_SECSIZE - 1)) 151 1.1 dsl return EINVAL; 152 1.1 dsl 153 1.1 dsl if (rsize) 154 1.1 dsl *rsize = size; 155 1.1 dsl 156 1.1 dsl if (size != 0 && readsects(&d, bios_sector + dblk, 157 1.8 junyoung size / BIOSDISK_DEFAULT_SECSIZE, 158 1.8 junyoung buf, 1) != 0) 159 1.1 dsl return EIO; 160 1.1 dsl 161 1.1 dsl return 0; 162 1.1 dsl } 163 1.22 manu 164 1.22 manu #ifndef NO_GPT 165 1.22 manu static int 166 1.22 manu is_unused(struct gpt_ent *ent) 167 1.22 manu { 168 1.22 manu const struct uuid unused = GPT_ENT_TYPE_UNUSED; 169 1.22 manu 170 1.22 manu return (memcmp(ent->ent_type, &unused, sizeof(unused)) == 0); 171 1.22 manu } 172 1.22 manu 173 1.22 manu static int 174 1.22 manu is_bootable(struct gpt_ent *ent) 175 1.22 manu { 176 1.22 manu /* GPT_ENT_TYPE_NETBSD_RAID omitted as we are already in a RAID */ 177 1.22 manu const struct uuid bootable[] = { 178 1.22 manu GPT_ENT_TYPE_NETBSD_FFS, 179 1.22 manu GPT_ENT_TYPE_NETBSD_LFS, 180 1.22 manu GPT_ENT_TYPE_NETBSD_CCD, 181 1.22 manu GPT_ENT_TYPE_NETBSD_CGD, 182 1.22 manu }; 183 1.22 manu int i; 184 1.22 manu 185 1.22 manu for (i = 0; i < sizeof(bootable) / sizeof(*bootable); i++) { 186 1.22 manu if (memcmp(ent->ent_type, &bootable[i], 187 1.22 manu sizeof(struct uuid)) == 0) 188 1.22 manu return 1; 189 1.22 manu } 190 1.22 manu 191 1.22 manu return 0; 192 1.22 manu } 193 1.22 manu 194 1.22 manu static daddr_t 195 1.22 manu gpt_lookup(daddr_t sector) 196 1.22 manu { 197 1.22 manu char buf[BIOSDISK_DEFAULT_SECSIZE]; 198 1.22 manu struct mbr_sector *pmbr; 199 1.22 manu const char gpt_hdr_sig[] = GPT_HDR_SIG; 200 1.22 manu struct gpt_hdr *hdr; 201 1.22 manu struct gpt_ent *ent; 202 1.22 manu uint32_t nents; 203 1.22 manu uint32_t entsz; 204 1.22 manu uint32_t entries_per_sector; 205 1.22 manu uint32_t sectors_per_entry; 206 1.22 manu uint64_t firstpart_lba = 0; 207 1.22 manu uint64_t bootable_lba = 0; 208 1.22 manu uint64_t bootme_lba = 0; 209 1.22 manu int i, j; 210 1.22 manu 211 1.22 manu /* 212 1.22 manu * Look for a PMBR 213 1.22 manu */ 214 1.22 manu if (readsects(&d, sector, 1, buf, 1) != 0) 215 1.22 manu return 0; 216 1.22 manu 217 1.22 manu pmbr = (struct mbr_sector *)buf; 218 1.22 manu 219 1.22 manu if (pmbr->mbr_magic != htole16(MBR_MAGIC)) 220 1.22 manu return 0; 221 1.22 manu 222 1.22 manu if (pmbr->mbr_parts[0].mbrp_type != MBR_PTYPE_PMBR) 223 1.22 manu return 0; 224 1.22 manu 225 1.22 manu sector++; /* skip PMBR */ 226 1.22 manu 227 1.22 manu /* 228 1.22 manu * Look for a GPT header 229 1.22 manu * Space is scarce, we do not check CRC. 230 1.22 manu */ 231 1.22 manu if (readsects(&d, sector, 1, buf, 1) != 0) 232 1.22 manu return 0; 233 1.22 manu 234 1.22 manu hdr = (struct gpt_hdr *)buf; 235 1.22 manu 236 1.22 manu if (memcmp(gpt_hdr_sig, hdr->hdr_sig, sizeof(hdr->hdr_sig)) != 0) 237 1.22 manu return 0; 238 1.22 manu 239 1.22 manu if (hdr->hdr_revision != htole32(GPT_HDR_REVISION)) 240 1.22 manu return 0; 241 1.22 manu 242 1.22 manu if (le32toh(hdr->hdr_size) > BIOSDISK_DEFAULT_SECSIZE) 243 1.22 manu return 0; 244 1.22 manu 245 1.22 manu nents = le32toh(hdr->hdr_entries); 246 1.22 manu entsz = le32toh(hdr->hdr_entsz); 247 1.22 manu 248 1.22 manu sector++; /* skip GPT header */ 249 1.22 manu 250 1.22 manu /* 251 1.22 manu * Read partition table 252 1.22 manu * 253 1.22 manu * According to UEFI specification section 5.3.2, entries 254 1.22 manu * are 128 * (2^n) bytes long. The most common scenario is 255 1.22 manu * 128 bytes (n = 0) where there are 4 entries per sector. 256 1.22 manu * If n > 2, then entries spans multiple sectors, but they 257 1.22 manu * remain sector-aligned. 258 1.22 manu */ 259 1.22 manu entries_per_sector = BIOSDISK_DEFAULT_SECSIZE / entsz; 260 1.22 manu if (entries_per_sector == 0) 261 1.22 manu entries_per_sector = 1; 262 1.22 manu 263 1.22 manu sectors_per_entry = entsz / BIOSDISK_DEFAULT_SECSIZE; 264 1.22 manu if (sectors_per_entry == 0) 265 1.22 manu sectors_per_entry = 1; 266 1.22 manu 267 1.22 manu for (i = 0; i < nents; i += entries_per_sector) { 268 1.22 manu if (readsects(&d, sector, 1, buf, 1) != 0) 269 1.22 manu return 0; 270 1.22 manu 271 1.22 manu sector += sectors_per_entry; 272 1.22 manu 273 1.22 manu for (j = 0; j < entries_per_sector; j++) { 274 1.22 manu ent = (struct gpt_ent *)&buf[j * entsz]; 275 1.22 manu 276 1.22 manu if (is_unused(ent)) 277 1.22 manu continue; 278 1.22 manu 279 1.22 manu /* First bootme wins, we can stop there */ 280 1.22 manu if (ent->ent_attr & GPT_ENT_ATTR_BOOTME) { 281 1.22 manu bootme_lba = le64toh(ent->ent_lba_start); 282 1.22 manu goto out; 283 1.22 manu } 284 1.22 manu 285 1.22 manu if (firstpart_lba == 0) 286 1.22 manu firstpart_lba = le64toh(ent->ent_lba_start); 287 1.22 manu 288 1.22 manu if (is_bootable(ent) && bootable_lba == 0) 289 1.22 manu bootable_lba = le64toh(ent->ent_lba_start); 290 1.22 manu } 291 1.22 manu } 292 1.22 manu 293 1.22 manu out: 294 1.22 manu if (bootme_lba) 295 1.22 manu return bootme_lba; 296 1.22 manu 297 1.22 manu if (bootable_lba) 298 1.22 manu return bootable_lba; 299 1.22 manu 300 1.22 manu if (firstpart_lba) 301 1.22 manu return firstpart_lba; 302 1.22 manu 303 1.22 manu return 0; 304 1.22 manu } 305 1.22 manu #endif /* ! NO_GPT */ 306