1 /* $OpenBSD: efidev.c,v 1.42 2023/10/26 14:08:48 jsg 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
efid_init(struct diskinfo * dip,void * handle)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
efid_io(int rw,efi_diskinfo_t ed,u_int off,int nsect,void * buf)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
efid_diskio(int rw,struct diskinfo * dip,u_int off,int nsect,void * buf)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
gpt_chk_mbr(struct dos_partition * dp,u_int64_t dsize)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
findopenbsd(efi_diskinfo_t ed,const char ** err)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
findopenbsd_gpt(efi_diskinfo_t ed,const char ** err)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 *
efi_getdisklabel(efi_diskinfo_t ed,struct disklabel * label)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
efi_getdisklabel_cd9660(efi_diskinfo_t ed,struct disklabel * label)455 efi_getdisklabel_cd9660(efi_diskinfo_t ed, struct disklabel *label)
456 {
457 uint8_t buf[DEV_BSIZE];
458 EFI_STATUS status;
459
460 status = efid_io(F_READ, ed, 64, 1, buf);
461 if (EFI_ERROR(status))
462 return -1;
463 if (buf[0] != ISO_VD_PRIMARY || bcmp(buf + 1, ISO_STANDARD_ID, 5) != 0)
464 return -1;
465
466 /* Create an imaginary disk label */
467 label->d_secsize = 2048;
468 label->d_ntracks = 1;
469 label->d_nsectors = 100;
470 label->d_ncylinders = 1;
471 label->d_secpercyl = label->d_ntracks * label->d_nsectors;
472
473 strncpy(label->d_typename, "ATAPI CD-ROM", sizeof(label->d_typename));
474 label->d_type = DTYPE_ATAPI;
475
476 strncpy(label->d_packname, "fictitious", sizeof(label->d_packname));
477 DL_SETDSIZE(label, 100);
478
479 /* 'a' partition covering the "whole" disk */
480 DL_SETPOFFSET(&label->d_partitions[0], 0);
481 DL_SETPSIZE(&label->d_partitions[0], 100);
482 label->d_partitions[0].p_fstype = FS_UNUSED;
483
484 /* The raw partition is special */
485 DL_SETPOFFSET(&label->d_partitions[RAW_PART], 0);
486 DL_SETPSIZE(&label->d_partitions[RAW_PART], 100);
487 label->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
488
489 label->d_npartitions = MAXPARTITIONS;
490
491 label->d_magic = DISKMAGIC;
492 label->d_magic2 = DISKMAGIC;
493 label->d_checksum = dkcksum(label);
494
495 return (0);
496 }
497
498 int
efiopen(struct open_file * f,...)499 efiopen(struct open_file *f, ...)
500 {
501 #ifdef SOFTRAID
502 struct sr_boot_volume *bv;
503 #endif
504 register char *cp, **file;
505 dev_t maj, unit, part;
506 struct diskinfo *dip;
507 int biosdev, devlen;
508 #if 0
509 const char *st;
510 #endif
511 va_list ap;
512 char *dev;
513
514 va_start(ap, f);
515 cp = *(file = va_arg(ap, char **));
516 va_end(ap);
517
518 #ifdef EFI_DEBUG
519 if (debug)
520 printf("%s\n", cp);
521 #endif
522
523 f->f_devdata = NULL;
524
525 /* Search for device specification. */
526 dev = cp;
527 if (cp[4] == ':')
528 devlen = 2;
529 else if (cp[5] == ':')
530 devlen = 3;
531 else
532 return ENOENT;
533 cp += devlen;
534
535 /* Get unit. */
536 if ('0' <= *cp && *cp <= '9')
537 unit = *cp++ - '0';
538 else {
539 printf("Bad unit number\n");
540 return EUNIT;
541 }
542
543 /* Get partition. */
544 if ('a' <= *cp && *cp <= 'p')
545 part = *cp++ - 'a';
546 else {
547 printf("Bad partition\n");
548 return EPART;
549 }
550
551 /* Get filename. */
552 cp++; /* skip ':' */
553 if (*cp != 0)
554 *file = cp;
555 else
556 f->f_flags |= F_RAW;
557
558 #ifdef SOFTRAID
559 /* Intercept softraid disks. */
560 if (strncmp("sr", dev, 2) == 0) {
561 /* We only support read-only softraid. */
562 f->f_flags |= F_NOWRITE;
563
564 /* Create a fake diskinfo for this softraid volume. */
565 SLIST_FOREACH(bv, &sr_volumes, sbv_link)
566 if (bv->sbv_unit == unit)
567 break;
568 if (bv == NULL) {
569 printf("Unknown device: sr%d\n", unit);
570 return EADAPT;
571 }
572
573 if ((bv->sbv_level == 'C' || bv->sbv_level == 0x1C) &&
574 bv->sbv_keys == NULL) {
575 if (sr_crypto_unlock_volume(bv) != 0)
576 return EPERM;
577 }
578
579 if (bv->sbv_diskinfo == NULL) {
580 dip = alloc(sizeof(struct diskinfo));
581 bzero(dip, sizeof(*dip));
582 dip->diskio = efid_diskio;
583 dip->strategy = efistrategy;
584 bv->sbv_diskinfo = dip;
585 dip->sr_vol = bv;
586 dip->bios_info.flags |= BDI_BADLABEL;
587 }
588
589 dip = bv->sbv_diskinfo;
590
591 if (dip->bios_info.flags & BDI_BADLABEL) {
592 /* Attempt to read disklabel. */
593 bv->sbv_part = 'c';
594 if (sr_getdisklabel(bv, &dip->disklabel))
595 return ERDLAB;
596 dip->bios_info.flags &= ~BDI_BADLABEL;
597 check_hibernate(dip);
598 }
599
600 bv->sbv_part = part + 'a';
601
602 bootdev_dip = dip;
603 f->f_devdata = dip;
604
605 return 0;
606 }
607 #endif
608 for (maj = 0; maj < nbdevs &&
609 strncmp(dev, bdevs[maj], devlen); maj++);
610 if (maj >= nbdevs) {
611 printf("Unknown device: ");
612 for (cp = *file; *cp != ':'; cp++)
613 putchar(*cp);
614 putchar('\n');
615 return EADAPT;
616 }
617
618 biosdev = unit;
619 switch (maj) {
620 case 0: /* wd */
621 case 4: /* sd */
622 case 17: /* hd */
623 biosdev |= 0x80;
624 break;
625 case 2: /* fd */
626 break;
627 case 6: /* cd */
628 biosdev |= 0xe0;
629 break;
630 default:
631 return ENXIO;
632 }
633
634 /* Find device */
635 dip = dklookup(biosdev);
636 if (dip == NULL)
637 return ENXIO;
638 bootdev_dip = dip;
639
640 /* Fix up bootdev */
641 { dev_t bsd_dev;
642 bsd_dev = dip->bios_info.bsd_dev;
643 dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
644 B_CONTROLLER(bsd_dev), unit, part);
645 dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
646 B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part);
647 }
648
649 #if 0
650 dip->bios_info.bsd_dev = dip->bootdev;
651 bootdev = dip->bootdev;
652 #endif
653
654 #ifdef EFI_DEBUG
655 if (debug) {
656 printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n",
657 dip->bios_info.bios_heads, dip->bios_info.bios_sectors,
658 dip->bios_info.bios_edd);
659 }
660 #endif
661
662 #if 0
663 /*
664 * XXX In UEFI, media change can be detected by MediaID
665 */
666 /* Try for disklabel again (might be removable media) */
667 if (dip->bios_info.flags & BDI_BADLABEL) {
668 st = efi_getdisklabel(dip->efi_info, &dip->disklabel);
669 #ifdef EFI_DEBUG
670 if (debug && st)
671 printf("%s\n", st);
672 #endif
673 if (!st) {
674 dip->bios_info.flags &= ~BDI_BADLABEL;
675 dip->bios_info.flags |= BDI_GOODLABEL;
676 } else
677 return ERDLAB;
678 }
679 #endif
680 f->f_devdata = dip;
681
682 return 0;
683 }
684
685 int
efistrategy(void * devdata,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)686 efistrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
687 size_t *rsize)
688 {
689 struct diskinfo *dip = (struct diskinfo *)devdata;
690 u_int8_t error = 0;
691 size_t nsect;
692
693 #ifdef SOFTRAID
694 /* Intercept strategy for softraid volumes. */
695 if (dip->sr_vol)
696 return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize);
697 #endif
698 nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
699 blk += DL_SECTOBLK(&dip->disklabel,
700 dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset);
701
702 if (blk < 0)
703 error = EINVAL;
704 else
705 error = dip->diskio(rw, dip, blk, nsect, buf);
706
707 #ifdef EFI_DEBUG
708 if (debug) {
709 if (error != 0)
710 printf("=0x%x(%s)", error, error);
711 putchar('\n');
712 }
713 #endif
714 if (rsize != NULL)
715 *rsize = nsect * DEV_BSIZE;
716
717 return (error);
718 }
719
720 int
eficlose(struct open_file * f)721 eficlose(struct open_file *f)
722 {
723 f->f_devdata = NULL;
724
725 return 0;
726 }
727
728 int
efiioctl(struct open_file * f,u_long cmd,void * data)729 efiioctl(struct open_file *f, u_long cmd, void *data)
730 {
731
732 return 0;
733 }
734
735 void
efi_dump_diskinfo(void)736 efi_dump_diskinfo(void)
737 {
738 efi_diskinfo_t ed;
739 struct diskinfo *dip;
740 bios_diskinfo_t *bdi;
741 uint64_t siz;
742 const char *sizu;
743
744 printf("Disk\tBlkSiz\tIoAlign\tSize\tFlags\tChecksum\n");
745 TAILQ_FOREACH(dip, &disklist, list) {
746 bdi = &dip->bios_info;
747 ed = dip->efi_info;
748
749 siz = (ed->blkio->Media->LastBlock + 1) *
750 ed->blkio->Media->BlockSize;
751 siz /= 1024 * 1024;
752 if (siz < 10000)
753 sizu = "MB";
754 else {
755 siz /= 1024;
756 sizu = "GB";
757 }
758
759 printf("%cd%d\t%u\t%u\t%u%s\t0x%x\t0x%x\t%s\n",
760 (B_TYPE(bdi->bsd_dev) == 6)? 'c' : 'h',
761 (bdi->bios_number & 0x1f),
762 ed->blkio->Media->BlockSize,
763 ed->blkio->Media->IoAlign, (unsigned)siz, sizu,
764 bdi->flags, bdi->checksum,
765 (ed->blkio->Media->RemovableMedia)? "Removable" : "");
766 }
767 }
768