1 /* $NetBSD: dkwedge_bsdlabel.c,v 1.15 2008/04/28 20:23:48 martin Exp $ */
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Adapted from kern/subr_disk_mbr.c:
35 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
36 * All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
66 * 4.4BSD disklabel support for disk wedges
68 * Here is the basic search algorithm in use here:
70 * For historical reasons, we scan for x86-style MBR partitions looking
71 * for a MBR_PTYPE_NETBSD (or MBR_PTYPE_386BSD) partition. The first
72 * 4.4BSD disklabel found in the 2nd sector of such a partition is used.
73 * We assume that the 4.4BSD disklabel describes all partitions on the
74 * disk; we do not use any partition information from the MBR partition
77 * If that fails, then we fall back on a table of known locations for
81 #include <sys/cdefs.h>
82 __KERNEL_RCSID(0, "$NetBSD: dkwedge_bsdlabel.c,v 1.15 2008/04/28 20:23:48 martin Exp $");
84 #include <sys/param.h>
86 #include <sys/systm.h>
89 #include <sys/errno.h>
91 #include <sys/vnode.h>
92 #include <sys/malloc.h>
94 #include <sys/bootblock.h>
95 #include <sys/disklabel.h>
97 #define BSD44_MBR_LABELSECTOR 1
99 #define DISKLABEL_SIZE(x) \
100 (offsetof(struct disklabel, d_partitions) + \
101 (sizeof(struct partition) * (x)))
104 * Note the smallest MAXPARTITIONS was 8, so we allow a disklabel
105 * that size to be locted at the end of the sector.
107 #define DISKLABEL_MINSIZE DISKLABEL_SIZE(8)
110 * Table of known platform-specific disklabel locations.
112 static const struct disklabel_location
{
113 daddr_t label_sector
; /* sector containing label */
114 size_t label_offset
; /* byte offset of label in sector */
115 } disklabel_locations
[] = {
116 { 0, 0 }, /* mvme68k, next68k */
117 { 0, 64 }, /* algor, alpha, amiga, amigappc, evbmips, evbppc,
118 luna68k, mac68k, macppc, news68k, newsmips,
119 pc532, pdp11, pmax, vax, x68k */
120 { 0, 128 }, /* sparc, sun68k */
121 { 1, 0 }, /* amd64, arc, arm, bebox, cobalt, evbppc, hp700,
122 hpcarm, hpcmips, i386, ibmnws, mipsco, mvmeppc,
123 ofppc, pmppc, prep, sandpoint,
124 sbmips, sgimips, sh3 */
125 /* XXX atari is weird */
126 { 2, 0 }, /* cesfic, hp300 */
131 #define SCAN_CONTINUE 0
135 typedef struct mbr_args
{
143 bsdlabel_fstype_to_str(uint8_t fstype
)
148 case FS_UNUSED
: str
= DKW_PTYPE_UNUSED
; break;
149 case FS_SWAP
: str
= DKW_PTYPE_SWAP
; break;
150 case FS_BSDFFS
: str
= DKW_PTYPE_FFS
; break;
151 case FS_MSDOS
: str
= DKW_PTYPE_FAT
; break;
152 case FS_BSDLFS
: str
= DKW_PTYPE_LFS
; break;
153 case FS_ISO9660
: str
= DKW_PTYPE_ISO9660
; break;
154 case FS_ADOS
: str
= DKW_PTYPE_AMIGADOS
; break;
155 case FS_HFS
: str
= DKW_PTYPE_APPLEHFS
; break;
156 case FS_FILECORE
: str
= DKW_PTYPE_FILECORE
; break;
157 case FS_EX2FS
: str
= DKW_PTYPE_EXT2FS
; break;
158 case FS_NTFS
: str
= DKW_PTYPE_NTFS
; break;
159 case FS_RAID
: str
= DKW_PTYPE_RAIDFRAME
; break;
160 case FS_CCD
: str
= DKW_PTYPE_CCD
; break;
161 case FS_APPLEUFS
: str
= DKW_PTYPE_APPLEUFS
; break;
162 default: str
= NULL
; break;
169 swap_disklabel(struct disklabel
*lp
)
173 #define SWAP16(x) lp->x = bswap16(lp->x)
174 #define SWAP32(x) lp->x = bswap32(lp->x)
182 SWAP32(d_ncylinders
);
184 SWAP32(d_secperunit
);
185 SWAP16(d_sparespertrack
);
186 SWAP16(d_sparespercyl
);
187 SWAP32(d_acylinders
);
189 SWAP16(d_interleave
);
192 SWAP32(d_headswitch
);
196 for (i
= 0; i
< NDDATA
; i
++)
197 SWAP32(d_drivedata
[i
]);
198 for (i
= 0; i
< NSPARE
; i
++)
203 SWAP16(d_npartitions
);
207 for (i
= 0; i
< lp
->d_npartitions
; i
++) {
208 SWAP32(d_partitions
[i
].p_size
);
209 SWAP32(d_partitions
[i
].p_offset
);
210 SWAP32(d_partitions
[i
].p_fsize
);
211 SWAP16(d_partitions
[i
].p_cpg
);
219 * Add wedges for a valid NetBSD disklabel.
222 addwedges(const mbr_args_t
*a
, const struct disklabel
*lp
)
226 for (i
= 0; i
< lp
->d_npartitions
; i
++) {
227 struct dkwedge_info dkw
;
228 const struct partition
*p
;
231 p
= &lp
->d_partitions
[i
];
233 if (p
->p_fstype
== FS_UNUSED
)
235 if ((ptype
= bsdlabel_fstype_to_str(p
->p_fstype
)) == NULL
) {
237 * XXX Should probably just add these...
238 * XXX maybe just have an empty ptype?
240 aprint_verbose("%s: skipping partition %d, type %d\n",
241 a
->pdk
->dk_name
, i
, p
->p_fstype
);
244 strcpy(dkw
.dkw_ptype
, ptype
);
246 strcpy(dkw
.dkw_parent
, a
->pdk
->dk_name
);
247 dkw
.dkw_offset
= p
->p_offset
;
248 dkw
.dkw_size
= p
->p_size
;
251 * These get historical disk naming style
254 snprintf((char *)&dkw
.dkw_wname
, sizeof(dkw
.dkw_wname
),
255 "%s%c", a
->pdk
->dk_name
, 'a' + i
);
257 error
= dkwedge_add(&dkw
);
259 aprint_error("%s: wedge named '%s' already "
260 "exists, manual intervention required\n",
261 a
->pdk
->dk_name
, dkw
.dkw_wname
);
263 aprint_error("%s: error %d adding partition "
264 "%d type %d\n", a
->pdk
->dk_name
, error
,
270 validate_label(mbr_args_t
*a
, daddr_t label_sector
, size_t label_offset
)
272 struct disklabel
*lp
;
275 uint16_t npartitions
;
277 error
= dkwedge_read(a
->pdk
, a
->vp
, label_sector
, a
->buf
, DEV_BSIZE
);
279 aprint_error("%s: unable to read BSD disklabel @ %" PRId64
280 ", error = %d\n", a
->pdk
->dk_name
, label_sector
, error
);
286 * We ignore label_offset; this seems to have not been used
287 * consistently in the old code, requiring us to do the search
291 lp_lim
= (char *)a
->buf
+ DEV_BSIZE
- DISKLABEL_MINSIZE
;
292 for (;; lp
= (void *)((char *)lp
+ sizeof(uint32_t))) {
293 if ((char *)lp
> (char *)lp_lim
)
294 return (SCAN_CONTINUE
);
295 label_offset
= (size_t)((char *)lp
- (char *)a
->buf
);
296 if (lp
->d_magic
!= DISKMAGIC
|| lp
->d_magic2
!= DISKMAGIC
) {
297 if (lp
->d_magic
!= bswap32(DISKMAGIC
) ||
298 lp
->d_magic2
!= bswap32(DISKMAGIC
))
300 /* Label is in the other byte order. */
305 npartitions
= (swapped
) ? bswap16(lp
->d_npartitions
)
308 /* Validate label length. */
309 if ((char *)lp
+ DISKLABEL_SIZE(npartitions
) >
310 (char *)a
->buf
+ DEV_BSIZE
) {
311 aprint_error("%s: BSD disklabel @ "
312 "%" PRId64
"+%zd has bogus partition count (%u)\n",
313 a
->pdk
->dk_name
, label_sector
, label_offset
,
319 * We have validated the partition count. Checksum it.
320 * Note that we purposefully checksum before swapping
323 if (dkcksum_sized(lp
, npartitions
) != 0) {
324 aprint_error("%s: BSD disklabel @ %" PRId64
325 "+%zd has bad checksum\n", a
->pdk
->dk_name
,
326 label_sector
, label_offset
);
329 /* Put the disklabel in the right order. */
338 scan_mbr(mbr_args_t
*a
, int (*actn
)(mbr_args_t
*, struct mbr_partition
*,
341 struct mbr_partition ptns
[MBR_PART_COUNT
];
342 struct mbr_partition
*dp
;
343 struct mbr_sector
*mbr
;
344 u_int ext_base
, this_ext
, next_ext
;
346 #ifdef COMPAT_386BSD_MBRPART
353 a
->error
= dkwedge_read(a
->pdk
, a
->vp
, this_ext
, a
->buf
,
356 aprint_error("%s: unable to read MBR @ %u, "
357 "error = %d\n", a
->pdk
->dk_name
, this_ext
,
363 if (mbr
->mbr_magic
!= htole16(MBR_MAGIC
))
364 return (SCAN_CONTINUE
);
366 /* Copy data out of buffer so action can use the buffer. */
367 memcpy(ptns
, &mbr
->mbr_parts
, sizeof(ptns
));
369 /* Looks for NetBSD partition. */
372 for (i
= 0; i
< MBR_PART_COUNT
; i
++, dp
++) {
373 if (dp
->mbrp_type
== 0)
375 if (MBR_IS_EXTENDED(dp
->mbrp_type
)) {
376 next_ext
= le32toh(dp
->mbrp_start
);
379 #ifdef COMPAT_386BSD_MBRPART
380 if (dp
->mbrp_type
== MBR_PTYPE_386BSD
) {
382 * If more than one matches, take last,
383 * as NetBSD install tool does.
390 rval
= (*actn
)(a
, dp
, i
, this_ext
);
391 if (rval
!= SCAN_CONTINUE
)
400 next_ext
+= ext_base
;
401 if (next_ext
<= this_ext
)
405 #ifdef COMPAT_386BSD_MBRPART
406 if (this_ext
== 0 && dp_386bsd
!= -1)
407 return ((*actn
)(a
, &ptns
[dp_386bsd
], dp_386bsd
, 0));
409 return (SCAN_CONTINUE
);
413 look_netbsd_part(mbr_args_t
*a
, struct mbr_partition
*dp
, int slot
,
416 int ptn_base
= ext_base
+ le32toh(dp
->mbrp_start
);
420 #ifdef COMPAT_386BSD_MBRPART
421 dp
->mbrp_type
== MBR_PTYPE_386BSD
||
423 dp
->mbrp_type
== MBR_PTYPE_NETBSD
) {
424 rval
= validate_label(a
, ptn_base
+ BSD44_MBR_LABELSECTOR
, 0);
426 /* If we got a NetBSD label, look no further. */
427 if (rval
== SCAN_FOUND
)
431 return (SCAN_CONTINUE
);
435 #define DKW_MALLOC(SZ) malloc((SZ), M_DEVBUF, M_WAITOK)
436 #define DKW_FREE(PTR) free((PTR), M_DEVBUF)
438 #define DKW_MALLOC(SZ) malloc((SZ))
439 #define DKW_FREE(PTR) free((PTR))
443 dkwedge_discover_bsdlabel(struct disk
*pdk
, struct vnode
*vp
)
446 const struct disklabel_location
*dl
;
451 a
.buf
= DKW_MALLOC(DEV_BSIZE
);
455 rval
= scan_mbr(&a
, look_netbsd_part
);
456 if (rval
!= SCAN_CONTINUE
) {
457 if (rval
== SCAN_FOUND
)
458 a
.error
= 0; /* found it, wedges installed */
462 /* Known location search. */
463 for (dl
= disklabel_locations
; dl
->label_sector
!= -1; dl
++) {
464 rval
= validate_label(&a
, dl
->label_sector
, dl
->label_offset
);
465 if (rval
!= SCAN_CONTINUE
) {
466 if (rval
== SCAN_FOUND
)
467 a
.error
= 0; /* found it, wedges installed */
472 /* No NetBSD disklabel found. */
480 DKWEDGE_DISCOVERY_METHOD_DECL(BSD44
, 5, dkwedge_discover_bsdlabel
);