1/* $NetBSD: mbr.c,v 1.6 2021/05/17 20:21:05 mrg Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#include <sys/param.h> 35#include <sys/bootblock.h> 36 37#include <lib/libkern/libkern.h> 38#include <lib/libsa/byteorder.h> 39#include <lib/libsa/stand.h> 40 41#include "mbr.h" 42 43static int find_mbr_part(struct of_dev *, uint32_t, char *, 44 struct disklabel *, uint32_t, uint8_t, int); 45static void make_dos_label(struct disklabel *, uint32_t); 46 47/* 48 * Find a valid MBR disklabel. 49 */ 50int 51search_mbr_label(struct of_dev *devp, u_long off, char *buf, 52 struct disklabel *lp, u_long off0) 53{ 54 static uint8_t fat_types[] = { 55 MBR_PTYPE_FAT12, MBR_PTYPE_FAT16S, MBR_PTYPE_FAT16B, 56 MBR_PTYPE_FAT32, MBR_PTYPE_FAT32L, MBR_PTYPE_FAT16L 57 }; 58 size_t read; 59 uint32_t poff; 60 int i; 61 62 /* Find a disklabel in a NetBSD or 386BSD partition. */ 63 poff = find_mbr_part(devp, off, buf, lp, 0, MBR_PTYPE_NETBSD, 0); 64#ifdef COMPAT_386BSD_MBRPART 65 if (poff == 0) { 66 poff = find_mbr_part(devp, off, buf, lp, 0, 67 MBR_PTYPE_386BSD, 0); 68 if (poff != 0) 69 printf("WARNING: old BSD partition ID!\n"); 70 } 71#endif 72 if (poff != 0) { 73 if (strategy(devp, F_READ, poff + LABELSECTOR, DEV_BSIZE, 74 buf, &read) == 0 && read == DEV_BSIZE) 75 if (getdisklabel(buf, lp) == NULL) 76 return 0; 77 } 78 79 /* 80 * No BSD partition with a valid disklabel found, so try to 81 * construct a label from a DOS partition. 82 */ 83 for (i = 0; i < sizeof(fat_types); i++) { 84 poff = find_mbr_part(devp, off, buf, lp, 0, fat_types[i], 0); 85 if (poff != 0) { 86 make_dos_label(lp, poff); 87 return 0; 88 } 89 } 90 91 return ERDLAB; 92} 93 94static int 95find_mbr_part(struct of_dev *devp, uint32_t off, char *buf, 96 struct disklabel *lp, uint32_t off0, uint8_t ptype, int recursion) 97{ 98 size_t read; 99 struct mbr_partition *p; 100 int i; 101 uint32_t poff; 102 103 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 104 || read != DEV_BSIZE) 105 return 0; 106 107 if (*(uint16_t *)&buf[MBR_MAGIC_OFFSET] != sa_htole16(MBR_MAGIC)) 108 return 0; 109 110 if (recursion++ <= 1) 111 off0 += off; 112 113 for (p = (struct mbr_partition *)(buf + MBR_PART_OFFSET), i = 0; 114 i < MBR_PART_COUNT; i++, p++) { 115 if (p->mbrp_type == ptype) { 116 recursion--; 117 return sa_le32toh(p->mbrp_start) + off0; 118 } 119 else if (p->mbrp_type == MBR_PTYPE_EXT) { 120 poff = find_mbr_part(devp, sa_le32toh(p->mbrp_start), 121 buf, lp, off0, ptype, recursion); 122 if (poff != 0) { 123 recursion--; 124 return poff; 125 } 126 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 127 || read != DEV_BSIZE) { 128 recursion--; 129 return 0; 130 } 131 } 132 } 133 134 return 0; 135} 136 137static void 138make_dos_label(struct disklabel *lp, uint32_t poff) 139{ 140 int i; 141 142 /* clear all partitions */ 143 lp->d_npartitions = RAW_PART + 1; 144 for (i = 0; i < MAXPARTITIONS; i++) { 145 lp->d_partitions[i].p_size = 0; 146 lp->d_partitions[i].p_offset = 0; 147 lp->d_partitions[i].p_fstype = 0; 148 } 149 150 /* set DOS partition as root partition */ 151 lp->d_partitions[0].p_offset = poff; 152 lp->d_partitions[0].p_fstype = FS_MSDOS; 153 154 /* disklabel is valid */ 155 lp->d_magic = lp->d_magic2 = DISKMAGIC; 156 lp->d_checksum = 0; 157 lp->d_checksum = dkcksum(lp); 158} 159