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