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