1 /* $NetBSD: disksubr_mbr.c,v 1.18 2013/08/13 00:04:08 matt Exp $ */ 2 3 /* 4 * Copyright (c) 1998 Christopher G. Demetriou. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Christopher G. Demetriou 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 62 */ 63 64 /* 65 * From i386 disklabel.c rev 1.29, with cleanups and modifications to 66 * make it easier to use on the arm32 and to use as MI code (not quite 67 * clean enough, yet). 68 */ 69 70 #include <sys/cdefs.h> 71 __KERNEL_RCSID(0, "$NetBSD: disksubr_mbr.c,v 1.18 2013/08/13 00:04:08 matt Exp $"); 72 73 #include <sys/param.h> 74 #include <sys/systm.h> 75 #include <sys/buf.h> 76 #include <sys/disklabel.h> 77 78 #include "opt_mbr.h" 79 80 #define MBRSIGOFS 0x1fe 81 static char mbrsig[2] = {0x55, 0xaa}; 82 83 int 84 mbr_label_read(dev_t dev, 85 void (*strat)(struct buf *), 86 struct disklabel *lp, 87 struct cpu_disklabel *osdep, 88 const char **msgp, 89 int *cylp, int *netbsd_label_offp) 90 { 91 struct mbr_partition *mbrp; 92 struct partition *pp; 93 int cyl, mbrpartoff, i; 94 struct buf *bp; 95 int rv = 1; 96 97 /* get a buffer and initialize it */ 98 bp = geteblk((int)lp->d_secsize); 99 bp->b_dev = dev; 100 101 /* In case nothing sets them */ 102 mbrpartoff = 0; 103 cyl = LABELSECTOR / lp->d_secpercyl; 104 105 mbrp = osdep->mbrparts; 106 107 /* read master boot record */ 108 bp->b_blkno = MBR_BBSECTOR; 109 bp->b_bcount = lp->d_secsize; 110 bp->b_flags |= B_READ; 111 bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl; 112 (*strat)(bp); 113 114 /* if successful, wander through dos partition table */ 115 if (biowait(bp)) { 116 *msgp = "dos partition I/O error"; 117 goto out; 118 } else { 119 struct mbr_partition *ourmbrp = NULL; 120 int nfound = 0; 121 122 /* XXX "there has to be a better check than this." */ 123 if (memcmp((char *)bp->b_data + MBRSIGOFS, mbrsig, 124 sizeof(mbrsig))) { 125 rv = 0; 126 goto out; 127 } 128 129 /* XXX how do we check veracity/bounds of this? */ 130 memcpy(mbrp, (char *)bp->b_data + MBR_PART_OFFSET, 131 MBR_PART_COUNT * sizeof(*mbrp)); 132 133 /* look for NetBSD partition */ 134 ourmbrp = NULL; 135 for (i = 0; !ourmbrp && i < MBR_PART_COUNT; i++) { 136 if (mbrp[i].mbrp_type == MBR_PTYPE_NETBSD) 137 ourmbrp = &mbrp[i]; 138 } 139 #ifdef COMPAT_386BSD_MBRPART 140 /* didn't find it -- look for 386BSD partition */ 141 for (i = 0; !ourmbrp && i < MBR_PART_COUNT; i++) { 142 if (mbrp[i].mbrp_type == MBR_PTYPE_386BSD) { 143 printf("WARNING: old BSD partition ID!\n"); 144 ourmbrp = &mbrp[i]; 145 break; 146 } 147 } 148 #endif 149 pp = &lp->d_partitions['e' - 'a']; 150 for (i = 0; i < MBR_PART_COUNT; i++, mbrp++, pp++) { 151 if ((i == 0 && mbrp->mbrp_type == MBR_PTYPE_PMBR) 152 || mbrp->mbrp_type == MBR_PTYPE_UNUSED) { 153 memset(pp, 0, sizeof(*pp)); 154 continue; 155 } 156 if (le32toh(mbrp->mbrp_start) + 157 le32toh(mbrp->mbrp_size) > lp->d_secperunit) { 158 /* This mbr doesn't look good.... */ 159 memset(pp, 0, sizeof(*pp)); 160 continue; 161 } 162 nfound++; 163 164 /* Install in partition e, f, g, or h. */ 165 pp->p_offset = le32toh(mbrp->mbrp_start); 166 pp->p_size = le32toh(mbrp->mbrp_size); 167 pp->p_fstype = xlat_mbr_fstype(mbrp->mbrp_type); 168 169 /* is this ours? */ 170 if (mbrp != ourmbrp) 171 continue; 172 173 /* need sector address for SCSI/IDE, 174 cylinder for ESDI/ST506/RLL */ 175 mbrpartoff = le32toh(mbrp->mbrp_start); 176 cyl = MBR_PCYL(mbrp->mbrp_scyl, mbrp->mbrp_ssect); 177 178 #ifdef __i386__ /* XXX? */ 179 /* update disklabel with details */ 180 lp->d_partitions[2].p_size = le32toh(mbrp->mbrp_size); 181 lp->d_partitions[2].p_offset = 182 le32toh(mbrp->mbrp_start); 183 lp->d_ntracks = mbrp->mbrp_ehd + 1; 184 lp->d_nsectors = MBR_PSECT(mbrp->mbrp_esect); 185 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 186 #endif 187 } 188 i += 'e' - 'a'; 189 if (nfound > 0) { 190 lp->d_npartitions = i; 191 strncpy(lp->d_packname, "fictitious-MBR", 192 sizeof lp->d_packname); 193 } 194 if (lp->d_npartitions < MAXPARTITIONS) { 195 memset(pp, 0, (MAXPARTITIONS - i) * sizeof(*pp)); 196 } 197 } 198 199 *cylp = cyl; 200 *netbsd_label_offp = mbrpartoff; 201 *msgp = NULL; 202 out: 203 brelse(bp, 0); 204 return (rv); 205 } 206 207 /* 208 * Return -1 not found, 0 found positive errno 209 */ 210 int 211 mbr_label_locate(dev_t dev, 212 void (*strat)(struct buf *), 213 struct disklabel *lp, 214 struct cpu_disklabel *osdep, 215 int *cylp, int *netbsd_label_offp) 216 { 217 struct mbr_partition *mbrp; 218 int cyl, mbrpartoff, i; 219 struct mbr_partition *ourmbrp = NULL; 220 struct buf *bp; 221 int rv; 222 223 /* get a buffer and initialize it */ 224 bp = geteblk((int)lp->d_secsize); 225 bp->b_dev = dev; 226 227 /* do MBR partitions in the process of getting disklabel? */ 228 mbrpartoff = 0; 229 cyl = LABELSECTOR / lp->d_secpercyl; 230 231 mbrp = osdep->mbrparts; 232 233 /* read master boot record */ 234 bp->b_blkno = MBR_BBSECTOR; 235 bp->b_bcount = lp->d_secsize; 236 bp->b_flags |= B_READ; 237 bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl; 238 (*strat)(bp); 239 240 if ((rv = biowait(bp)) != 0) { 241 goto out; 242 } 243 244 if (memcmp((char *)bp->b_data + MBRSIGOFS, mbrsig, sizeof(mbrsig))) { 245 rv = 0; 246 goto out; 247 } 248 249 /* XXX how do we check veracity/bounds of this? */ 250 memcpy(mbrp, (char *)bp->b_data + MBR_PART_OFFSET, 251 MBR_PART_COUNT * sizeof(*mbrp)); 252 253 /* look for NetBSD partition */ 254 ourmbrp = NULL; 255 for (i = 0; !ourmbrp && i < MBR_PART_COUNT; i++) { 256 if (mbrp[i].mbrp_type == MBR_PTYPE_NETBSD) 257 ourmbrp = &mbrp[i]; 258 } 259 #ifdef COMPAT_386BSD_MBRPART 260 /* didn't find it -- look for 386BSD partition */ 261 for (i = 0; !ourmbrp && i < MBR_PART_COUNT; i++) { 262 if (mbrp[i].mbrp_type == MBR_PTYPE_386BSD) { 263 printf("WARNING: old BSD partition ID!\n"); 264 ourmbrp = &mbrp[i]; 265 } 266 } 267 #endif 268 if (!ourmbrp) { 269 rv = 0; /* XXX allow easy clobber? */ 270 goto out; 271 } 272 273 /* need sector address for SCSI/IDE, cylinder for ESDI/ST506/RLL */ 274 mbrpartoff = le32toh(ourmbrp->mbrp_start); 275 cyl = MBR_PCYL(ourmbrp->mbrp_scyl, ourmbrp->mbrp_ssect); 276 277 *cylp = cyl; 278 *netbsd_label_offp = mbrpartoff; 279 rv = -1; 280 out: 281 brelse(bp, 0); 282 return (rv); 283 } 284