biosdisk.c revision 1.50 1 /* $NetBSD: biosdisk.c,v 1.50 2019/08/18 02:18:25 manu Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1998
5 * Matthias Drochner. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29 /*
30 * raw BIOS disk device for libsa.
31 * needs lowlevel parts from bios_disk.S and biosdisk_ll.c
32 * partly from netbsd:sys/arch/i386/boot/disk.c
33 * no bad144 handling!
34 *
35 * A lot of this must match sys/kern/subr_disk_mbr.c
36 */
37
38 /*
39 * Ported to boot 386BSD by Julian Elischer (julian (at) tfs.com) Sept 1992
40 *
41 * Mach Operating System
42 * Copyright (c) 1992, 1991 Carnegie Mellon University
43 * All Rights Reserved.
44 *
45 * Permission to use, copy, modify and distribute this software and its
46 * documentation is hereby granted, provided that both the copyright
47 * notice and this permission notice appear in all copies of the
48 * software, derivative works or modified versions, and any portions
49 * thereof, and that both notices appear in supporting documentation.
50 *
51 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
52 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
53 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
54 *
55 * Carnegie Mellon requests users of this software to return to
56 *
57 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
58 * School of Computer Science
59 * Carnegie Mellon University
60 * Pittsburgh PA 15213-3890
61 *
62 * any improvements or extensions that they make and grant Carnegie Mellon
63 * the rights to redistribute these changes.
64 */
65
66 #if !defined(NO_DISKLABEL) || !defined(NO_GPT)
67 #define FSTYPENAMES
68 #endif
69
70 #include <lib/libkern/libkern.h>
71 #include <lib/libsa/stand.h>
72
73 #include <sys/types.h>
74 #include <sys/md5.h>
75 #include <sys/param.h>
76 #include <sys/disklabel.h>
77 #include <sys/disklabel_gpt.h>
78 #include <sys/uuid.h>
79
80 #include <fs/cd9660/iso.h>
81 #include <fs/unicode.h>
82
83 #include <lib/libsa/saerrno.h>
84 #include <machine/cpu.h>
85
86 #include "libi386.h"
87 #include "biosdisk_ll.h"
88 #include "biosdisk.h"
89 #ifdef _STANDALONE
90 #include "bootinfo.h"
91 #endif
92
93 #ifndef NO_GPT
94 #define MAXDEVNAME 39 /* "NAME=" + 34 char part_name */
95 #else
96 #define MAXDEVNAME 16
97 #endif
98
99 #ifndef BIOSDISK_BUFSIZE
100 #define BIOSDISK_BUFSIZE 2048 /* must be large enough for a CD sector */
101 #endif
102
103 #define BIOSDISKNPART 26
104
105 struct biosdisk {
106 struct biosdisk_ll ll;
107 daddr_t boff;
108 char buf[BIOSDISK_BUFSIZE];
109 #if !defined(NO_DISKLABEL) || !defined(NO_GPT)
110 struct biosdisk_partition part[BIOSDISKNPART];
111 #endif
112 };
113
114 #include <dev/raidframe/raidframevar.h>
115 #define RF_COMPONENT_INFO_OFFSET 16384 /* from sys/dev/raidframe/rf_netbsdkintf.c */
116 #define RF_COMPONENT_LABEL_VERSION 2 /* from <dev/raidframe/rf_raid.h> */
117
118 #define RAIDFRAME_NDEV 16 /* abitrary limit to 15 raidframe devices */
119 struct raidframe {
120 int last_unit;
121 int serial;
122 int biosdev;
123 int parent_part;
124 #ifndef NO_GPT
125 char parent_name[MAXDEVNAME + 1];
126 #endif
127 daddr_t offset;
128 daddr_t size;
129 };
130
131
132 #ifndef NO_GPT
133 const struct uuid GET_nbsd_raid = GPT_ENT_TYPE_NETBSD_RAIDFRAME;
134 const struct uuid GET_nbsd_ffs = GPT_ENT_TYPE_NETBSD_FFS;
135 const struct uuid GET_nbsd_lfs = GPT_ENT_TYPE_NETBSD_LFS;
136 const struct uuid GET_nbsd_swap = GPT_ENT_TYPE_NETBSD_SWAP;
137 const struct uuid GET_nbsd_ccd = GPT_ENT_TYPE_NETBSD_CCD;
138 const struct uuid GET_nbsd_cgd = GPT_ENT_TYPE_NETBSD_CGD;
139
140 const struct uuid GET_efi = GPT_ENT_TYPE_EFI;
141 const struct uuid GET_mbr = GPT_ENT_TYPE_MBR;
142 const struct uuid GET_fbsd = GPT_ENT_TYPE_FREEBSD;
143 const struct uuid GET_fbsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
144 const struct uuid GET_fbsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
145 const struct uuid GET_fbsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
146 const struct uuid GET_fbsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
147 const struct uuid GET_ms_rsvd = GPT_ENT_TYPE_MS_RESERVED;
148 const struct uuid GET_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
149 const struct uuid GET_ms_ldm_metadata = GPT_ENT_TYPE_MS_LDM_METADATA;
150 const struct uuid GET_ms_ldm_data = GPT_ENT_TYPE_MS_LDM_DATA;
151 const struct uuid GET_linux_data = GPT_ENT_TYPE_LINUX_DATA;
152 const struct uuid GET_linux_raid = GPT_ENT_TYPE_LINUX_RAID;
153 const struct uuid GET_linux_swap = GPT_ENT_TYPE_LINUX_SWAP;
154 const struct uuid GET_linux_lvm = GPT_ENT_TYPE_LINUX_LVM;
155 const struct uuid GET_apple_hfs = GPT_ENT_TYPE_APPLE_HFS;
156 const struct uuid GET_apple_ufs = GPT_ENT_TYPE_APPLE_UFS;
157 const struct uuid GET_bios = GPT_ENT_TYPE_BIOS;
158
159 const struct gpt_part gpt_parts[] = {
160 { &GET_nbsd_raid, "NetBSD RAID" },
161 { &GET_nbsd_ffs, "NetBSD FFS" },
162 { &GET_nbsd_lfs, "NetBSD LFS" },
163 { &GET_nbsd_swap, "NetBSD Swap" },
164 { &GET_nbsd_ccd, "NetBSD ccd" },
165 { &GET_nbsd_cgd, "NetBSD cgd" },
166 { &GET_efi, "EFI System" },
167 { &GET_mbr, "MBR" },
168 { &GET_fbsd, "FreeBSD" },
169 { &GET_fbsd_swap, "FreeBSD Swap" },
170 { &GET_fbsd_ufs, "FreeBSD UFS" },
171 { &GET_fbsd_vinum, "FreeBSD Vinum" },
172 { &GET_fbsd_zfs, "FreeBSD ZFS" },
173 { &GET_ms_rsvd, "Microsoft Reserved" },
174 { &GET_ms_basic_data, "Microsoft Basic data" },
175 { &GET_ms_ldm_metadata, "Microsoft LDM metadata" },
176 { &GET_ms_ldm_data, "Microsoft LDM data" },
177 { &GET_linux_data, "Linux data" },
178 { &GET_linux_raid, "Linux RAID" },
179 { &GET_linux_swap, "Linux Swap" },
180 { &GET_linux_lvm, "Linux LVM" },
181 { &GET_apple_hfs, "Apple HFS" },
182 { &GET_apple_ufs, "Apple UFS" },
183 { &GET_bios, "BIOS Boot (GRUB)" },
184 };
185 #endif /* NO_GPT */
186
187 #ifdef _STANDALONE
188 static struct btinfo_bootdisk bi_disk;
189 static struct btinfo_bootwedge bi_wedge;
190 #endif
191
192 #define MBR_PARTS(buf) ((char *)(buf) + offsetof(struct mbr_sector, mbr_parts))
193
194 #ifndef devb2cdb
195 #define devb2cdb(bno) (((bno) * DEV_BSIZE) / ISO_DEFAULT_BLOCK_SIZE)
196 #endif
197
198 static void
199 dealloc_biosdisk(struct biosdisk *d)
200 {
201 #ifndef NO_GPT
202 int i;
203
204 for (i = 0; i < __arraycount(d->part); i++) {
205 if (d->part[i].part_name != NULL)
206 dealloc(d->part[i].part_name, BIOSDISK_PART_NAME_LEN);
207 }
208 #endif
209
210 dealloc(d, sizeof(*d));
211
212 return;
213 }
214
215 static struct biosdisk_partition *
216 copy_biosdisk_part(struct biosdisk *d)
217 {
218 struct biosdisk_partition *part;
219
220 part = alloc(sizeof(d->part));
221 if (part == NULL)
222 goto out;
223
224 memcpy(part, d->part, sizeof(d->part));
225
226 #ifndef NO_GPT
227 int i;
228
229 for (i = 0; i < __arraycount(d->part); i++) {
230 if (d->part[i].part_name != NULL) {
231 part[i].part_name = alloc(BIOSDISK_PART_NAME_LEN);
232 memcpy(part[i].part_name, d->part[i].part_name,
233 BIOSDISK_PART_NAME_LEN);
234 }
235 }
236 #endif
237
238 out:
239 return part;
240 }
241
242 int
243 biosdisk_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
244 void *buf, size_t *rsize)
245 {
246 struct biosdisk *d;
247 int blks, frag;
248
249 if (flag != F_READ)
250 return EROFS;
251
252 d = (struct biosdisk *) devdata;
253
254 if (d->ll.type == BIOSDISK_TYPE_CD)
255 dblk = devb2cdb(dblk);
256
257 dblk += d->boff;
258
259 blks = size / d->ll.secsize;
260 if (blks && readsects(&d->ll, dblk, blks, buf, 0)) {
261 if (rsize)
262 *rsize = 0;
263 return EIO;
264 }
265
266 /* needed for CD */
267 frag = size % d->ll.secsize;
268 if (frag) {
269 if (readsects(&d->ll, dblk + blks, 1, d->buf, 0)) {
270 if (rsize)
271 *rsize = blks * d->ll.secsize;
272 return EIO;
273 }
274 memcpy(buf + blks * d->ll.secsize, d->buf, frag);
275 }
276
277 if (rsize)
278 *rsize = size;
279 return 0;
280 }
281
282 static struct biosdisk *
283 alloc_biosdisk(int biosdev)
284 {
285 struct biosdisk *d;
286
287 d = alloc(sizeof(*d));
288 if (d == NULL)
289 return NULL;
290 memset(d, 0, sizeof(*d));
291
292 d->ll.dev = biosdev;
293 if (set_geometry(&d->ll, NULL)) {
294 #ifdef DISK_DEBUG
295 printf("no geometry information\n");
296 #endif
297 dealloc_biosdisk(d);
298 return NULL;
299 }
300 return d;
301 }
302
303 #if !defined(NO_DISKLABEL) || !defined(NO_GPT)
304 static void
305 md5(void *hash, const void *data, size_t len)
306 {
307 MD5_CTX ctx;
308
309 MD5Init(&ctx);
310 MD5Update(&ctx, data, len);
311 MD5Final(hash, &ctx);
312
313 return;
314 }
315 #endif
316
317 #ifndef NO_GPT
318 bool
319 guid_is_nil(const struct uuid *u)
320 {
321 static const struct uuid nil = { .time_low = 0 };
322 return (memcmp(u, &nil, sizeof(*u)) == 0 ? true : false);
323 }
324
325 bool
326 guid_is_equal(const struct uuid *a, const struct uuid *b)
327 {
328 return (memcmp(a, b, sizeof(*a)) == 0 ? true : false);
329 }
330
331 #ifndef NO_GPT
332 static void
333 part_name_utf8(const uint16_t *utf16_src, size_t utf16_srclen,
334 char *utf8_dst, size_t utf8_dstlen)
335 {
336 char *c = utf8_dst;
337 size_t r = utf8_dstlen - 1;
338 size_t n;
339 int j;
340
341 if (utf8_dst == NULL)
342 return;
343
344 for (j = 0; j < utf16_srclen && utf16_src[j] != 0x0000; j++) {
345 n = wput_utf8(c, r, le16toh(utf16_src[j]));
346 if (n == 0)
347 break;
348 c += n; r -= n;
349 }
350 *c = '\0';
351
352 return;
353 }
354 #endif
355
356 static int
357 check_gpt(struct biosdisk *d, daddr_t rf_offset, daddr_t sector)
358 {
359 struct gpt_hdr gpth;
360 const struct gpt_ent *ep;
361 const struct uuid *u;
362 daddr_t entblk;
363 size_t size;
364 uint32_t crc;
365 int sectors;
366 int entries;
367 int entry;
368 int i, j;
369
370 /* read in gpt_hdr sector */
371 if (readsects(&d->ll, sector, 1, d->buf, 1)) {
372 #ifdef DISK_DEBUG
373 printf("Error reading GPT header at %"PRId64"\n", sector);
374 #endif
375 return EIO;
376 }
377
378 memcpy(&gpth, d->buf, sizeof(gpth));
379
380 if (memcmp(GPT_HDR_SIG, gpth.hdr_sig, sizeof(gpth.hdr_sig)))
381 return -1;
382
383 crc = gpth.hdr_crc_self;
384 gpth.hdr_crc_self = 0;
385 gpth.hdr_crc_self = crc32(0, (const void *)&gpth, GPT_HDR_SIZE);
386 if (gpth.hdr_crc_self != crc) {
387 return -1;
388 }
389
390 if (gpth.hdr_lba_self + rf_offset != sector)
391 return -1;
392
393 #ifdef _STANDALONE
394 bi_wedge.matchblk = sector;
395 bi_wedge.matchnblks = 1;
396
397 md5(bi_wedge.matchhash, d->buf, d->ll.secsize);
398 #endif
399
400 sectors = sizeof(d->buf)/d->ll.secsize; /* sectors per buffer */
401 entries = sizeof(d->buf)/gpth.hdr_entsz; /* entries per buffer */
402 entblk = gpth.hdr_lba_table + rf_offset;
403 crc = crc32(0, NULL, 0);
404
405 j = 0;
406 ep = (const struct gpt_ent *)d->buf;
407
408 for (entry = 0; entry < gpth.hdr_entries; entry += entries) {
409 size = MIN(sizeof(d->buf),
410 (gpth.hdr_entries - entry) * gpth.hdr_entsz);
411 entries = size / gpth.hdr_entsz;
412 sectors = roundup(size, d->ll.secsize) / d->ll.secsize;
413 if (readsects(&d->ll, entblk, sectors, d->buf, 1))
414 return -1;
415 entblk += sectors;
416 crc = crc32(crc, (const void *)d->buf, size);
417
418 for (i = 0; j < BIOSDISKNPART && i < entries; i++) {
419 u = (const struct uuid *)ep[i].ent_type;
420 if (!guid_is_nil(u)) {
421 d->part[j].offset = ep[i].ent_lba_start;
422 d->part[j].size = ep[i].ent_lba_end -
423 ep[i].ent_lba_start + 1;
424 if (guid_is_equal(u, &GET_nbsd_ffs))
425 d->part[j].fstype = FS_BSDFFS;
426 else if (guid_is_equal(u, &GET_nbsd_lfs))
427 d->part[j].fstype = FS_BSDLFS;
428 else if (guid_is_equal(u, &GET_nbsd_raid))
429 d->part[j].fstype = FS_RAID;
430 else if (guid_is_equal(u, &GET_nbsd_swap))
431 d->part[j].fstype = FS_SWAP;
432 else if (guid_is_equal(u, &GET_nbsd_ccd))
433 d->part[j].fstype = FS_CCD;
434 else if (guid_is_equal(u, &GET_nbsd_cgd))
435 d->part[j].fstype = FS_CGD;
436 else
437 d->part[j].fstype = FS_OTHER;
438 #ifndef NO_GPT
439 for (int k = 0;
440 k < __arraycount(gpt_parts);
441 k++) {
442 if (guid_is_equal(u, gpt_parts[k].guid))
443 d->part[j].guid = &gpt_parts[k];
444 }
445 d->part[j].attr = ep[i].ent_attr;
446
447 d->part[j].part_name =
448 alloc(BIOSDISK_PART_NAME_LEN);
449 part_name_utf8(ep[i].ent_name,
450 sizeof(ep[i].ent_name),
451 d->part[j].part_name,
452 BIOSDISK_PART_NAME_LEN);
453 #endif
454 j++;
455 }
456 }
457
458 }
459
460 if (crc != gpth.hdr_crc_table) {
461 #ifdef DISK_DEBUG
462 printf("GPT table CRC invalid\n");
463 #endif
464 return -1;
465 }
466
467 return 0;
468 }
469
470 static int
471 read_gpt(struct biosdisk *d, daddr_t rf_offset, daddr_t rf_size)
472 {
473 struct biosdisk_extinfo ed;
474 daddr_t gptsector[2];
475 int i, error;
476
477 if (d->ll.type != BIOSDISK_TYPE_HD)
478 /* No GPT on floppy and CD */
479 return -1;
480
481 if (rf_offset && rf_size) {
482 gptsector[0] = rf_offset + GPT_HDR_BLKNO;
483 gptsector[1] = rf_offset + rf_size - 1;
484 } else {
485 gptsector[0] = GPT_HDR_BLKNO;
486 if (set_geometry(&d->ll, &ed) == 0 &&
487 d->ll.flags & BIOSDISK_INT13EXT) {
488 gptsector[1] = ed.totsec - 1;
489 /* Sanity check values returned from BIOS */
490 if (ed.sbytes >= 512 &&
491 (ed.sbytes & (ed.sbytes - 1)) == 0)
492 d->ll.secsize = ed.sbytes;
493 } else {
494 #ifdef DISK_DEBUG
495 printf("Unable to determine extended disk geometry - "
496 "using CHS\n");
497 #endif
498 /* at least try some other reasonable values then */
499 gptsector[1] = d->ll.chs_sectors - 1;
500 }
501 }
502
503 for (i = 0; i < __arraycount(gptsector); i++) {
504 error = check_gpt(d, rf_offset, gptsector[i]);
505 if (error == 0)
506 break;
507 }
508
509 if (i >= __arraycount(gptsector)) {
510 memset(d->part, 0, sizeof(d->part));
511 return -1;
512 }
513
514 #ifndef USE_SECONDARY_GPT
515 if (i > 0) {
516 #ifdef DISK_DEBUG
517 printf("ignoring valid secondary GPT\n");
518 #endif
519 return -1;
520 }
521 #endif
522
523 #ifdef DISK_DEBUG
524 printf("using %s GPT\n", (i == 0) ? "primary" : "secondary");
525 #endif
526 return 0;
527 }
528 #endif /* !NO_GPT */
529
530 #ifndef NO_DISKLABEL
531 static void
532 ingest_label(struct biosdisk *d, struct disklabel *lp)
533 {
534 int part;
535
536 memset(d->part, 0, sizeof(d->part));
537
538 for (part = 0; part < lp->d_npartitions; part++) {
539 if (lp->d_partitions[part].p_size == 0)
540 continue;
541 if (lp->d_partitions[part].p_fstype == FS_UNUSED)
542 continue;
543 d->part[part].fstype = lp->d_partitions[part].p_fstype;
544 d->part[part].offset = lp->d_partitions[part].p_offset;
545 d->part[part].size = lp->d_partitions[part].p_size;
546 }
547 }
548
549 static int
550 check_label(struct biosdisk *d, daddr_t sector)
551 {
552 struct disklabel *lp;
553
554 /* find partition in NetBSD disklabel */
555 if (readsects(&d->ll, sector + LABELSECTOR, 1, d->buf, 0)) {
556 #ifdef DISK_DEBUG
557 printf("Error reading disklabel\n");
558 #endif
559 return EIO;
560 }
561 lp = (struct disklabel *) (d->buf + LABELOFFSET);
562 if (lp->d_magic != DISKMAGIC || dkcksum(lp)) {
563 #ifdef DISK_DEBUG
564 printf("warning: no disklabel in sector %"PRId64"\n", sector);
565 #endif
566 return -1;
567 }
568
569 ingest_label(d, lp);
570
571 #ifdef _STANDALONE
572 bi_disk.labelsector = sector + LABELSECTOR;
573 bi_disk.label.type = lp->d_type;
574 memcpy(bi_disk.label.packname, lp->d_packname, 16);
575 bi_disk.label.checksum = lp->d_checksum;
576
577 bi_wedge.matchblk = sector + LABELSECTOR;
578 bi_wedge.matchnblks = 1;
579
580 md5(bi_wedge.matchhash, d->buf, d->ll.secsize);
581 #endif
582
583 return 0;
584 }
585
586 static int
587 read_minix_subp(struct biosdisk *d, struct disklabel* dflt_lbl,
588 int this_ext, daddr_t sector)
589 {
590 struct mbr_partition mbr[MBR_PART_COUNT];
591 int i;
592 int typ;
593 struct partition *p;
594
595 if (readsects(&d->ll, sector, 1, d->buf, 0)) {
596 #ifdef DISK_DEBUG
597 printf("Error reading MFS sector %"PRId64"\n", sector);
598 #endif
599 return EIO;
600 }
601 if ((uint8_t)d->buf[510] != 0x55 || (uint8_t)d->buf[511] != 0xAA) {
602 return -1;
603 }
604 memcpy(&mbr, MBR_PARTS(d->buf), sizeof(mbr));
605 for (i = 0; i < MBR_PART_COUNT; i++) {
606 typ = mbr[i].mbrp_type;
607 if (typ == 0)
608 continue;
609 sector = this_ext + mbr[i].mbrp_start;
610 if (dflt_lbl->d_npartitions >= MAXPARTITIONS)
611 continue;
612 p = &dflt_lbl->d_partitions[dflt_lbl->d_npartitions++];
613 p->p_offset = sector;
614 p->p_size = mbr[i].mbrp_size;
615 p->p_fstype = xlat_mbr_fstype(typ);
616 }
617 return 0;
618 }
619
620 #if defined(EFIBOOT) && defined(SUPPORT_CD9660)
621 static int
622 check_cd9660(struct biosdisk *d)
623 {
624 struct biosdisk_extinfo ed;
625 struct iso_primary_descriptor *vd;
626 daddr_t bno;
627
628 for (bno = 16;; bno++) {
629 if (readsects(&d->ll, bno, 1, d->buf, 0))
630 return -1;
631 vd = (struct iso_primary_descriptor *)d->buf;
632 if (memcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0)
633 return -1;
634 if (isonum_711(vd->type) == ISO_VD_END)
635 return -1;
636 if (isonum_711(vd->type) == ISO_VD_PRIMARY)
637 break;
638 }
639 if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE)
640 return -1;
641
642 if (set_geometry(&d->ll, &ed))
643 return -1;
644
645 memset(d->part, 0, sizeof(d->part));
646 d->part[0].fstype = FS_ISO9660;
647 d->part[0].offset = 0;
648 d->part[0].size = ed.totsec;
649 return 0;
650 }
651 #endif
652
653 static int
654 read_label(struct biosdisk *d, daddr_t offset)
655 {
656 struct disklabel dflt_lbl;
657 struct mbr_partition mbr[MBR_PART_COUNT];
658 struct partition *p;
659 uint32_t sector;
660 int i;
661 int error;
662 int typ;
663 uint32_t ext_base, this_ext, next_ext;
664 #ifdef COMPAT_386BSD_MBRPART
665 int sector_386bsd = -1;
666 #endif
667
668 memset(&dflt_lbl, 0, sizeof(dflt_lbl));
669 dflt_lbl.d_npartitions = 8;
670
671 d->boff = 0;
672
673 if (d->ll.type != BIOSDISK_TYPE_HD)
674 /* No label on floppy and CD */
675 return -1;
676
677 /*
678 * find NetBSD Partition in DOS partition table
679 * XXX check magic???
680 */
681 ext_base = offset;
682 next_ext = offset;
683 for (;;) {
684 this_ext = ext_base + next_ext;
685 next_ext = offset;
686 if (readsects(&d->ll, this_ext, 1, d->buf, 0)) {
687 #ifdef DISK_DEBUG
688 printf("error reading MBR sector %u\n", this_ext);
689 #endif
690 return EIO;
691 }
692 memcpy(&mbr, MBR_PARTS(d->buf), sizeof(mbr));
693 /* Look for NetBSD partition ID */
694 for (i = 0; i < MBR_PART_COUNT; i++) {
695 typ = mbr[i].mbrp_type;
696 if (typ == 0)
697 continue;
698 sector = this_ext + mbr[i].mbrp_start;
699 #ifdef DISK_DEBUG
700 printf("ptn type %d in sector %u\n", typ, sector);
701 #endif
702 if (typ == MBR_PTYPE_MINIX_14B) {
703 if (!read_minix_subp(d, &dflt_lbl,
704 this_ext, sector)) {
705 /* Don't add "container" partition */
706 continue;
707 }
708 }
709 if (typ == MBR_PTYPE_NETBSD) {
710 error = check_label(d, sector);
711 if (error >= 0)
712 return error;
713 }
714 if (MBR_IS_EXTENDED(typ)) {
715 next_ext = mbr[i].mbrp_start + offset;
716 continue;
717 }
718 #ifdef COMPAT_386BSD_MBRPART
719 if (this_ext == offset && typ == MBR_PTYPE_386BSD)
720 sector_386bsd = sector;
721 #endif
722 if (this_ext != offset) {
723 if (dflt_lbl.d_npartitions >= MAXPARTITIONS)
724 continue;
725 p = &dflt_lbl.d_partitions[dflt_lbl.d_npartitions++];
726 } else
727 p = &dflt_lbl.d_partitions[i];
728 p->p_offset = sector;
729 p->p_size = mbr[i].mbrp_size;
730 p->p_fstype = xlat_mbr_fstype(typ);
731 }
732 if (next_ext == offset)
733 break;
734 if (ext_base == offset) {
735 ext_base = next_ext;
736 next_ext = offset;
737 }
738 }
739
740 sector = offset;
741 #ifdef COMPAT_386BSD_MBRPART
742 if (sector_386bsd != -1) {
743 printf("old BSD partition ID!\n");
744 sector = sector_386bsd;
745 }
746 #endif
747
748 /*
749 * One of two things:
750 * 1. no MBR
751 * 2. no NetBSD partition in MBR
752 *
753 * We simply default to "start of disk" in this case and
754 * press on.
755 */
756 error = check_label(d, sector);
757 if (error >= 0)
758 return error;
759
760 #if defined(EFIBOOT) && defined(SUPPORT_CD9660)
761 /* Check CD/DVD */
762 error = check_cd9660(d);
763 if (error >= 0)
764 return error;
765 #endif
766
767 /*
768 * Nothing at start of disk, return info from mbr partitions.
769 */
770 /* XXX fill it to make checksum match kernel one */
771 dflt_lbl.d_checksum = dkcksum(&dflt_lbl);
772 ingest_label(d, &dflt_lbl);
773 return 0;
774 }
775 #endif /* NO_DISKLABEL */
776
777 #if !defined(NO_DISKLABEL) || !defined(NO_GPT)
778 static int
779 read_partitions(struct biosdisk *d, daddr_t offset, daddr_t size)
780 {
781 int error;
782
783 error = -1;
784
785 #ifndef NO_GPT
786 error = read_gpt(d, offset, size);
787 if (error == 0)
788 return 0;
789
790 #endif
791 #ifndef NO_DISKLABEL
792 error = read_label(d, offset);
793
794 #endif
795 return error;
796 }
797 #endif
798
799 #ifndef NO_RAIDFRAME
800 static void
801 raidframe_probe(struct raidframe *raidframe, int *raidframe_count,
802 struct biosdisk *d, int part)
803 {
804 int i = *raidframe_count;
805 struct RF_ComponentLabel_s label;
806 daddr_t offset;
807
808 if (i + 1 > RAIDFRAME_NDEV)
809 return;
810
811 offset = d->part[part].offset;
812 if ((biosdisk_read_raidframe(d->ll.dev, offset, &label)) != 0)
813 return;
814
815 if (label.version != RF_COMPONENT_LABEL_VERSION)
816 printf("Unexpected raidframe label version\n");
817
818 raidframe[i].last_unit = label.last_unit;
819 raidframe[i].serial = label.serial_number;
820 raidframe[i].biosdev = d->ll.dev;
821 raidframe[i].parent_part = part;
822 #ifndef NO_GPT
823 if (d->part[part].part_name)
824 strlcpy(raidframe[i].parent_name,
825 d->part[part].part_name, MAXDEVNAME);
826 else
827 raidframe[i].parent_name[0] = '\0';
828 #endif
829 raidframe[i].offset = offset;
830 raidframe[i].size = label.__numBlocks;
831
832 (*raidframe_count)++;
833
834 return;
835 }
836 #endif
837
838 void
839 biosdisk_probe(void)
840 {
841 struct biosdisk *d;
842 struct biosdisk_extinfo ed;
843 #ifndef NO_RAIDFRAME
844 struct raidframe raidframe[RAIDFRAME_NDEV];
845 int raidframe_count = 0;
846 #endif
847 uint64_t size;
848 int first;
849 int i;
850 #if !defined(NO_DISKLABEL) || !defined(NO_GPT)
851 int part;
852 #endif
853
854 for (i = 0; i < MAX_BIOSDISKS + 2; i++) {
855 first = 1;
856 d = alloc(sizeof(*d));
857 if (d == NULL) {
858 printf("Out of memory\n");
859 return;
860 }
861 memset(d, 0, sizeof(d));
862 memset(&ed, 0, sizeof(ed));
863 if (i >= MAX_BIOSDISKS)
864 d->ll.dev = 0x00 + i - MAX_BIOSDISKS; /* fd */
865 else
866 d->ll.dev = 0x80 + i; /* hd/cd */
867 if (set_geometry(&d->ll, &ed))
868 goto next_disk;
869 printf("disk ");
870 switch (d->ll.type) {
871 case BIOSDISK_TYPE_CD:
872 printf("cd0\n cd0a\n");
873 break;
874 case BIOSDISK_TYPE_FD:
875 printf("fd%d\n", d->ll.dev & 0x7f);
876 printf(" fd%da\n", d->ll.dev & 0x7f);
877 break;
878 case BIOSDISK_TYPE_HD:
879 printf("hd%d", d->ll.dev & 0x7f);
880 if (d->ll.flags & BIOSDISK_INT13EXT) {
881 printf(" size ");
882 size = ed.totsec * ed.sbytes;
883 if (size >= (10ULL * 1024 * 1024 * 1024))
884 printf("%"PRIu64" GB",
885 size / (1024 * 1024 * 1024));
886 else
887 printf("%"PRIu64" MB",
888 size / (1024 * 1024));
889 }
890 printf("\n");
891 break;
892 }
893 #if !defined(NO_DISKLABEL) || !defined(NO_GPT)
894 if (d->ll.type != BIOSDISK_TYPE_HD)
895 goto next_disk;
896
897 if (read_partitions(d, 0, 0) != 0)
898 goto next_disk;
899
900 for (part = 0; part < BIOSDISKNPART; part++) {
901 if (d->part[part].size == 0)
902 continue;
903 if (d->part[part].fstype == FS_UNUSED)
904 continue;
905 #ifndef NO_RAIDFRAME
906 if (d->part[part].fstype == FS_RAID)
907 raidframe_probe(raidframe,
908 &raidframe_count, d, part);
909 #endif
910 if (first) {
911 printf(" ");
912 first = 0;
913 }
914 #ifndef NO_GPT
915 if (d->part[part].part_name != NULL)
916 printf(" NAME=%s(", d->part[part].part_name);
917 else
918 #endif
919 printf(" hd%d%c(", d->ll.dev & 0x7f, part + 'a');
920
921 #ifndef NO_GPT
922 if (d->part[part].guid != NULL)
923 printf("%s", d->part[part].guid->name);
924 else
925 #endif
926
927 if (d->part[part].fstype < FSMAXTYPES)
928 printf("%s",
929 fstypenames[d->part[part].fstype]);
930 else
931 printf("%d", d->part[part].fstype);
932 printf(")");
933 }
934 #endif
935 if (first == 0)
936 printf("\n");
937
938 next_disk:
939 dealloc_biosdisk(d);
940 }
941
942 #ifndef NO_RAIDFRAME
943 for (i = 0; i < raidframe_count; i++) {
944 size_t secsize;
945
946 if ((d = alloc_biosdisk(raidframe[i].biosdev)) == NULL) {
947 printf("Out of memory\n");
948 return;
949 }
950
951 secsize = d->ll.secsize;
952
953 printf("raidframe raid%d serial %d in ",
954 raidframe[i].last_unit, raidframe[i].serial);
955 #ifndef NO_GPT
956 if (raidframe[i].parent_name[0])
957 printf("NAME=%s size ", raidframe[i].parent_name);
958 else
959 #endif
960 printf("hd%d%c size ", d->ll.dev & 0x7f,
961 raidframe[i].parent_part + 'a');
962 if (raidframe[i].size >= (10ULL * 1024 * 1024 * 1024 / secsize))
963 printf("%"PRIu64" GB",
964 raidframe[i].size / (1024 * 1024 * 1024 / secsize));
965 else
966 printf("%"PRIu64" MB",
967 raidframe[i].size / (1024 * 1024 / secsize));
968 printf("\n");
969
970 if (read_partitions(d,
971 raidframe[i].offset + RF_PROTECTED_SECTORS,
972 raidframe[i].size) != 0)
973 goto next_raidrame;
974
975 first = 1;
976 for (part = 0; part < BIOSDISKNPART; part++) {
977 #ifndef NO_GPT
978 bool bootme = d->part[part].attr & GPT_ENT_ATTR_BOOTME;
979 #else
980 bool bootme = 0;
981 #endif
982
983 if (d->part[part].size == 0)
984 continue;
985 if (d->part[part].fstype == FS_UNUSED)
986 continue;
987 if (d->part[part].fstype == FS_RAID)
988 continue;
989 if (first) {
990 printf(" ");
991 first = 0;
992 }
993 #ifndef NO_GPT
994 if (d->part[part].part_name != NULL)
995 printf(" NAME=%s(", d->part[part].part_name);
996 else
997 #endif
998 printf(" raid%d%c(", raidframe[i].last_unit,
999 part + 'a');
1000 #ifndef NO_GPT
1001 if (d->part[part].guid != NULL)
1002 printf("%s", d->part[part].guid->name);
1003 else
1004 #endif
1005 if (d->part[part].fstype < FSMAXTYPES)
1006 printf("%s",
1007 fstypenames[d->part[part].fstype]);
1008 else
1009 printf("%d", d->part[part].fstype);
1010 printf("%s)", bootme ? ", bootme" : "");
1011 }
1012
1013 next_raidrame:
1014 if (first == 0)
1015 printf("\n");
1016
1017 dealloc_biosdisk(d);
1018 }
1019 #endif
1020 }
1021
1022 /* Determine likely partition for possible sector number of dos
1023 * partition.
1024 */
1025
1026 int
1027 biosdisk_findpartition(int biosdev, daddr_t sector,
1028 int *partition, const char **part_name)
1029 {
1030 #if defined(NO_DISKLABEL) && defined(NO_GPT)
1031 *partition = 0;
1032 *part_name = NULL;
1033 return 0;
1034 #else
1035 int i;
1036 struct biosdisk *d;
1037 int biosboot_sector_part = -1;
1038 int bootable_fs_part = -1;
1039 int boot_part = 0;
1040 #ifndef NO_GPT
1041 int gpt_bootme_part = -1;
1042 static char namebuf[MAXDEVNAME + 1];
1043 #endif
1044
1045 #ifdef DISK_DEBUG
1046 printf("looking for partition device %x, sector %"PRId64"\n", biosdev, sector);
1047 #endif
1048
1049 /* default ot first partition */
1050 *partition = 0;
1051 *part_name = NULL;
1052
1053 /* Look for netbsd partition that is the dos boot one */
1054 d = alloc_biosdisk(biosdev);
1055 if (d == NULL)
1056 return -1;
1057
1058 if (read_partitions(d, 0, 0) == 0) {
1059 for (i = 0; i < BIOSDISKNPART; i++) {
1060 if (d->part[i].fstype == FS_UNUSED)
1061 continue;
1062
1063 if (d->part[i].offset == sector &&
1064 biosboot_sector_part == -1)
1065 biosboot_sector_part = i;
1066
1067 #ifndef NO_GPT
1068 if (d->part[i].attr & GPT_ENT_ATTR_BOOTME &&
1069 gpt_bootme_part == -1)
1070 gpt_bootme_part = i;
1071 #endif
1072 switch (d->part[i].fstype) {
1073 case FS_BSDFFS:
1074 case FS_BSDLFS:
1075 case FS_RAID:
1076 case FS_CCD:
1077 case FS_CGD:
1078 case FS_ISO9660:
1079 if (bootable_fs_part == -1)
1080 bootable_fs_part = i;
1081 break;
1082
1083 default:
1084 break;
1085 }
1086 }
1087
1088 #ifndef NO_GPT
1089 if (gpt_bootme_part != -1)
1090 boot_part = gpt_bootme_part;
1091 else
1092 #endif
1093 if (biosboot_sector_part != -1)
1094 boot_part = biosboot_sector_part;
1095 else if (bootable_fs_part != -1)
1096 boot_part = bootable_fs_part;
1097 else
1098 boot_part = 0;
1099
1100 *partition = boot_part;
1101 #ifndef NO_GPT
1102 if (part_name && d->part[boot_part].part_name) {
1103 strlcpy(namebuf, d->part[boot_part].part_name,
1104 BIOSDISK_PART_NAME_LEN);
1105 *part_name = namebuf;
1106 }
1107 #endif
1108 }
1109
1110 dealloc_biosdisk(d);
1111 return 0;
1112 #endif /* NO_DISKLABEL && NO_GPT */
1113 }
1114
1115 int
1116 biosdisk_readpartition(int biosdev, daddr_t offset, daddr_t size,
1117 struct biosdisk_partition **partpp, int *rnum)
1118 {
1119 #if defined(NO_DISKLABEL) && defined(NO_GPT)
1120 return ENOTSUP;
1121 #else
1122 struct biosdisk *d;
1123 struct biosdisk_partition *part;
1124 int rv;
1125
1126 /* Look for netbsd partition that is the dos boot one */
1127 d = alloc_biosdisk(biosdev);
1128 if (d == NULL)
1129 return ENOMEM;
1130
1131 if (read_partitions(d, offset, size)) {
1132 rv = EINVAL;
1133 goto out;
1134 }
1135
1136 part = copy_biosdisk_part(d);
1137 if (part == NULL) {
1138 rv = ENOMEM;
1139 goto out;
1140 }
1141
1142 *partpp = part;
1143 *rnum = (int)__arraycount(d->part);
1144 rv = 0;
1145 out:
1146 dealloc_biosdisk(d);
1147 return rv;
1148 #endif /* NO_DISKLABEL && NO_GPT */
1149 }
1150
1151 #ifndef NO_RAIDFRAME
1152 int
1153 biosdisk_read_raidframe(int biosdev, daddr_t offset,
1154 struct RF_ComponentLabel_s *label)
1155 {
1156 #if defined(NO_DISKLABEL) && defined(NO_GPT)
1157 return ENOTSUP;
1158 #else
1159 struct biosdisk *d;
1160 struct biosdisk_extinfo ed;
1161 daddr_t size;
1162 int rv = -1;
1163
1164 /* Look for netbsd partition that is the dos boot one */
1165 d = alloc_biosdisk(biosdev);
1166 if (d == NULL)
1167 goto out;
1168
1169 if (d->ll.type != BIOSDISK_TYPE_HD)
1170 /* No raidframe on floppy and CD */
1171 goto out;
1172
1173 if (set_geometry(&d->ll, &ed) != 0)
1174 goto out;
1175
1176 /* Sanity check values returned from BIOS */
1177 if (ed.sbytes >= 512 &&
1178 (ed.sbytes & (ed.sbytes - 1)) == 0)
1179 d->ll.secsize = ed.sbytes;
1180
1181 offset += (RF_COMPONENT_INFO_OFFSET / d->ll.secsize);
1182 size = roundup(sizeof(*label), d->ll.secsize) / d->ll.secsize;
1183 if (readsects(&d->ll, offset, size, d->buf, 0))
1184 goto out;
1185 memcpy(label, d->buf, sizeof(*label));
1186 rv = 0;
1187 out:
1188 if (d != NULL)
1189 dealloc_biosdisk(d);
1190 return rv;
1191 #endif /* NO_DISKLABEL && NO_GPT */
1192 }
1193 #endif /* NO_RAIDFRAME */
1194
1195 #ifdef _STANDALONE
1196 static void
1197 add_biosdisk_bootinfo(void)
1198 {
1199 if (bootinfo == NULL) {
1200 return;
1201 }
1202 BI_ADD(&bi_disk, BTINFO_BOOTDISK, sizeof(bi_disk));
1203 BI_ADD(&bi_wedge, BTINFO_BOOTWEDGE, sizeof(bi_wedge));
1204 return;
1205 }
1206 #endif
1207
1208 #ifndef NO_GPT
1209 static daddr_t
1210 raidframe_part_offset(struct biosdisk *d, int part)
1211 {
1212 struct biosdisk raidframe;
1213 daddr_t rf_offset;
1214 daddr_t rf_size;
1215 int i, candidate;
1216
1217 memset(&raidframe, 0, sizeof(raidframe));
1218 raidframe.ll = d->ll;
1219
1220 rf_offset = d->part[part].offset + RF_PROTECTED_SECTORS;
1221 rf_size = d->part[part].size;
1222 if (read_gpt(&raidframe, rf_offset, rf_size) != 0)
1223 return RF_PROTECTED_SECTORS;
1224
1225 candidate = 0;
1226 for (i = 0; i < BIOSDISKNPART; i++) {
1227 if (raidframe.part[i].size == 0)
1228 continue;
1229 if (raidframe.part[i].fstype == FS_UNUSED)
1230 continue;
1231 #ifndef NO_GPT
1232 if (raidframe.part[i].attr & GPT_ENT_ATTR_BOOTME)
1233 candidate = i;
1234 #endif
1235 }
1236
1237 return RF_PROTECTED_SECTORS + raidframe.part[candidate].offset;
1238 }
1239 #endif
1240
1241 int
1242 biosdisk_open(struct open_file *f, ...)
1243 /* struct open_file *f, int biosdev, int partition */
1244 {
1245 va_list ap;
1246 struct biosdisk *d;
1247 int biosdev;
1248 int partition;
1249 int error = 0;
1250
1251 va_start(ap, f);
1252 biosdev = va_arg(ap, int);
1253 d = alloc_biosdisk(biosdev);
1254 if (d == NULL) {
1255 error = ENXIO;
1256 goto out;
1257 }
1258
1259 partition = va_arg(ap, int);
1260 #ifdef _STANDALONE
1261 bi_disk.biosdev = d->ll.dev;
1262 bi_disk.partition = partition;
1263 bi_disk.labelsector = -1;
1264
1265 bi_wedge.biosdev = d->ll.dev;
1266 bi_wedge.matchblk = -1;
1267 #endif
1268
1269 #if !defined(NO_DISKLABEL) || !defined(NO_GPT)
1270 error = read_partitions(d, 0, 0);
1271 if (error == -1) {
1272 error = 0;
1273 goto nolabel;
1274 }
1275 if (error)
1276 goto out;
1277
1278 if (partition >= BIOSDISKNPART ||
1279 d->part[partition].fstype == FS_UNUSED) {
1280 #ifdef DISK_DEBUG
1281 printf("illegal partition\n");
1282 #endif
1283 error = EPART;
1284 goto out;
1285 }
1286
1287 d->boff = d->part[partition].offset;
1288
1289 if (d->part[partition].fstype == FS_RAID)
1290 #ifndef NO_GPT
1291 d->boff += raidframe_part_offset(d, partition);
1292 #else
1293 d->boff += RF_PROTECTED_SECTORS;
1294 #endif
1295
1296 #ifdef _STANDALONE
1297 bi_wedge.startblk = d->part[partition].offset;
1298 bi_wedge.nblks = d->part[partition].size;
1299 #endif
1300
1301 nolabel:
1302 #endif
1303 #ifdef DISK_DEBUG
1304 printf("partition @%"PRId64"\n", d->boff);
1305 #endif
1306
1307 #ifdef _STANDALONE
1308 add_biosdisk_bootinfo();
1309 #endif
1310
1311 f->f_devdata = d;
1312 out:
1313 va_end(ap);
1314 if (error)
1315 dealloc_biosdisk(d);
1316 return error;
1317 }
1318
1319 #ifndef NO_GPT
1320 static int
1321 biosdisk_find_name(const char *fname, int *biosdev,
1322 daddr_t *offset, daddr_t *size)
1323 {
1324 struct biosdisk *d;
1325 char name[MAXDEVNAME + 1];
1326 char *sep;
1327 #ifndef NO_RAIDFRAME
1328 struct raidframe raidframe[RAIDFRAME_NDEV];
1329 int raidframe_count = 0;
1330 #endif
1331 int i;
1332 int part;
1333 int ret = -1;
1334
1335 /* Strip leadinf NAME= and cut after the coloon included */
1336 strlcpy(name, fname + 5, MAXDEVNAME);
1337 sep = strchr(name, ':');
1338 if (sep)
1339 *sep = '\0';
1340
1341 for (i = 0; i < MAX_BIOSDISKS; i++) {
1342 d = alloc(sizeof(*d));
1343 if (d == NULL) {
1344 printf("Out of memory\n");
1345 goto out;
1346 }
1347
1348 memset(d, 0, sizeof(*d));
1349 d->ll.dev = 0x80 + i; /* hd/cd */
1350 if (set_geometry(&d->ll, NULL))
1351 goto next_disk;
1352
1353 if (d->ll.type != BIOSDISK_TYPE_HD)
1354 goto next_disk;
1355
1356 if (read_partitions(d, 0, 0) != 0)
1357 goto next_disk;
1358
1359 for (part = 0; part < BIOSDISKNPART; part++) {
1360 if (d->part[part].size == 0)
1361 continue;
1362 if (d->part[part].fstype == FS_UNUSED)
1363 continue;
1364 #ifndef NO_RAIDFRAME
1365 if (d->part[part].fstype == FS_RAID) {
1366 raidframe_probe(raidframe,
1367 &raidframe_count, d, part);
1368 /*
1369 * Do not match RAID partition for a name,
1370 * we want to report an inner partition.
1371 */
1372 continue;
1373 }
1374 #endif
1375 if (d->part[part].part_name != NULL &&
1376 strcmp(d->part[part].part_name, name) == 0) {
1377 *biosdev = d->ll.dev;
1378 *offset = d->part[part].offset;
1379 *size = d->part[part].size;
1380 ret = 0;
1381 goto out;
1382 }
1383
1384 }
1385 next_disk:
1386 dealloc_biosdisk(d);
1387 d = NULL;
1388 }
1389
1390 #ifndef NO_RAIDFRAME
1391 for (i = 0; i < raidframe_count; i++) {
1392 int candidate = -1;
1393
1394 if ((d = alloc_biosdisk(raidframe[i].biosdev)) == NULL) {
1395 printf("Out of memory\n");
1396 goto out;
1397 }
1398
1399 if (read_partitions(d,
1400 raidframe[i].offset + RF_PROTECTED_SECTORS,
1401 raidframe[i].size) != 0)
1402 goto next_raidframe;
1403
1404 for (part = 0; part < BIOSDISKNPART; part++) {
1405 bool bootme = d->part[part].attr & GPT_ENT_ATTR_BOOTME;
1406 if (d->part[part].size == 0)
1407 continue;
1408 if (d->part[part].fstype == FS_UNUSED)
1409 continue;
1410 if (d->part[part].part_name == NULL)
1411 continue;
1412 if (strcmp(d->part[part].part_name, name) == 0) {
1413 *biosdev = raidframe[i].biosdev;
1414 *offset = raidframe[i].offset
1415 + RF_PROTECTED_SECTORS
1416 + d->part[part].offset;
1417 *size = d->part[part].size;
1418 ret = 0;
1419 goto out;
1420 }
1421 if (strcmp(raidframe[i].parent_name, name) == 0) {
1422 if (candidate == -1 || bootme)
1423 candidate = part;
1424 continue;
1425 }
1426 }
1427
1428 if (candidate != -1) {
1429 *biosdev = raidframe[i].biosdev;
1430 *offset = raidframe[i].offset
1431 + RF_PROTECTED_SECTORS
1432 + d->part[candidate].offset;
1433 *size = d->part[candidate].size;
1434 ret = 0;
1435 goto out;
1436 }
1437
1438 next_raidframe:
1439 dealloc_biosdisk(d);
1440 d = NULL;
1441 }
1442 #endif
1443
1444 out:
1445 if (d != NULL)
1446 dealloc_biosdisk(d);
1447
1448 return ret;
1449 }
1450 #endif
1451
1452 #ifndef NO_RAIDFRAME
1453 static int
1454 biosdisk_find_raid(const char *name, int *biosdev,
1455 daddr_t *offset, daddr_t *size)
1456 {
1457 struct biosdisk *d = NULL;
1458 struct raidframe raidframe[RAIDFRAME_NDEV];
1459 int raidframe_count = 0;
1460 int i;
1461 int target_unit = 0;
1462 int target_part;
1463 int part;
1464 int ret = -1;
1465
1466 if (strstr(name, "raid") != name)
1467 goto out;
1468
1469 #define isnum(c) ((c) >= '0' && (c) <= '9')
1470 i = 4; /* skip leading "raid" */
1471 if (!isnum(name[i]))
1472 goto out;
1473 do {
1474 target_unit *= 10;
1475 target_unit += name[i++] - '0';
1476 } while (isnum(name[i]));
1477
1478 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z')
1479
1480 if (!isvalidpart(name[i]))
1481 goto out;
1482 target_part = name[i] - 'a';
1483
1484 for (i = 0; i < MAX_BIOSDISKS; i++) {
1485 d = alloc(sizeof(*d));
1486 if (d == NULL) {
1487 printf("Out of memory\n");
1488 goto out;
1489 }
1490
1491 memset(d, 0, sizeof(*d));
1492 d->ll.dev = 0x80 + i; /* hd/cd */
1493 if (set_geometry(&d->ll, NULL))
1494 goto next_disk;
1495
1496 if (d->ll.type != BIOSDISK_TYPE_HD)
1497 goto next_disk;
1498
1499 if (read_partitions(d, 0, 0) != 0)
1500 goto next_disk;
1501
1502 for (part = 0; part < BIOSDISKNPART; part++) {
1503 if (d->part[part].size == 0)
1504 continue;
1505 if (d->part[part].fstype != FS_RAID)
1506 continue;
1507 raidframe_probe(raidframe,
1508 &raidframe_count, d, part);
1509
1510 }
1511 next_disk:
1512 dealloc_biosdisk(d);
1513 d = NULL;
1514 }
1515
1516 for (i = 0; i < raidframe_count; i++) {
1517 if (raidframe[i].last_unit != target_unit)
1518 continue;
1519
1520 if ((d = alloc_biosdisk(raidframe[i].biosdev)) == NULL) {
1521 printf("Out of memory\n");
1522 goto out;
1523 }
1524
1525 if (read_partitions(d,
1526 raidframe[i].offset + RF_PROTECTED_SECTORS,
1527 raidframe[i].size) != 0)
1528 goto next_raidframe;
1529
1530 for (part = 0; part < BIOSDISKNPART; part++) {
1531 if (d->part[part].size == 0)
1532 continue;
1533 if (d->part[part].fstype == FS_UNUSED)
1534 continue;
1535 if (part == target_part) {
1536 *biosdev = raidframe[i].biosdev;
1537 *offset = raidframe[i].offset
1538 + RF_PROTECTED_SECTORS
1539 + d->part[part].offset;
1540 *size = d->part[part].size;
1541 ret = 0;
1542 goto out;
1543 }
1544 }
1545 next_raidframe:
1546 dealloc_biosdisk(d);
1547 d = NULL;
1548 }
1549 out:
1550 if (d != NULL)
1551 dealloc_biosdisk(d);
1552
1553 return ret;
1554 }
1555 #endif
1556
1557 int
1558 biosdisk_open_name(struct open_file *f, const char *name)
1559 {
1560 #if defined(NO_GPT) && defined(NO_RAIDFRAME)
1561 return ENXIO;
1562 #else
1563 struct biosdisk *d = NULL;
1564 int biosdev;
1565 daddr_t offset;
1566 daddr_t size;
1567 int error = -1;
1568
1569 #ifndef NO_GPT
1570 if (strstr(name, "NAME=") == name)
1571 error = biosdisk_find_name(name, &biosdev, &offset, &size);
1572 #endif
1573 #ifndef NO_RAIDFRAME
1574 if (strstr(name, "raid") == name)
1575 error = biosdisk_find_raid(name, &biosdev, &offset, &size);
1576 #endif
1577
1578 if (error != 0) {
1579 printf("%s not found\n", name);
1580 error = ENXIO;
1581 goto out;
1582 }
1583
1584 d = alloc_biosdisk(biosdev);
1585 if (d == NULL) {
1586 error = ENXIO;
1587 goto out;
1588 }
1589
1590 #ifdef _STANDALONE
1591 bi_disk.biosdev = d->ll.dev;
1592 bi_disk.partition = 0;
1593 bi_disk.labelsector = -1;
1594
1595 bi_wedge.biosdev = d->ll.dev;
1596
1597 /*
1598 * If we did not get wedge match info from check_gpt()
1599 * compute it now.
1600 */
1601 if (bi_wedge.matchblk == -1) {
1602 if (readsects(&d->ll, offset, 1, d->buf, 1)) {
1603 #ifdef DISK_DEBUG
1604 printf("Error reading sector at %"PRId64"\n", offset);
1605 #endif
1606 error = EIO;
1607 goto out;
1608 }
1609
1610 bi_wedge.matchblk = offset;
1611 bi_wedge.matchnblks = 1;
1612
1613 md5(bi_wedge.matchhash, d->buf, d->ll.secsize);
1614 }
1615 #endif
1616
1617 d->boff = offset;
1618
1619 #ifdef _STANDALONE
1620 bi_wedge.startblk = offset;
1621 bi_wedge.nblks = size;
1622
1623 add_biosdisk_bootinfo();
1624 #endif
1625
1626 f->f_devdata = d;
1627 out:
1628 if (error && d != NULL)
1629 dealloc_biosdisk(d);
1630 return error;
1631 #endif
1632 }
1633
1634
1635
1636 #ifndef LIBSA_NO_FS_CLOSE
1637 int
1638 biosdisk_close(struct open_file *f)
1639 {
1640 struct biosdisk *d = f->f_devdata;
1641
1642 /* let the floppy drive go off */
1643 if (d->ll.type == BIOSDISK_TYPE_FD)
1644 wait_sec(3); /* 2s is enough on all PCs I found */
1645
1646 dealloc_biosdisk(d);
1647 f->f_devdata = NULL;
1648 return 0;
1649 }
1650 #endif
1651
1652 int
1653 biosdisk_ioctl(struct open_file *f, u_long cmd, void *arg)
1654 {
1655 return EIO;
1656 }
1657