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
efid_init(struct diskinfo * dip,void * handle)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
efid_io(int rw,efi_diskinfo_t ed,u_int off,int nsect,void * buf)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
efid_diskio(int rw,struct diskinfo * dip,u_int off,int nsect,void * buf)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
gpt_chk_mbr(struct dos_partition * dp,u_int64_t dsize)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
findopenbsd(efi_diskinfo_t ed,const char ** err)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
findopenbsd_gpt(efi_diskinfo_t ed,const char ** err)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 *
efi_getdisklabel(efi_diskinfo_t ed,struct disklabel * label)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
efi_getdisklabel_cd9660(efi_diskinfo_t ed,struct disklabel * label)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
efiopen(struct open_file * f,...)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
efistrategy(void * devdata,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)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
eficlose(struct open_file * f)547 eficlose(struct open_file *f)
548 {
549 f->f_devdata = NULL;
550
551 return 0;
552 }
553
554 int
efiioctl(struct open_file * f,u_long cmd,void * data)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
esp_open(char * path,struct open_file * f)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
esp_close(struct open_file * f)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
esp_read(struct open_file * f,void * addr,size_t size,size_t * resid)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
esp_write(struct open_file * f,void * start,size_t size,size_t * resid)645 esp_write(struct open_file *f, void *start, size_t size, size_t *resid)
646 {
647 return (EROFS);
648 }
649
650 off_t
esp_seek(struct open_file * f,off_t offset,int where)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
esp_stat(struct open_file * f,struct stat * sb)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
esp_readdir(struct open_file * f,char * name)730 esp_readdir(struct open_file *f, char *name)
731 {
732 return EOPNOTSUPP;
733 }
734
735 int
espopen(struct open_file * f,...)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
espclose(struct open_file * f)752 espclose(struct open_file *f)
753 {
754 return 0;
755 }
756
757 int
espioctl(struct open_file * f,u_long cmd,void * data)758 espioctl(struct open_file *f, u_long cmd, void *data)
759 {
760 return EOPNOTSUPP;
761 }
762
763 int
espstrategy(void * devdata,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)764 espstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
765 size_t *rsize)
766 {
767 return EOPNOTSUPP;
768 }
769