1 /* $NetBSD: mbr.c,v 1.5 2016/03/30 21:14:54 christos 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/libsa/byteorder.h> 38 #include <lib/libsa/stand.h> 39 40 #include "mbr.h" 41 42 static int find_mbr_part(struct of_dev *, uint32_t, char *, 43 struct disklabel *, uint32_t, uint8_t, int); 44 static void make_dos_label(struct disklabel *, uint32_t); 45 46 /* 47 * Find a valid MBR disklabel. 48 */ 49 int 50 search_mbr_label(struct of_dev *devp, u_long off, char *buf, 51 struct disklabel *lp, u_long off0) 52 { 53 static uint8_t fat_types[] = { 54 MBR_PTYPE_FAT12, MBR_PTYPE_FAT16S, MBR_PTYPE_FAT16B, 55 MBR_PTYPE_FAT32, MBR_PTYPE_FAT32L, MBR_PTYPE_FAT16L 56 }; 57 size_t read; 58 uint32_t poff; 59 int i; 60 61 /* Find a disklabel in a NetBSD or 386BSD partition. */ 62 poff = find_mbr_part(devp, off, buf, lp, 0, MBR_PTYPE_NETBSD, 0); 63 #ifdef COMPAT_386BSD_MBRPART 64 if (poff == 0) { 65 poff = find_mbr_part(devp, off, buf, lp, 0, 66 MBR_PTYPE_386BSD, 0); 67 if (poff != 0) 68 printf("WARNING: old BSD partition ID!\n"); 69 } 70 #endif 71 if (poff != 0) { 72 if (strategy(devp, F_READ, poff + LABELSECTOR, DEV_BSIZE, 73 buf, &read) == 0 && read == DEV_BSIZE) 74 if (getdisklabel(buf, lp) == NULL) 75 return 0; 76 } 77 78 /* 79 * No BSD partition with a valid disklabel found, so try to 80 * construct a label from a DOS partition. 81 */ 82 for (i = 0; i < sizeof(fat_types); i++) { 83 poff = find_mbr_part(devp, off, buf, lp, 0, fat_types[i], 0); 84 if (poff != 0) { 85 make_dos_label(lp, poff); 86 return 0; 87 } 88 } 89 90 return ERDLAB; 91 } 92 93 static int 94 find_mbr_part(struct of_dev *devp, uint32_t off, char *buf, 95 struct disklabel *lp, uint32_t off0, uint8_t ptype, int recursion) 96 { 97 size_t read; 98 struct mbr_partition *p; 99 int i; 100 uint32_t poff; 101 102 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 103 || read != DEV_BSIZE) 104 return 0; 105 106 if (*(uint16_t *)&buf[MBR_MAGIC_OFFSET] != sa_htole16(MBR_MAGIC)) 107 return 0; 108 109 if (recursion++ <= 1) 110 off0 += off; 111 112 for (p = (struct mbr_partition *)(buf + MBR_PART_OFFSET), i = 0; 113 i < MBR_PART_COUNT; i++, p++) { 114 if (p->mbrp_type == ptype) { 115 recursion--; 116 return sa_le32toh(p->mbrp_start) + off0; 117 } 118 else if (p->mbrp_type == MBR_PTYPE_EXT) { 119 poff = find_mbr_part(devp, sa_le32toh(p->mbrp_start), 120 buf, lp, off0, ptype, recursion); 121 if (poff != 0) { 122 recursion--; 123 return poff; 124 } 125 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 126 || read != DEV_BSIZE) { 127 recursion--; 128 return 0; 129 } 130 } 131 } 132 133 return 0; 134 } 135 136 static void 137 make_dos_label(struct disklabel *lp, uint32_t poff) 138 { 139 int i; 140 141 /* clear all partitions */ 142 lp->d_npartitions = RAW_PART + 1; 143 for (i = 0; i < MAXPARTITIONS; i++) { 144 lp->d_partitions[i].p_size = 0; 145 lp->d_partitions[i].p_offset = 0; 146 lp->d_partitions[i].p_fstype = 0; 147 } 148 149 /* set DOS partition as root partition */ 150 lp->d_partitions[0].p_offset = poff; 151 lp->d_partitions[0].p_fstype = FS_MSDOS; 152 153 /* disklabel is valid */ 154 lp->d_magic = lp->d_magic2 = DISKMAGIC; 155 lp->d_checksum = 0; 156 lp->d_checksum = dkcksum(lp); 157 } 158