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