1 /* $NetBSD: biosdisk.c,v 1.49 2018/04/02 09:44:18 nonaka 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 82 #include <lib/libsa/saerrno.h> 83 #include <machine/cpu.h> 84 85 #include "libi386.h" 86 #include "biosdisk_ll.h" 87 #include "biosdisk.h" 88 #ifdef _STANDALONE 89 #include "bootinfo.h" 90 #endif 91 92 #ifndef BIOSDISK_BUFSIZE 93 #define BIOSDISK_BUFSIZE 2048 /* must be large enough for a CD sector */ 94 #endif 95 96 #define BIOSDISKNPART 26 97 98 struct biosdisk { 99 struct biosdisk_ll ll; 100 daddr_t boff; 101 char buf[BIOSDISK_BUFSIZE]; 102 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 103 struct biosdisk_partition part[BIOSDISKNPART]; 104 #endif 105 }; 106 107 #ifndef NO_GPT 108 const struct uuid GET_nbsd_raid = GPT_ENT_TYPE_NETBSD_RAIDFRAME; 109 const struct uuid GET_nbsd_ffs = GPT_ENT_TYPE_NETBSD_FFS; 110 const struct uuid GET_nbsd_lfs = GPT_ENT_TYPE_NETBSD_LFS; 111 const struct uuid GET_nbsd_swap = GPT_ENT_TYPE_NETBSD_SWAP; 112 const struct uuid GET_nbsd_ccd = GPT_ENT_TYPE_NETBSD_CCD; 113 const struct uuid GET_nbsd_cgd = GPT_ENT_TYPE_NETBSD_CGD; 114 #ifdef EFIBOOT 115 const struct uuid GET_efi = GPT_ENT_TYPE_EFI; 116 const struct uuid GET_mbr = GPT_ENT_TYPE_MBR; 117 const struct uuid GET_fbsd = GPT_ENT_TYPE_FREEBSD; 118 const struct uuid GET_fbsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; 119 const struct uuid GET_fbsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; 120 const struct uuid GET_fbsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; 121 const struct uuid GET_fbsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; 122 const struct uuid GET_ms_rsvd = GPT_ENT_TYPE_MS_RESERVED; 123 const struct uuid GET_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA; 124 const struct uuid GET_ms_ldm_metadata = GPT_ENT_TYPE_MS_LDM_METADATA; 125 const struct uuid GET_ms_ldm_data = GPT_ENT_TYPE_MS_LDM_DATA; 126 const struct uuid GET_linux_data = GPT_ENT_TYPE_LINUX_DATA; 127 const struct uuid GET_linux_raid = GPT_ENT_TYPE_LINUX_RAID; 128 const struct uuid GET_linux_swap = GPT_ENT_TYPE_LINUX_SWAP; 129 const struct uuid GET_linux_lvm = GPT_ENT_TYPE_LINUX_LVM; 130 const struct uuid GET_apple_hfs = GPT_ENT_TYPE_APPLE_HFS; 131 const struct uuid GET_apple_ufs = GPT_ENT_TYPE_APPLE_UFS; 132 const struct uuid GET_bios = GPT_ENT_TYPE_BIOS; 133 134 const struct gpt_part gpt_parts[] = { 135 { &GET_nbsd_raid, "NetBSD RAID" }, 136 { &GET_nbsd_ffs, "NetBSD FFS" }, 137 { &GET_nbsd_lfs, "NetBSD LFS" }, 138 { &GET_nbsd_swap, "NetBSD Swap" }, 139 { &GET_nbsd_ccd, "NetBSD ccd" }, 140 { &GET_nbsd_cgd, "NetBSD cgd" }, 141 { &GET_efi, "EFI System" }, 142 { &GET_mbr, "MBR" }, 143 { &GET_fbsd, "FreeBSD" }, 144 { &GET_fbsd_swap, "FreeBSD Swap" }, 145 { &GET_fbsd_ufs, "FreeBSD UFS" }, 146 { &GET_fbsd_vinum, "FreeBSD Vinum" }, 147 { &GET_fbsd_zfs, "FreeBSD ZFS" }, 148 { &GET_ms_rsvd, "Microsoft Reserved" }, 149 { &GET_ms_basic_data, "Microsoft Basic data" }, 150 { &GET_ms_ldm_metadata, "Microsoft LDM metadata" }, 151 { &GET_ms_ldm_data, "Microsoft LDM data" }, 152 { &GET_linux_data, "Linux data" }, 153 { &GET_linux_raid, "Linux RAID" }, 154 { &GET_linux_swap, "Linux Swap" }, 155 { &GET_linux_lvm, "Linux LVM" }, 156 { &GET_apple_hfs, "Apple HFS" }, 157 { &GET_apple_ufs, "Apple UFS" }, 158 { &GET_bios, "BIOS Boot (GRUB)" }, 159 }; 160 #endif 161 #endif /* NO_GPT */ 162 163 #ifdef _STANDALONE 164 static struct btinfo_bootdisk bi_disk; 165 static struct btinfo_bootwedge bi_wedge; 166 #endif 167 168 #define MBR_PARTS(buf) ((char *)(buf) + offsetof(struct mbr_sector, mbr_parts)) 169 170 #define RF_PROTECTED_SECTORS 64 /* XXX refer to <.../rf_optnames.h> */ 171 172 #ifndef devb2cdb 173 #define devb2cdb(bno) (((bno) * DEV_BSIZE) / ISO_DEFAULT_BLOCK_SIZE) 174 #endif 175 176 int 177 biosdisk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, 178 void *buf, size_t *rsize) 179 { 180 struct biosdisk *d; 181 int blks, frag; 182 183 if (flag != F_READ) 184 return EROFS; 185 186 d = (struct biosdisk *) devdata; 187 188 if (d->ll.type == BIOSDISK_TYPE_CD) 189 dblk = devb2cdb(dblk); 190 191 dblk += d->boff; 192 193 blks = size / d->ll.secsize; 194 if (blks && readsects(&d->ll, dblk, blks, buf, 0)) { 195 if (rsize) 196 *rsize = 0; 197 return EIO; 198 } 199 200 /* needed for CD */ 201 frag = size % d->ll.secsize; 202 if (frag) { 203 if (readsects(&d->ll, dblk + blks, 1, d->buf, 0)) { 204 if (rsize) 205 *rsize = blks * d->ll.secsize; 206 return EIO; 207 } 208 memcpy(buf + blks * d->ll.secsize, d->buf, frag); 209 } 210 211 if (rsize) 212 *rsize = size; 213 return 0; 214 } 215 216 static struct biosdisk * 217 alloc_biosdisk(int biosdev) 218 { 219 struct biosdisk *d; 220 221 d = alloc(sizeof(*d)); 222 if (d == NULL) 223 return NULL; 224 memset(d, 0, sizeof(*d)); 225 226 d->ll.dev = biosdev; 227 if (set_geometry(&d->ll, NULL)) { 228 #ifdef DISK_DEBUG 229 printf("no geometry information\n"); 230 #endif 231 dealloc(d, sizeof(*d)); 232 return NULL; 233 } 234 return d; 235 } 236 237 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 238 static void 239 md5(void *hash, const void *data, size_t len) 240 { 241 MD5_CTX ctx; 242 243 MD5Init(&ctx); 244 MD5Update(&ctx, data, len); 245 MD5Final(hash, &ctx); 246 247 return; 248 } 249 #endif 250 251 #ifndef NO_GPT 252 bool 253 guid_is_nil(const struct uuid *u) 254 { 255 static const struct uuid nil = { .time_low = 0 }; 256 return (memcmp(u, &nil, sizeof(*u)) == 0 ? true : false); 257 } 258 259 bool 260 guid_is_equal(const struct uuid *a, const struct uuid *b) 261 { 262 return (memcmp(a, b, sizeof(*a)) == 0 ? true : false); 263 } 264 265 static int 266 check_gpt(struct biosdisk *d, daddr_t sector) 267 { 268 struct gpt_hdr gpth; 269 const struct gpt_ent *ep; 270 const struct uuid *u; 271 daddr_t entblk; 272 size_t size; 273 uint32_t crc; 274 int sectors; 275 int entries; 276 int entry; 277 int i, j; 278 279 /* read in gpt_hdr sector */ 280 if (readsects(&d->ll, sector, 1, d->buf, 1)) { 281 #ifdef DISK_DEBUG 282 printf("Error reading GPT header at %"PRId64"\n", sector); 283 #endif 284 return EIO; 285 } 286 287 memcpy(&gpth, d->buf, sizeof(gpth)); 288 289 if (memcmp(GPT_HDR_SIG, gpth.hdr_sig, sizeof(gpth.hdr_sig))) 290 return -1; 291 292 crc = gpth.hdr_crc_self; 293 gpth.hdr_crc_self = 0; 294 gpth.hdr_crc_self = crc32(0, (const void *)&gpth, GPT_HDR_SIZE); 295 if (gpth.hdr_crc_self != crc) { 296 return -1; 297 } 298 299 if (gpth.hdr_lba_self != sector) 300 return -1; 301 302 #ifdef _STANDALONE 303 bi_wedge.matchblk = sector; 304 bi_wedge.matchnblks = 1; 305 306 md5(bi_wedge.matchhash, d->buf, d->ll.secsize); 307 #endif 308 309 sectors = sizeof(d->buf)/d->ll.secsize; /* sectors per buffer */ 310 entries = sizeof(d->buf)/gpth.hdr_entsz; /* entries per buffer */ 311 entblk = gpth.hdr_lba_table; 312 crc = crc32(0, NULL, 0); 313 314 j = 0; 315 ep = (const struct gpt_ent *)d->buf; 316 317 for (entry = 0; entry < gpth.hdr_entries; entry += entries) { 318 size = MIN(sizeof(d->buf), 319 (gpth.hdr_entries - entry) * gpth.hdr_entsz); 320 entries = size / gpth.hdr_entsz; 321 sectors = roundup(size, d->ll.secsize) / d->ll.secsize; 322 if (readsects(&d->ll, entblk, sectors, d->buf, 1)) 323 return -1; 324 entblk += sectors; 325 crc = crc32(crc, (const void *)d->buf, size); 326 327 for (i = 0; j < BIOSDISKNPART && i < entries; i++) { 328 u = (const struct uuid *)ep[i].ent_type; 329 if (!guid_is_nil(u)) { 330 d->part[j].offset = ep[i].ent_lba_start; 331 d->part[j].size = ep[i].ent_lba_end - 332 ep[i].ent_lba_start + 1; 333 if (guid_is_equal(u, &GET_nbsd_ffs)) 334 d->part[j].fstype = FS_BSDFFS; 335 else if (guid_is_equal(u, &GET_nbsd_lfs)) 336 d->part[j].fstype = FS_BSDLFS; 337 else if (guid_is_equal(u, &GET_nbsd_raid)) 338 d->part[j].fstype = FS_RAID; 339 else if (guid_is_equal(u, &GET_nbsd_swap)) 340 d->part[j].fstype = FS_SWAP; 341 else if (guid_is_equal(u, &GET_nbsd_ccd)) 342 d->part[j].fstype = FS_CCD; 343 else if (guid_is_equal(u, &GET_nbsd_cgd)) 344 d->part[j].fstype = FS_CGD; 345 else 346 d->part[j].fstype = FS_OTHER; 347 #ifdef EFIBOOT 348 for (int k = 0; 349 k < __arraycount(gpt_parts); 350 k++) { 351 if (guid_is_equal(u, gpt_parts[k].guid)) 352 d->part[j].guid = &gpt_parts[k]; 353 } 354 d->part[j].attr = ep[i].ent_attr; 355 #endif 356 j++; 357 } 358 } 359 360 } 361 362 if (crc != gpth.hdr_crc_table) { 363 #ifdef DISK_DEBUG 364 printf("GPT table CRC invalid\n"); 365 #endif 366 return -1; 367 } 368 369 return 0; 370 } 371 372 static int 373 read_gpt(struct biosdisk *d) 374 { 375 struct biosdisk_extinfo ed; 376 daddr_t gptsector[2]; 377 int i, error; 378 379 if (d->ll.type != BIOSDISK_TYPE_HD) 380 /* No GPT on floppy and CD */ 381 return -1; 382 383 gptsector[0] = GPT_HDR_BLKNO; 384 if (set_geometry(&d->ll, &ed) == 0 && d->ll.flags & BIOSDISK_INT13EXT) { 385 gptsector[1] = ed.totsec - 1; 386 /* Sanity check values returned from BIOS */ 387 if (ed.sbytes >= 512 && (ed.sbytes & (ed.sbytes - 1)) == 0) 388 d->ll.secsize = ed.sbytes; 389 } else { 390 #ifdef DISK_DEBUG 391 printf("Unable to determine extended disk geometry - " 392 "using CHS\n"); 393 #endif 394 /* at least try some other reasonable values then */ 395 gptsector[1] = d->ll.chs_sectors - 1; 396 } 397 398 for (i = 0; i < __arraycount(gptsector); i++) { 399 error = check_gpt(d, gptsector[i]); 400 if (error == 0) 401 break; 402 } 403 404 if (i >= __arraycount(gptsector)) { 405 memset(d->part, 0, sizeof(d->part)); 406 return -1; 407 } 408 409 #ifndef USE_SECONDARY_GPT 410 if (i > 0) { 411 #ifdef DISK_DEBUG 412 printf("ignoring valid secondary GPT\n"); 413 #endif 414 return -1; 415 } 416 #endif 417 418 #ifdef DISK_DEBUG 419 printf("using %s GPT\n", (i == 0) ? "primary" : "secondary"); 420 #endif 421 return 0; 422 } 423 #endif /* !NO_GPT */ 424 425 #ifndef NO_DISKLABEL 426 static void 427 ingest_label(struct biosdisk *d, struct disklabel *lp) 428 { 429 int part; 430 431 memset(d->part, 0, sizeof(d->part)); 432 433 for (part = 0; part < lp->d_npartitions; part++) { 434 if (lp->d_partitions[part].p_size == 0) 435 continue; 436 if (lp->d_partitions[part].p_fstype == FS_UNUSED) 437 continue; 438 d->part[part].fstype = lp->d_partitions[part].p_fstype; 439 d->part[part].offset = lp->d_partitions[part].p_offset; 440 d->part[part].size = lp->d_partitions[part].p_size; 441 } 442 } 443 444 static int 445 check_label(struct biosdisk *d, daddr_t sector) 446 { 447 struct disklabel *lp; 448 449 /* find partition in NetBSD disklabel */ 450 if (readsects(&d->ll, sector + LABELSECTOR, 1, d->buf, 0)) { 451 #ifdef DISK_DEBUG 452 printf("Error reading disklabel\n"); 453 #endif 454 return EIO; 455 } 456 lp = (struct disklabel *) (d->buf + LABELOFFSET); 457 if (lp->d_magic != DISKMAGIC || dkcksum(lp)) { 458 #ifdef DISK_DEBUG 459 printf("warning: no disklabel in sector %"PRId64"\n", sector); 460 #endif 461 return -1; 462 } 463 464 ingest_label(d, lp); 465 466 #ifdef _STANDALONE 467 bi_disk.labelsector = sector + LABELSECTOR; 468 bi_disk.label.type = lp->d_type; 469 memcpy(bi_disk.label.packname, lp->d_packname, 16); 470 bi_disk.label.checksum = lp->d_checksum; 471 472 bi_wedge.matchblk = sector + LABELSECTOR; 473 bi_wedge.matchnblks = 1; 474 475 md5(bi_wedge.matchhash, d->buf, d->ll.secsize); 476 #endif 477 478 return 0; 479 } 480 481 static int 482 read_minix_subp(struct biosdisk *d, struct disklabel* dflt_lbl, 483 int this_ext, daddr_t sector) 484 { 485 struct mbr_partition mbr[MBR_PART_COUNT]; 486 int i; 487 int typ; 488 struct partition *p; 489 490 if (readsects(&d->ll, sector, 1, d->buf, 0)) { 491 #ifdef DISK_DEBUG 492 printf("Error reading MFS sector %"PRId64"\n", sector); 493 #endif 494 return EIO; 495 } 496 if ((uint8_t)d->buf[510] != 0x55 || (uint8_t)d->buf[511] != 0xAA) { 497 return -1; 498 } 499 memcpy(&mbr, MBR_PARTS(d->buf), sizeof(mbr)); 500 for (i = 0; i < MBR_PART_COUNT; i++) { 501 typ = mbr[i].mbrp_type; 502 if (typ == 0) 503 continue; 504 sector = this_ext + mbr[i].mbrp_start; 505 if (dflt_lbl->d_npartitions >= MAXPARTITIONS) 506 continue; 507 p = &dflt_lbl->d_partitions[dflt_lbl->d_npartitions++]; 508 p->p_offset = sector; 509 p->p_size = mbr[i].mbrp_size; 510 p->p_fstype = xlat_mbr_fstype(typ); 511 } 512 return 0; 513 } 514 515 #if defined(EFIBOOT) && defined(SUPPORT_CD9660) 516 static int 517 check_cd9660(struct biosdisk *d) 518 { 519 struct biosdisk_extinfo ed; 520 struct iso_primary_descriptor *vd; 521 daddr_t bno; 522 523 for (bno = 16;; bno++) { 524 if (readsects(&d->ll, bno, 1, d->buf, 0)) 525 return -1; 526 vd = (struct iso_primary_descriptor *)d->buf; 527 if (memcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) 528 return -1; 529 if (isonum_711(vd->type) == ISO_VD_END) 530 return -1; 531 if (isonum_711(vd->type) == ISO_VD_PRIMARY) 532 break; 533 } 534 if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) 535 return -1; 536 537 if (set_geometry(&d->ll, &ed)) 538 return -1; 539 540 memset(d->part, 0, sizeof(d->part)); 541 d->part[0].fstype = FS_ISO9660; 542 d->part[0].offset = 0; 543 d->part[0].size = ed.totsec; 544 return 0; 545 } 546 #endif 547 548 static int 549 read_label(struct biosdisk *d) 550 { 551 struct disklabel dflt_lbl; 552 struct mbr_partition mbr[MBR_PART_COUNT]; 553 struct partition *p; 554 uint32_t sector; 555 int i; 556 int error; 557 int typ; 558 uint32_t ext_base, this_ext, next_ext; 559 #ifdef COMPAT_386BSD_MBRPART 560 int sector_386bsd = -1; 561 #endif 562 563 memset(&dflt_lbl, 0, sizeof(dflt_lbl)); 564 dflt_lbl.d_npartitions = 8; 565 566 d->boff = 0; 567 568 if (d->ll.type != BIOSDISK_TYPE_HD) 569 /* No label on floppy and CD */ 570 return -1; 571 572 /* 573 * find NetBSD Partition in DOS partition table 574 * XXX check magic??? 575 */ 576 ext_base = 0; 577 next_ext = 0; 578 for (;;) { 579 this_ext = ext_base + next_ext; 580 next_ext = 0; 581 if (readsects(&d->ll, this_ext, 1, d->buf, 0)) { 582 #ifdef DISK_DEBUG 583 printf("error reading MBR sector %u\n", this_ext); 584 #endif 585 return EIO; 586 } 587 memcpy(&mbr, MBR_PARTS(d->buf), sizeof(mbr)); 588 /* Look for NetBSD partition ID */ 589 for (i = 0; i < MBR_PART_COUNT; i++) { 590 typ = mbr[i].mbrp_type; 591 if (typ == 0) 592 continue; 593 sector = this_ext + mbr[i].mbrp_start; 594 #ifdef DISK_DEBUG 595 printf("ptn type %d in sector %u\n", typ, sector); 596 #endif 597 if (typ == MBR_PTYPE_MINIX_14B) { 598 if (!read_minix_subp(d, &dflt_lbl, 599 this_ext, sector)) { 600 /* Don't add "container" partition */ 601 continue; 602 } 603 } 604 if (typ == MBR_PTYPE_NETBSD) { 605 error = check_label(d, sector); 606 if (error >= 0) 607 return error; 608 } 609 if (MBR_IS_EXTENDED(typ)) { 610 next_ext = mbr[i].mbrp_start; 611 continue; 612 } 613 #ifdef COMPAT_386BSD_MBRPART 614 if (this_ext == 0 && typ == MBR_PTYPE_386BSD) 615 sector_386bsd = sector; 616 #endif 617 if (this_ext != 0) { 618 if (dflt_lbl.d_npartitions >= MAXPARTITIONS) 619 continue; 620 p = &dflt_lbl.d_partitions[dflt_lbl.d_npartitions++]; 621 } else 622 p = &dflt_lbl.d_partitions[i]; 623 p->p_offset = sector; 624 p->p_size = mbr[i].mbrp_size; 625 p->p_fstype = xlat_mbr_fstype(typ); 626 } 627 if (next_ext == 0) 628 break; 629 if (ext_base == 0) { 630 ext_base = next_ext; 631 next_ext = 0; 632 } 633 } 634 635 sector = 0; 636 #ifdef COMPAT_386BSD_MBRPART 637 if (sector_386bsd != -1) { 638 printf("old BSD partition ID!\n"); 639 sector = sector_386bsd; 640 } 641 #endif 642 643 /* 644 * One of two things: 645 * 1. no MBR 646 * 2. no NetBSD partition in MBR 647 * 648 * We simply default to "start of disk" in this case and 649 * press on. 650 */ 651 error = check_label(d, sector); 652 if (error >= 0) 653 return error; 654 655 #if defined(EFIBOOT) && defined(SUPPORT_CD9660) 656 /* Check CD/DVD */ 657 error = check_cd9660(d); 658 if (error >= 0) 659 return error; 660 #endif 661 662 /* 663 * Nothing at start of disk, return info from mbr partitions. 664 */ 665 /* XXX fill it to make checksum match kernel one */ 666 dflt_lbl.d_checksum = dkcksum(&dflt_lbl); 667 ingest_label(d, &dflt_lbl); 668 return 0; 669 } 670 #endif /* NO_DISKLABEL */ 671 672 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 673 static int 674 read_partitions(struct biosdisk *d) 675 { 676 int error; 677 678 error = -1; 679 680 #ifndef NO_GPT 681 error = read_gpt(d); 682 if (error == 0) 683 return 0; 684 685 #endif 686 #ifndef NO_DISKLABEL 687 error = read_label(d); 688 689 #endif 690 return error; 691 } 692 #endif 693 694 void 695 biosdisk_probe(void) 696 { 697 struct biosdisk d; 698 struct biosdisk_extinfo ed; 699 uint64_t size; 700 int first; 701 int i; 702 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 703 int part; 704 #endif 705 706 for (i = 0; i < MAX_BIOSDISKS + 2; i++) { 707 first = 1; 708 memset(&d, 0, sizeof(d)); 709 memset(&ed, 0, sizeof(ed)); 710 if (i >= MAX_BIOSDISKS) 711 d.ll.dev = 0x00 + i - MAX_BIOSDISKS; /* fd */ 712 else 713 d.ll.dev = 0x80 + i; /* hd/cd */ 714 if (set_geometry(&d.ll, &ed)) 715 continue; 716 printf("disk "); 717 switch (d.ll.type) { 718 case BIOSDISK_TYPE_CD: 719 printf("cd0\n cd0a\n"); 720 break; 721 case BIOSDISK_TYPE_FD: 722 printf("fd%d\n", d.ll.dev & 0x7f); 723 printf(" fd%da\n", d.ll.dev & 0x7f); 724 break; 725 case BIOSDISK_TYPE_HD: 726 printf("hd%d", d.ll.dev & 0x7f); 727 if (d.ll.flags & BIOSDISK_INT13EXT) { 728 printf(" size "); 729 size = ed.totsec * ed.sbytes; 730 if (size >= (10ULL * 1024 * 1024 * 1024)) 731 printf("%"PRIu64" GB", 732 size / (1024 * 1024 * 1024)); 733 else 734 printf("%"PRIu64" MB", 735 size / (1024 * 1024)); 736 } 737 printf("\n"); 738 break; 739 } 740 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 741 if (d.ll.type != BIOSDISK_TYPE_HD) 742 continue; 743 744 if (read_partitions(&d) != 0) 745 continue; 746 747 for (part = 0; part < BIOSDISKNPART; part++) { 748 if (d.part[part].size == 0) 749 continue; 750 if (d.part[part].fstype == FS_UNUSED) 751 continue; 752 if (first) { 753 printf(" "); 754 first = 0; 755 } 756 printf(" hd%d%c(", d.ll.dev & 0x7f, part + 'a'); 757 #ifdef EFIBOOT 758 if (d.part[part].guid != NULL) 759 printf("%s", d.part[part].guid->name); 760 else 761 #endif 762 if (d.part[part].fstype < FSMAXTYPES) 763 printf("%s", 764 fstypenames[d.part[part].fstype]); 765 else 766 printf("%d", d.part[part].fstype); 767 printf(")"); 768 } 769 #endif 770 if (first == 0) 771 printf("\n"); 772 } 773 } 774 775 /* Determine likely partition for possible sector number of dos 776 * partition. 777 */ 778 779 int 780 biosdisk_findpartition(int biosdev, daddr_t sector) 781 { 782 #if defined(NO_DISKLABEL) && defined(NO_GPT) 783 return 0; 784 #else 785 struct biosdisk *d; 786 int partition = 0; 787 #ifdef EFIBOOT 788 int candidate = 0; 789 #endif 790 791 #ifdef DISK_DEBUG 792 printf("looking for partition device %x, sector %"PRId64"\n", biosdev, sector); 793 #endif 794 795 /* Look for netbsd partition that is the dos boot one */ 796 d = alloc_biosdisk(biosdev); 797 if (d == NULL) 798 return 0; 799 800 if (read_partitions(d) == 0) { 801 for (partition = (BIOSDISKNPART-1); --partition;) { 802 if (d->part[partition].fstype == FS_UNUSED) 803 continue; 804 #ifdef EFIBOOT 805 switch (d->part[partition].fstype) { 806 case FS_BSDFFS: 807 case FS_BSDLFS: 808 case FS_RAID: 809 case FS_CCD: 810 case FS_CGD: 811 case FS_ISO9660: 812 if (d->part[partition].attr & GPT_ENT_ATTR_BOOTME) 813 goto found; 814 candidate = partition; 815 break; 816 817 default: 818 if (d->part[partition].attr & GPT_ENT_ATTR_BOOTME) 819 candidate = partition; 820 break; 821 } 822 #else 823 if (d->part[partition].offset == sector) 824 break; 825 #endif 826 } 827 #ifdef EFIBOOT 828 found: 829 if (partition == 0 && candidate != 0) 830 partition = candidate; 831 #endif 832 } 833 834 dealloc(d, sizeof(*d)); 835 return partition; 836 #endif /* NO_DISKLABEL && NO_GPT */ 837 } 838 839 int 840 biosdisk_readpartition(int biosdev, struct biosdisk_partition **partpp, 841 int *rnum) 842 { 843 #if defined(NO_DISKLABEL) && defined(NO_GPT) 844 return ENOTSUP; 845 #else 846 struct biosdisk *d; 847 struct biosdisk_partition *part; 848 int rv; 849 850 /* Look for netbsd partition that is the dos boot one */ 851 d = alloc_biosdisk(biosdev); 852 if (d == NULL) 853 return ENOMEM; 854 855 if (read_partitions(d)) { 856 rv = EINVAL; 857 goto out; 858 } 859 860 part = alloc(sizeof(d->part)); 861 if (part == NULL) { 862 rv = ENOMEM; 863 goto out; 864 } 865 866 memcpy(part, d->part, sizeof(d->part)); 867 *partpp = part; 868 *rnum = (int)__arraycount(d->part); 869 rv = 0; 870 out: 871 dealloc(d, sizeof(*d)); 872 return rv; 873 #endif /* NO_DISKLABEL && NO_GPT */ 874 } 875 876 #ifdef _STANDALONE 877 static void 878 add_biosdisk_bootinfo(void) 879 { 880 if (bootinfo == NULL) { 881 return; 882 } 883 BI_ADD(&bi_disk, BTINFO_BOOTDISK, sizeof(bi_disk)); 884 BI_ADD(&bi_wedge, BTINFO_BOOTWEDGE, sizeof(bi_wedge)); 885 return; 886 } 887 #endif 888 889 int 890 biosdisk_open(struct open_file *f, ...) 891 /* struct open_file *f, int biosdev, int partition */ 892 { 893 va_list ap; 894 struct biosdisk *d; 895 int biosdev; 896 int partition; 897 int error = 0; 898 899 va_start(ap, f); 900 biosdev = va_arg(ap, int); 901 d = alloc_biosdisk(biosdev); 902 if (d == NULL) { 903 error = ENXIO; 904 goto out; 905 } 906 907 partition = va_arg(ap, int); 908 #ifdef _STANDALONE 909 bi_disk.biosdev = d->ll.dev; 910 bi_disk.partition = partition; 911 bi_disk.labelsector = -1; 912 913 bi_wedge.biosdev = d->ll.dev; 914 bi_wedge.matchblk = -1; 915 #endif 916 917 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 918 error = read_partitions(d); 919 if (error == -1) { 920 error = 0; 921 goto nolabel; 922 } 923 if (error) 924 goto out; 925 926 if (partition >= BIOSDISKNPART || 927 d->part[partition].fstype == FS_UNUSED) { 928 #ifdef DISK_DEBUG 929 printf("illegal partition\n"); 930 #endif 931 error = EPART; 932 goto out; 933 } 934 935 d->boff = d->part[partition].offset; 936 937 if (d->part[partition].fstype == FS_RAID) 938 d->boff += RF_PROTECTED_SECTORS; 939 940 #ifdef _STANDALONE 941 bi_wedge.startblk = d->part[partition].offset; 942 bi_wedge.nblks = d->part[partition].size; 943 #endif 944 945 nolabel: 946 #endif 947 #ifdef DISK_DEBUG 948 printf("partition @%"PRId64"\n", d->boff); 949 #endif 950 951 #ifdef _STANDALONE 952 add_biosdisk_bootinfo(); 953 #endif 954 955 f->f_devdata = d; 956 out: 957 va_end(ap); 958 if (error) 959 dealloc(d, sizeof(*d)); 960 return error; 961 } 962 963 #ifndef LIBSA_NO_FS_CLOSE 964 int 965 biosdisk_close(struct open_file *f) 966 { 967 struct biosdisk *d = f->f_devdata; 968 969 /* let the floppy drive go off */ 970 if (d->ll.type == BIOSDISK_TYPE_FD) 971 wait_sec(3); /* 2s is enough on all PCs I found */ 972 973 dealloc(d, sizeof(*d)); 974 f->f_devdata = NULL; 975 return 0; 976 } 977 #endif 978 979 int 980 biosdisk_ioctl(struct open_file *f, u_long cmd, void *arg) 981 { 982 return EIO; 983 } 984