1 /* $OpenBSD: efidev.c,v 1.19 2016/08/31 15:11:22 yasuoka Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Michael Shalayeff 5 * Copyright (c) 2003 Tobias Weingartner 6 * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 #include <sys/param.h> 32 #include <sys/reboot.h> 33 #include <sys/disklabel.h> 34 #include <lib/libz/zlib.h> 35 #include <isofs/cd9660/iso.h> 36 37 #include "libsa.h" 38 #include "disk.h" 39 40 #ifdef SOFTRAID 41 #include <dev/softraidvar.h> 42 #include "softraid.h" 43 #endif 44 45 #include <efi.h> 46 #include "eficall.h" 47 48 extern int debug; 49 50 #include "efidev.h" 51 #include "biosdev.h" /* for dklookup() */ 52 53 #define EFI_BLKSPERSEC(_ed) ((_ed)->blkio->Media->BlockSize / DEV_BSIZE) 54 #define EFI_SECTOBLK(_ed, _n) ((_n) * EFI_BLKSPERSEC(_ed)) 55 56 struct efi_diskinfo { 57 EFI_BLOCK_IO *blkio; 58 UINT32 mediaid; 59 }; 60 61 int bios_bootdev; 62 static EFI_STATUS 63 efid_io(int, efi_diskinfo_t, u_int, int, void *); 64 static int efid_diskio(int, struct diskinfo *, u_int, int, void *); 65 static int efi_getdisklabel_cd9660(efi_diskinfo_t, struct disklabel *); 66 static u_int findopenbsd(efi_diskinfo_t, const char **); 67 static u_int findopenbsd_gpt(efi_diskinfo_t, const char **); 68 static int gpt_chk_mbr(struct dos_partition *, u_int64_t); 69 70 void 71 efid_init(struct diskinfo *dip, void *handle) 72 { 73 EFI_BLOCK_IO *blkio = handle; 74 75 memset(dip, 0, sizeof(struct diskinfo)); 76 dip->efi_info = alloc(sizeof(struct efi_diskinfo)); 77 dip->efi_info->blkio = blkio; 78 dip->efi_info->mediaid = blkio->Media->MediaId; 79 dip->diskio = efid_diskio; 80 dip->strategy = efistrategy; 81 } 82 83 static EFI_STATUS 84 efid_io(int rw, efi_diskinfo_t ed, u_int off, int nsect, void *buf) 85 { 86 u_int blks, lba, i_lblks, i_tblks, i_nblks; 87 EFI_STATUS status = EFI_SUCCESS; 88 static u_char *iblk = NULL; 89 static u_int iblksz = 0; 90 91 /* block count of the intrisic block size in DEV_BSIZE */ 92 blks = EFI_BLKSPERSEC(ed); 93 if (blks == 0) 94 /* block size < 512. HP Stream 13 actually has such a disk. */ 95 return (EFI_UNSUPPORTED); 96 lba = off / blks; 97 98 /* leading and trailing unaligned blocks in intrisic block */ 99 i_lblks = ((off % blks) == 0)? 0 : blks - (off % blks); 100 i_tblks = (off + nsect) % blks; 101 102 /* aligned blocks in intrisic block */ 103 i_nblks = nsect - (i_lblks + i_tblks); 104 105 switch (rw) { 106 case F_READ: 107 /* allocate the space for reading unaligned blocks */ 108 if (ed->blkio->Media->BlockSize != DEV_BSIZE) { 109 if (iblk && iblksz < ed->blkio->Media->BlockSize) { 110 free(iblk, iblksz); 111 iblk = NULL; 112 } 113 if (iblk == NULL) { 114 iblk = alloc(ed->blkio->Media->BlockSize); 115 iblksz = ed->blkio->Media->BlockSize; 116 } 117 } 118 if (i_lblks > 0) { 119 status = EFI_CALL(ed->blkio->ReadBlocks, 120 ed->blkio, ed->mediaid, lba - 1, 121 ed->blkio->Media->BlockSize, iblk); 122 if (EFI_ERROR(status)) 123 goto on_eio; 124 memcpy(buf, iblk + (blks - i_lblks), 125 i_lblks * DEV_BSIZE); 126 } 127 if (i_nblks > 0) { 128 status = EFI_CALL(ed->blkio->ReadBlocks, 129 ed->blkio, ed->mediaid, lba, 130 ed->blkio->Media->BlockSize * (i_nblks / blks), 131 buf + (i_lblks * DEV_BSIZE)); 132 if (EFI_ERROR(status)) 133 goto on_eio; 134 } 135 if (i_tblks > 0) { 136 status = EFI_CALL(ed->blkio->ReadBlocks, 137 ed->blkio, ed->mediaid, lba + (i_nblks / blks), 138 ed->blkio->Media->BlockSize, iblk); 139 if (EFI_ERROR(status)) 140 goto on_eio; 141 memcpy(buf + (i_lblks + i_nblks) * DEV_BSIZE, iblk, 142 i_tblks * DEV_BSIZE); 143 } 144 break; 145 case F_WRITE: 146 if (ed->blkio->Media->ReadOnly) 147 goto on_eio; 148 /* XXX not yet */ 149 goto on_eio; 150 break; 151 } 152 return (EFI_SUCCESS); 153 154 on_eio: 155 return (status); 156 } 157 158 static int 159 efid_diskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf) 160 { 161 EFI_STATUS status; 162 163 status = efid_io(rw, dip->efi_info, off, nsect, buf); 164 165 return ((EFI_ERROR(status))? -1 : 0); 166 } 167 168 /* 169 * Returns 0 if the MBR with the provided partition array is a GPT protective 170 * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only 171 * one MBR partition, an EFI partition that either covers the whole disk or as 172 * much of it as is possible with a 32bit size field. 173 * 174 * Taken from kern/subr_disk.c. 175 * 176 * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!** 177 */ 178 static int 179 gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) 180 { 181 struct dos_partition *dp2; 182 int efi, found, i; 183 u_int32_t psize; 184 185 found = efi = 0; 186 for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) { 187 if (dp2->dp_typ == DOSPTYP_UNUSED) 188 continue; 189 found++; 190 if (dp2->dp_typ != DOSPTYP_EFI) 191 continue; 192 psize = letoh32(dp2->dp_size); 193 if (psize == (dsize - 1) || 194 psize == UINT32_MAX) { 195 if (letoh32(dp2->dp_start) == 1) 196 efi++; 197 } 198 } 199 if (found == 1 && efi == 1) 200 return (0); 201 202 return (1); 203 } 204 205 /* 206 * Try to find the disk address of the first MBR OpenBSD partition. 207 * 208 * N.B.: must boot from a partition within first 2^32-1 sectors! 209 * 210 * Called only if the MBR on sector 0 is *not* a protective MBR 211 * and *does* have a valid signature. 212 * 213 * We don't check the signatures of EBR's, and they cannot be 214 * protective MBR's so there is no need to check for that. 215 */ 216 static u_int 217 findopenbsd(efi_diskinfo_t ed, const char **err) 218 { 219 EFI_STATUS status; 220 struct dos_mbr mbr; 221 struct dos_partition *dp; 222 u_int mbroff = DOSBBSECTOR; 223 u_int mbr_eoff = DOSBBSECTOR; /* Offset of MBR extended partition. */ 224 int i, maxebr = DOS_MAXEBR, nextebr; 225 226 again: 227 if (!maxebr--) { 228 *err = "too many extended partitions"; 229 return (-1); 230 } 231 232 /* Read MBR */ 233 bzero(&mbr, sizeof(mbr)); 234 status = efid_io(F_READ, ed, mbroff, 1, &mbr); 235 if (EFI_ERROR(status)) { 236 *err = "Disk I/O Error"; 237 return (-1); 238 } 239 240 /* Search for OpenBSD partition */ 241 nextebr = 0; 242 for (i = 0; i < NDOSPART; i++) { 243 dp = &mbr.dmbr_parts[i]; 244 if (!dp->dp_size) 245 continue; 246 #ifdef BIOS_DEBUG 247 if (debug) 248 printf("found partition %u: " 249 "type %u (0x%x) offset %u (0x%x)\n", 250 (int)(dp - mbr.dmbr_parts), 251 dp->dp_typ, dp->dp_typ, 252 dp->dp_start, dp->dp_start); 253 #endif 254 if (dp->dp_typ == DOSPTYP_OPENBSD) { 255 if (dp->dp_start > (dp->dp_start + mbroff)) 256 continue; 257 return (dp->dp_start + mbroff); 258 } 259 260 /* 261 * Record location of next ebr if and only if this is the first 262 * extended partition in this boot record! 263 */ 264 if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND || 265 dp->dp_typ == DOSPTYP_EXTENDL)) { 266 nextebr = dp->dp_start + mbr_eoff; 267 if (nextebr < dp->dp_start) 268 nextebr = (u_int)-1; 269 if (mbr_eoff == DOSBBSECTOR) 270 mbr_eoff = dp->dp_start; 271 } 272 } 273 274 if (nextebr && nextebr != (u_int)-1) { 275 mbroff = nextebr; 276 goto again; 277 } 278 279 return (-1); 280 } 281 282 /* 283 * Try to find the disk address of the first GPT OpenBSD partition. 284 * 285 * N.B.: must boot from a partition within first 2^32-1 sectors! 286 * 287 * Called only if the MBR on sector 0 *is* a protective MBR 288 * with a valid signature and sector 1 is a valid GPT header. 289 */ 290 static u_int 291 findopenbsd_gpt(efi_diskinfo_t ed, const char **err) 292 { 293 EFI_STATUS status; 294 struct gpt_header gh; 295 int i, part, found; 296 uint64_t lba; 297 uint32_t orig_csum, new_csum; 298 uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec; 299 uint32_t gpsectors; 300 const char openbsd_uuid_code[] = GPT_UUID_OPENBSD; 301 struct gpt_partition gp; 302 static struct uuid *openbsd_uuid = NULL, openbsd_uuid_space; 303 static u_char buf[4096]; 304 305 /* Prepare OpenBSD UUID */ 306 if (openbsd_uuid == NULL) { 307 /* XXX: should be replaced by uuid_dec_be() */ 308 memcpy(&openbsd_uuid_space, openbsd_uuid_code, 309 sizeof(openbsd_uuid_space)); 310 openbsd_uuid_space.time_low = 311 betoh32(openbsd_uuid_space.time_low); 312 openbsd_uuid_space.time_mid = 313 betoh16(openbsd_uuid_space.time_mid); 314 openbsd_uuid_space.time_hi_and_version = 315 betoh16(openbsd_uuid_space.time_hi_and_version); 316 317 openbsd_uuid = &openbsd_uuid_space; 318 } 319 320 if (EFI_BLKSPERSEC(ed) > 8) { 321 *err = "disk sector > 4096 bytes\n"; 322 return (-1); 323 } 324 325 /* LBA1: GPT Header */ 326 lba = 1; 327 status = efid_io(F_READ, ed, EFI_SECTOBLK(ed, lba), EFI_BLKSPERSEC(ed), 328 buf); 329 if (EFI_ERROR(status)) { 330 *err = "Disk I/O Error"; 331 return (-1); 332 } 333 memcpy(&gh, buf, sizeof(gh)); 334 335 /* Check signature */ 336 if (letoh64(gh.gh_sig) != GPTSIGNATURE) { 337 *err = "bad GPT signature\n"; 338 return (-1); 339 } 340 341 if (letoh32(gh.gh_rev) != GPTREVISION) { 342 *err = "bad GPT revision\n"; 343 return (-1); 344 } 345 346 ghsize = letoh32(gh.gh_size); 347 if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) { 348 *err = "bad GPT header size\n"; 349 return (-1); 350 } 351 352 /* Check checksum */ 353 orig_csum = gh.gh_csum; 354 gh.gh_csum = 0; 355 new_csum = crc32(0, (unsigned char *)&gh, ghsize); 356 gh.gh_csum = orig_csum; 357 if (letoh32(orig_csum) != new_csum) { 358 *err = "bad GPT header checksum\n"; 359 return (-1); 360 } 361 362 lba = letoh64(gh.gh_part_lba); 363 ghpartsize = letoh32(gh.gh_part_size); 364 ghpartspersec = ed->blkio->Media->BlockSize / ghpartsize; 365 ghpartnum = letoh32(gh.gh_part_num); 366 gpsectors = (ghpartnum + ghpartspersec - 1) / ghpartspersec; 367 new_csum = crc32(0L, Z_NULL, 0); 368 found = 0; 369 for (i = 0; i < gpsectors; i++, lba++) { 370 status = efid_io(F_READ, ed, EFI_SECTOBLK(ed, lba), 371 EFI_BLKSPERSEC(ed), buf); 372 if (EFI_ERROR(status)) { 373 *err = "Disk I/O Error"; 374 return (-1); 375 } 376 for (part = 0; part < ghpartspersec; part++) { 377 if (ghpartnum == 0) 378 break; 379 new_csum = crc32(new_csum, buf + part * sizeof(gp), 380 sizeof(gp)); 381 ghpartnum--; 382 if (found) 383 continue; 384 memcpy(&gp, buf + part * sizeof(gp), sizeof(gp)); 385 if (memcmp(&gp.gp_type, openbsd_uuid, 386 sizeof(struct uuid)) == 0) 387 found = 1; 388 } 389 } 390 if (new_csum != letoh32(gh.gh_part_csum)) { 391 *err = "bad GPT entries checksum\n"; 392 return (-1); 393 } 394 if (found) { 395 lba = letoh64(gp.gp_lba_start); 396 /* Bootloaders do not current handle addresses > UINT_MAX! */ 397 if (lba > UINT_MAX || EFI_SECTOBLK(ed, lba) > UINT_MAX) { 398 *err = "OpenBSD Partition LBA > 2**32 - 1"; 399 return (-1); 400 } 401 return (u_int)lba; 402 } 403 404 return (-1); 405 } 406 407 const char * 408 efi_getdisklabel(efi_diskinfo_t ed, struct disklabel *label) 409 { 410 u_int start = 0; 411 uint8_t buf[DEV_BSIZE]; 412 struct dos_partition dosparts[NDOSPART]; 413 EFI_STATUS status; 414 const char *err = NULL; 415 int error; 416 417 /* 418 * Read sector 0. Ensure it has a valid MBR signature. 419 * 420 * If it's a protective MBR then try to find the disklabel via 421 * GPT. If it's not a protective MBR, try to find the disklabel 422 * via MBR. 423 */ 424 memset(buf, 0, sizeof(buf)); 425 status = efid_io(F_READ, ed, DOSBBSECTOR, 1, buf); 426 if (EFI_ERROR(status)) 427 return ("Disk I/O Error"); 428 429 /* Check MBR signature. */ 430 if (buf[510] != 0x55 || buf[511] != 0xaa) { 431 if (efi_getdisklabel_cd9660(ed, label) == 0) 432 return (NULL); 433 return ("invalid MBR signature"); 434 } 435 436 memcpy(dosparts, buf+DOSPARTOFF, sizeof(dosparts)); 437 438 /* check for GPT protective MBR. */ 439 if (gpt_chk_mbr(dosparts, ed->blkio->Media->LastBlock + 1) == 0) { 440 start = findopenbsd_gpt(ed, &err); 441 if (start == (u_int)-1) { 442 if (err != NULL) 443 return (err); 444 return ("no OpenBSD GPT partition"); 445 } 446 } else { 447 start = findopenbsd(ed, &err); 448 if (start == (u_int)-1) { 449 if (err != NULL) 450 return (err); 451 return "no OpenBSD MBR partition\n"; 452 } 453 } 454 455 /* Load BSD disklabel */ 456 #ifdef BIOS_DEBUG 457 if (debug) 458 printf("loading disklabel @ %u\n", start + DOS_LABELSECTOR); 459 #endif 460 /* read disklabel */ 461 error = efid_io(F_READ, ed, start + DOS_LABELSECTOR, 1, buf); 462 463 if (error) 464 return "failed to read disklabel"; 465 466 /* Fill in disklabel */ 467 return (getdisklabel(buf, label)); 468 } 469 470 static int 471 efi_getdisklabel_cd9660(efi_diskinfo_t ed, struct disklabel *label) 472 { 473 int off; 474 uint8_t buf[DEV_BSIZE]; 475 EFI_STATUS status; 476 477 for (off = 0; off < 100; off++) { 478 status = efid_io(F_READ, ed, 479 EFI_BLKSPERSEC(ed) * (16 + off), 1, buf); 480 if (EFI_ERROR(status)) 481 return (-1); 482 if (bcmp(buf + 1, ISO_STANDARD_ID, 5) != 0 || 483 buf[0] == ISO_VD_END) 484 return (-1); 485 if (buf[0] == ISO_VD_PRIMARY) 486 break; 487 } 488 if (off >= 100) 489 return (-1); 490 491 /* Create an imaginary disk label */ 492 label->d_secsize = 2048; 493 label->d_ntracks = 1; 494 label->d_nsectors = 100; 495 label->d_ncylinders = 1; 496 label->d_secpercyl = label->d_ntracks * label->d_nsectors; 497 if (label->d_secpercyl == 0) { 498 label->d_secpercyl = 100; 499 /* as long as it's not 0, since readdisklabel divides by it */ 500 } 501 502 strncpy(label->d_typename, "ATAPI CD-ROM", sizeof(label->d_typename)); 503 label->d_type = DTYPE_ATAPI; 504 505 strncpy(label->d_packname, "fictitious", sizeof(label->d_packname)); 506 DL_SETDSIZE(label, 100); 507 508 label->d_bbsize = 2048; 509 label->d_sbsize = 2048; 510 511 /* 'a' partition covering the "whole" disk */ 512 DL_SETPOFFSET(&label->d_partitions[0], 0); 513 DL_SETPSIZE(&label->d_partitions[0], 100); 514 label->d_partitions[0].p_fstype = FS_UNUSED; 515 516 /* The raw partition is special */ 517 DL_SETPOFFSET(&label->d_partitions[RAW_PART], 0); 518 DL_SETPSIZE(&label->d_partitions[RAW_PART], 100); 519 label->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 520 521 label->d_npartitions = MAXPARTITIONS; 522 523 label->d_magic = DISKMAGIC; 524 label->d_magic2 = DISKMAGIC; 525 label->d_checksum = dkcksum(label); 526 527 return (0); 528 } 529 530 int 531 efiopen(struct open_file *f, ...) 532 { 533 #ifdef SOFTRAID 534 struct sr_boot_volume *bv; 535 #endif 536 register char *cp, **file; 537 dev_t maj, unit, part; 538 struct diskinfo *dip; 539 int biosdev, devlen; 540 #if 0 541 const char *st; 542 #endif 543 va_list ap; 544 char *dev; 545 546 va_start(ap, f); 547 cp = *(file = va_arg(ap, char **)); 548 va_end(ap); 549 550 #ifdef EFI_DEBUG 551 if (debug) 552 printf("%s\n", cp); 553 #endif 554 555 f->f_devdata = NULL; 556 557 /* Search for device specification. */ 558 dev = cp; 559 if (cp[4] == ':') 560 devlen = 2; 561 else if (cp[5] == ':') 562 devlen = 3; 563 else 564 return ENOENT; 565 cp += devlen; 566 567 /* Get unit. */ 568 if ('0' <= *cp && *cp <= '9') 569 unit = *cp++ - '0'; 570 else { 571 printf("Bad unit number\n"); 572 return EUNIT; 573 } 574 575 /* Get partition. */ 576 if ('a' <= *cp && *cp <= 'p') 577 part = *cp++ - 'a'; 578 else { 579 printf("Bad partition\n"); 580 return EPART; 581 } 582 583 /* Get filename. */ 584 cp++; /* skip ':' */ 585 if (*cp != 0) 586 *file = cp; 587 else 588 f->f_flags |= F_RAW; 589 590 #ifdef SOFTRAID 591 /* Intercept softraid disks. */ 592 if (strncmp("sr", dev, 2) == 0) { 593 594 /* Create a fake diskinfo for this softraid volume. */ 595 SLIST_FOREACH(bv, &sr_volumes, sbv_link) 596 if (bv->sbv_unit == unit) 597 break; 598 if (bv == NULL) { 599 printf("Unknown device: sr%d\n", unit); 600 return EADAPT; 601 } 602 603 if (bv->sbv_level == 'C' && bv->sbv_keys == NULL) 604 if (sr_crypto_decrypt_keys(bv) != 0) 605 return EPERM; 606 607 if (bv->sbv_diskinfo == NULL) { 608 dip = alloc(sizeof(struct diskinfo)); 609 bzero(dip, sizeof(*dip)); 610 dip->diskio = efid_diskio; 611 dip->strategy = efistrategy; 612 bv->sbv_diskinfo = dip; 613 dip->sr_vol = bv; 614 dip->bios_info.flags |= BDI_BADLABEL; 615 } 616 617 dip = bv->sbv_diskinfo; 618 619 if (dip->bios_info.flags & BDI_BADLABEL) { 620 /* Attempt to read disklabel. */ 621 bv->sbv_part = 'c'; 622 if (sr_getdisklabel(bv, &dip->disklabel)) 623 return ERDLAB; 624 dip->bios_info.flags &= ~BDI_BADLABEL; 625 } 626 627 bv->sbv_part = part + 'a'; 628 629 bootdev_dip = dip; 630 f->f_devdata = dip; 631 632 return 0; 633 } 634 #endif 635 for (maj = 0; maj < nbdevs && 636 strncmp(dev, bdevs[maj], devlen); maj++); 637 if (maj >= nbdevs) { 638 printf("Unknown device: "); 639 for (cp = *file; *cp != ':'; cp++) 640 putchar(*cp); 641 putchar('\n'); 642 return EADAPT; 643 } 644 645 biosdev = unit; 646 switch (maj) { 647 case 0: /* wd */ 648 case 4: /* sd */ 649 case 17: /* hd */ 650 biosdev |= 0x80; 651 break; 652 case 2: /* fd */ 653 break; 654 case 6: /* cd */ 655 biosdev = bios_bootdev & 0xff; 656 break; 657 default: 658 return ENXIO; 659 } 660 661 /* Find device */ 662 dip = dklookup(biosdev); 663 if (dip == NULL) 664 return ENXIO; 665 bootdev_dip = dip; 666 667 /* Fix up bootdev */ 668 { dev_t bsd_dev; 669 bsd_dev = dip->bios_info.bsd_dev; 670 dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev), 671 B_CONTROLLER(bsd_dev), unit, part); 672 dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev), 673 B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part); 674 } 675 676 #if 0 677 dip->bios_info.bsd_dev = dip->bootdev; 678 bootdev = dip->bootdev; 679 #endif 680 681 #ifdef EFI_DEBUG 682 if (debug) { 683 printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n", 684 dip->bios_info.bios_heads, dip->bios_info.bios_sectors, 685 dip->bios_info.bios_edd); 686 } 687 #endif 688 689 #if 0 690 /* 691 * XXX In UEFI, media change can be detected by MediaID 692 */ 693 /* Try for disklabel again (might be removable media) */ 694 if (dip->bios_info.flags & BDI_BADLABEL) { 695 st = efi_getdisklabel(dip->efi_info, &dip->disklabel); 696 #ifdef EFI_DEBUG 697 if (debug && st) 698 printf("%s\n", st); 699 #endif 700 if (!st) { 701 dip->bios_info.flags &= ~BDI_BADLABEL; 702 dip->bios_info.flags |= BDI_GOODLABEL; 703 } else 704 return ERDLAB; 705 } 706 #endif 707 f->f_devdata = dip; 708 709 return 0; 710 } 711 712 int 713 efistrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf, 714 size_t *rsize) 715 { 716 struct diskinfo *dip = (struct diskinfo *)devdata; 717 u_int8_t error = 0; 718 size_t nsect; 719 720 #ifdef SOFTRAID 721 /* Intercept strategy for softraid volumes. */ 722 if (dip->sr_vol) 723 return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize); 724 #endif 725 nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; 726 blk += dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset; 727 728 if (blk < 0) 729 error = EINVAL; 730 else 731 error = dip->diskio(rw, dip, blk, nsect, buf); 732 733 #ifdef EFI_DEBUG 734 if (debug) { 735 if (error != 0) 736 printf("=0x%x(%s)", error, error); 737 putchar('\n'); 738 } 739 #endif 740 if (rsize != NULL) 741 *rsize = nsect * DEV_BSIZE; 742 743 return (error); 744 } 745 746 int 747 eficlose(struct open_file *f) 748 { 749 f->f_devdata = NULL; 750 751 return 0; 752 } 753 754 int 755 efiioctl(struct open_file *f, u_long cmd, void *data) 756 { 757 758 return 0; 759 } 760 761 void 762 efi_dump_diskinfo(void) 763 { 764 efi_diskinfo_t ed; 765 struct diskinfo *dip; 766 bios_diskinfo_t *bdi; 767 uint64_t siz; 768 const char *sizu; 769 770 printf("Disk\tBlkSiz\tIoAlign\tSize\tFlags\tChecksum\n"); 771 TAILQ_FOREACH(dip, &disklist, list) { 772 bdi = &dip->bios_info; 773 ed = dip->efi_info; 774 775 siz = (ed->blkio->Media->LastBlock + 1) * 776 ed->blkio->Media->BlockSize; 777 siz /= 1024 * 1024; 778 if (siz < 10000) 779 sizu = "MB"; 780 else { 781 siz /= 1024; 782 sizu = "GB"; 783 } 784 785 printf("hd%d\t%u\t%u\t%u%s\t0x%x\t0x%x\t%s\n", 786 (bdi->bios_number & 0x7f), 787 ed->blkio->Media->BlockSize, 788 ed->blkio->Media->IoAlign, siz, sizu, 789 bdi->flags, bdi->checksum, 790 (ed->blkio->Media->RemovableMedia)? "Removable" : ""); 791 } 792 } 793