xref: /openbsd/sys/arch/amd64/stand/efiboot/efidev.c (revision d89ec533)
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