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