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