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