Home | History | Annotate | Line # | Download | only in bootxx
      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