xref: /openbsd/sys/arch/amd64/stand/efiboot/efidev.c (revision 5af055cd)
1 /*	$OpenBSD: efidev.c,v 1.16 2016/01/06 02:10:03 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 
36 #include "libsa.h"
37 #include "disk.h"
38 
39 #ifdef SOFTRAID
40 #include <dev/softraidvar.h>
41 #include "softraid.h"
42 #endif
43 
44 #include <efi.h>
45 #include "eficall.h"
46 
47 extern int debug;
48 
49 #include "efidev.h"
50 #include "biosdev.h"	/* for dklookup() */
51 
52 #define EFI_BLKSPERSEC(_ed)	((_ed)->blkio->Media->BlockSize / DEV_BSIZE)
53 #define EFI_SECTOBLK(_ed, _n)	((_n) * EFI_BLKSPERSEC(_ed))
54 
55 struct efi_diskinfo {
56 	EFI_BLOCK_IO		*blkio;
57 	UINT32			 mediaid;
58 };
59 
60 int bios_bootdev;
61 static EFI_STATUS
62 		 efid_io(int, efi_diskinfo_t, u_int, int, void *);
63 static int	 efid_diskio(int, struct diskinfo *, u_int, int, void *);
64 static u_int	 findopenbsd(efi_diskinfo_t, const char **);
65 static uint64_t	 findopenbsd_gpt(efi_diskinfo_t, const char **);
66 static int	 gpt_chk_mbr(struct dos_partition *, u_int64_t);
67 
68 void
69 efid_init(struct diskinfo *dip, void *handle)
70 {
71 	EFI_BLOCK_IO		*blkio = handle;
72 
73 	memset(dip, 0, sizeof(struct diskinfo));
74 	dip->efi_info = alloc(sizeof(struct efi_diskinfo));
75 	dip->efi_info->blkio = blkio;
76 	dip->efi_info->mediaid = blkio->Media->MediaId;
77 	dip->diskio = efid_diskio;
78 	dip->strategy = efistrategy;
79 }
80 
81 static EFI_STATUS
82 efid_io(int rw, efi_diskinfo_t ed, u_int off, int nsect, void *buf)
83 {
84 	u_int		 blks, lba, i_lblks, i_tblks, i_nblks;
85 	EFI_STATUS	 status = EFI_SUCCESS;
86 	static u_char	*iblk = NULL;
87 	static u_int	 iblksz = 0;
88 
89 	/* block count of the intrisic block size in DEV_BSIZE */
90 	blks = EFI_BLKSPERSEC(ed);
91 	lba = off / blks;
92 
93 	/* leading and trailing unaligned blocks in intrisic block */
94 	i_lblks = ((off % blks) == 0)? 0 : blks - (off % blks);
95 	i_tblks = (off + nsect) % blks;
96 
97 	/* aligned blocks in intrisic block */
98 	i_nblks = nsect - (i_lblks + i_tblks);
99 
100 	switch (rw) {
101 	case F_READ:
102 		/* allocate the space for reading unaligned blocks */
103 		if (ed->blkio->Media->BlockSize != DEV_BSIZE) {
104 			if (iblk && iblksz < ed->blkio->Media->BlockSize) {
105 				free(iblk, iblksz);
106 				iblk = NULL;
107 			}
108 			if (iblk == NULL) {
109 				iblk = alloc(ed->blkio->Media->BlockSize);
110 				iblksz = ed->blkio->Media->BlockSize;
111 			}
112 		}
113 		if (i_lblks > 0) {
114 			status = EFI_CALL(ed->blkio->ReadBlocks,
115 			    ed->blkio, ed->mediaid, lba - 1,
116 			    ed->blkio->Media->BlockSize, iblk);
117 			if (EFI_ERROR(status))
118 				goto on_eio;
119 			memcpy(buf, iblk + (blks - i_lblks),
120 			    i_lblks * DEV_BSIZE);
121 		}
122 		if (i_nblks > 0) {
123 			status = EFI_CALL(ed->blkio->ReadBlocks,
124 			    ed->blkio, ed->mediaid, lba,
125 			    ed->blkio->Media->BlockSize * (i_nblks / blks),
126 			    buf + (i_lblks * DEV_BSIZE));
127 			if (EFI_ERROR(status))
128 				goto on_eio;
129 		}
130 		if (i_tblks > 0) {
131 			status = EFI_CALL(ed->blkio->ReadBlocks,
132 			    ed->blkio, ed->mediaid, lba + (i_nblks / blks),
133 			    ed->blkio->Media->BlockSize, iblk);
134 			if (EFI_ERROR(status))
135 				goto on_eio;
136 			memcpy(buf + (i_lblks + i_nblks) * DEV_BSIZE, iblk,
137 			    i_tblks * DEV_BSIZE);
138 		}
139 		break;
140 	case F_WRITE:
141 		if (ed->blkio->Media->ReadOnly)
142 			goto on_eio;
143 		/* XXX not yet */
144 		goto on_eio;
145 		break;
146 	}
147 	return (EFI_SUCCESS);
148 
149 on_eio:
150 	return (status);
151 }
152 
153 static int
154 efid_diskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf)
155 {
156 	EFI_STATUS status;
157 
158 	status = efid_io(rw, dip->efi_info, off, nsect, buf);
159 
160 	return ((EFI_ERROR(status))? -1 : 0);
161 }
162 
163 /*
164  * Returns 0 if the MBR with the provided partition array is a GPT protective
165  * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
166  * one MBR partition, an EFI partition that either covers the whole disk or as
167  * much of it as is possible with a 32bit size field.
168  *
169  * Taken from kern/subr_disk.c.
170  *
171  * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
172  */
173 static int
174 gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize)
175 {
176 	struct dos_partition *dp2;
177 	int efi, found, i;
178 	u_int32_t psize;
179 
180 	found = efi = 0;
181 	for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
182 		if (dp2->dp_typ == DOSPTYP_UNUSED)
183 			continue;
184 		found++;
185 		if (dp2->dp_typ != DOSPTYP_EFI)
186 			continue;
187 		psize = letoh32(dp2->dp_size);
188 		if (psize == (dsize - 1) ||
189 		    psize == UINT32_MAX) {
190 			if (letoh32(dp2->dp_start) == 1)
191 				efi++;
192 		}
193 	}
194 	if (found == 1 && efi == 1)
195 		return (0);
196 
197 	return (1);
198 }
199 
200 /*
201  * Try to read the bsd label on the given BIOS device.
202  */
203 static u_int
204 findopenbsd(efi_diskinfo_t ed, const char **err)
205 {
206 	EFI_STATUS status;
207 	struct dos_mbr mbr;
208 	struct dos_partition *dp;
209 	uint64_t gptoff;
210 	u_int mbroff = DOSBBSECTOR;
211 	u_int mbr_eoff = DOSBBSECTOR;	/* Offset of MBR extended partition. */
212 	int i, maxebr = DOS_MAXEBR, nextebr;
213 
214 again:
215 	if (!maxebr--) {
216 		*err = "too many extended partitions";
217 		return (-1);
218 	}
219 
220 	/* Read MBR */
221 	bzero(&mbr, sizeof(mbr));
222 	status = efid_io(F_READ, ed, mbroff, 1, &mbr);
223 	if (EFI_ERROR(status)) {
224 		*err = "Disk I/O Error";
225 		return (-1);
226 	}
227 
228 	/* check mbr signature */
229 	if (mbr.dmbr_sign != DOSMBR_SIGNATURE) {
230 		*err = "bad MBR signature\n";
231 		return (-1);
232 	}
233 
234 	/* check for GPT protective MBR. */
235 	if (mbroff == DOSBBSECTOR && gpt_chk_mbr(mbr.dmbr_parts,
236 	    ed->blkio->Media->LastBlock + 1) == 0) {
237 		gptoff = findopenbsd_gpt(ed, err);
238 		if (gptoff > UINT_MAX || EFI_SECTOBLK(ed, gptoff) > UINT_MAX) {
239 			*err = "Paritition LBA > 2**32";
240 			return (-1);
241 		}
242 		if (gptoff == -1)
243 			return (-1);
244 		return EFI_SECTOBLK(ed, gptoff);
245 	}
246 
247 	/* Search for OpenBSD partition */
248 	nextebr = 0;
249 	for (i = 0; i < NDOSPART; i++) {
250 		dp = &mbr.dmbr_parts[i];
251 		if (!dp->dp_size)
252 			continue;
253 #ifdef BIOS_DEBUG
254 		if (debug)
255 			printf("found partition %u: "
256 			    "type %u (0x%x) offset %u (0x%x)\n",
257 			    (int)(dp - mbr.dmbr_parts),
258 			    dp->dp_typ, dp->dp_typ,
259 			    dp->dp_start, dp->dp_start);
260 #endif
261 		if (dp->dp_typ == DOSPTYP_OPENBSD) {
262 			if (dp->dp_start > (dp->dp_start + mbroff))
263 				continue;
264 			return (dp->dp_start + mbroff);
265 		}
266 
267 		/*
268 		 * Record location of next ebr if and only if this is the first
269 		 * extended partition in this boot record!
270 		 */
271 		if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND ||
272 		    dp->dp_typ == DOSPTYP_EXTENDL)) {
273 			nextebr = dp->dp_start + mbr_eoff;
274 			if (nextebr < dp->dp_start)
275 				nextebr = (u_int)-1;
276 			if (mbr_eoff == DOSBBSECTOR)
277 				mbr_eoff = dp->dp_start;
278 		}
279 	}
280 
281 	if (nextebr && nextebr != (u_int)-1) {
282 		mbroff = nextebr;
283 		goto again;
284 	}
285 
286 	return (-1);
287 }
288 
289 /* call this only if LBA1 == GPT */
290 static uint64_t
291 findopenbsd_gpt(efi_diskinfo_t ed, const char **err)
292 {
293 	EFI_STATUS		 status;
294 	struct			 gpt_header gh;
295 	int			 i, part, found;
296 	uint64_t		 lba;
297 	uint32_t		 orig_csum, new_csum;
298 	uint32_t		 ghsize, ghpartsize, ghpartnum, ghpartspersec;
299 	uint32_t		 gpsectors;
300 	const char		 openbsd_uuid_code[] = GPT_UUID_OPENBSD;
301 	struct gpt_partition	 gp;
302 	static struct uuid	*openbsd_uuid = NULL, openbsd_uuid_space;
303 	static u_char		 buf[4096];
304 
305 	/* Prepare OpenBSD UUID */
306 	if (openbsd_uuid == NULL) {
307 		/* XXX: should be replaced by uuid_dec_be() */
308 		memcpy(&openbsd_uuid_space, openbsd_uuid_code,
309 		    sizeof(openbsd_uuid_space));
310 		openbsd_uuid_space.time_low =
311 		    betoh32(openbsd_uuid_space.time_low);
312 		openbsd_uuid_space.time_mid =
313 		    betoh16(openbsd_uuid_space.time_mid);
314 		openbsd_uuid_space.time_hi_and_version =
315 		    betoh16(openbsd_uuid_space.time_hi_and_version);
316 
317 		openbsd_uuid = &openbsd_uuid_space;
318 	}
319 
320 	if (EFI_BLKSPERSEC(ed) > 8) {
321 		*err = "disk sector > 4096 bytes\n";
322 		return (-1);
323 	}
324 
325 	/* LBA1: GPT Header */
326 	lba = 1;
327 	status = efid_io(F_READ, ed, EFI_SECTOBLK(ed, lba), EFI_BLKSPERSEC(ed),
328 	    buf);
329 	if (EFI_ERROR(status)) {
330 		*err = "Disk I/O Error";
331 		return (-1);
332 	}
333 	memcpy(&gh, buf, sizeof(gh));
334 
335 	/* Check signature */
336 	if (letoh64(gh.gh_sig) != GPTSIGNATURE) {
337 		*err = "bad GPT signature\n";
338 		return (-1);
339 	}
340 
341 	if (letoh32(gh.gh_rev) != GPTREVISION) {
342 		*err = "bad GPT revision\n";
343 		return (-1);
344 	}
345 
346 	ghsize = letoh32(gh.gh_size);
347 	if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) {
348 		*err = "bad GPT header size\n";
349 		return (-1);
350 	}
351 
352 	/* Check checksum */
353 	orig_csum = gh.gh_csum;
354 	gh.gh_csum = 0;
355 	new_csum = crc32(0, (unsigned char *)&gh, ghsize);
356 	gh.gh_csum = orig_csum;
357 	if (letoh32(orig_csum) != new_csum) {
358 		*err = "bad GPT header checksum\n";
359 		return (-1);
360 	}
361 
362 	lba = letoh64(gh.gh_part_lba);
363 	ghpartsize = letoh32(gh.gh_part_size);
364 	ghpartspersec = ed->blkio->Media->BlockSize / ghpartsize;
365 	ghpartnum = letoh32(gh.gh_part_num);
366 	gpsectors = (ghpartnum + ghpartspersec - 1) / ghpartspersec;
367 	new_csum = crc32(0L, Z_NULL, 0);
368 	found = 0;
369 	for (i = 0; i < gpsectors; i++, lba++) {
370 		status = efid_io(F_READ, ed, EFI_SECTOBLK(ed, lba),
371 		    EFI_BLKSPERSEC(ed), buf);
372 		if (EFI_ERROR(status)) {
373 			*err = "Disk I/O Error";
374 			return (-1);
375 		}
376 		for (part = 0; part < ghpartspersec; part++) {
377 			if (ghpartnum == 0)
378 				break;
379 			new_csum = crc32(new_csum, buf + part * sizeof(gp),
380 			    sizeof(gp));
381 			ghpartnum--;
382 			if (found)
383 				continue;
384 			memcpy(&gp, buf + part * sizeof(gp), sizeof(gp));
385 			if (memcmp(&gp.gp_type, openbsd_uuid,
386 			    sizeof(struct uuid)) == 0)
387 				found = 1;
388 		}
389 	}
390 	if (new_csum != letoh32(gh.gh_part_csum)) {
391 		*err = "bad GPT entries checksum\n";
392 		return (-1);
393 	}
394 	if (found)
395 		return (letoh64(gp.gp_lba_start));
396 
397 	return (-1);
398 }
399 
400 const char *
401 efi_getdisklabel(efi_diskinfo_t ed, struct disklabel *label)
402 {
403 	u_int start = 0;
404 	char buf[DEV_BSIZE];
405 	const char *err = NULL;
406 	int error;
407 
408 	/* Sanity check */
409 	/* XXX */
410 
411 	start = findopenbsd(ed, &err);
412 	if (start == (u_int)-1) {
413 		if (err != NULL)
414 			return (err);
415 		return "no OpenBSD partition\n";
416 	}
417 
418 	/* Load BSD disklabel */
419 #ifdef BIOS_DEBUG
420 	if (debug)
421 		printf("loading disklabel @ %u\n", start + DOS_LABELSECTOR);
422 #endif
423 	/* read disklabel */
424 	error = efid_io(F_READ, ed, start + DOS_LABELSECTOR, 1, buf);
425 
426 	if (error)
427 		return "failed to read disklabel";
428 
429 	/* Fill in disklabel */
430 	return (getdisklabel(buf, label));
431 }
432 
433 int
434 efiopen(struct open_file *f, ...)
435 {
436 #ifdef SOFTRAID
437 	struct sr_boot_volume *bv;
438 #endif
439 	register char *cp, **file;
440 	dev_t maj, unit, part;
441 	struct diskinfo *dip;
442 	int biosdev, devlen;
443 #if 0
444 	const char *st;
445 #endif
446 	va_list ap;
447 	char *dev;
448 
449 	va_start(ap, f);
450 	cp = *(file = va_arg(ap, char **));
451 	va_end(ap);
452 
453 #ifdef EFI_DEBUG
454 	if (debug)
455 		printf("%s\n", cp);
456 #endif
457 
458 	f->f_devdata = NULL;
459 
460 	/* Search for device specification. */
461 	dev = cp;
462 	if (cp[4] == ':')
463 		devlen = 2;
464 	else if (cp[5] == ':')
465 		devlen = 3;
466 	else
467 		return ENOENT;
468 	cp += devlen;
469 
470 	/* Get unit. */
471 	if ('0' <= *cp && *cp <= '9')
472 		unit = *cp++ - '0';
473 	else {
474 		printf("Bad unit number\n");
475 		return EUNIT;
476 	}
477 
478 	/* Get partition. */
479 	if ('a' <= *cp && *cp <= 'p')
480 		part = *cp++ - 'a';
481 	else {
482 		printf("Bad partition\n");
483 		return EPART;
484 	}
485 
486 	/* Get filename. */
487 	cp++;	/* skip ':' */
488 	if (*cp != 0)
489 		*file = cp;
490 	else
491 		f->f_flags |= F_RAW;
492 
493 #ifdef SOFTRAID
494 	/* Intercept softraid disks. */
495 	if (strncmp("sr", dev, 2) == 0) {
496 
497 		/* Create a fake diskinfo for this softraid volume. */
498 		SLIST_FOREACH(bv, &sr_volumes, sbv_link)
499 			if (bv->sbv_unit == unit)
500 				break;
501 		if (bv == NULL) {
502 			printf("Unknown device: sr%d\n", unit);
503 			return EADAPT;
504 		}
505 
506 		if (bv->sbv_level == 'C' && bv->sbv_keys == NULL)
507 			if (sr_crypto_decrypt_keys(bv) != 0)
508 				return EPERM;
509 
510 		if (bv->sbv_diskinfo == NULL) {
511 			dip = alloc(sizeof(struct diskinfo));
512 			bzero(dip, sizeof(*dip));
513 			dip->diskio = efid_diskio;
514 			dip->strategy = efistrategy;
515 			bv->sbv_diskinfo = dip;
516 			dip->sr_vol = bv;
517 			dip->bios_info.flags |= BDI_BADLABEL;
518 		}
519 
520 		dip = bv->sbv_diskinfo;
521 
522 		if (dip->bios_info.flags & BDI_BADLABEL) {
523 			/* Attempt to read disklabel. */
524 			bv->sbv_part = 'c';
525 			if (sr_getdisklabel(bv, &dip->disklabel))
526 				return ERDLAB;
527 			dip->bios_info.flags &= ~BDI_BADLABEL;
528 		}
529 
530 		bv->sbv_part = part + 'a';
531 
532 		bootdev_dip = dip;
533 		f->f_devdata = dip;
534 
535 		return 0;
536 	}
537 #endif
538 	for (maj = 0; maj < nbdevs &&
539 	    strncmp(dev, bdevs[maj], devlen); maj++);
540 	if (maj >= nbdevs) {
541 		printf("Unknown device: ");
542 		for (cp = *file; *cp != ':'; cp++)
543 			putchar(*cp);
544 		putchar('\n');
545 		return EADAPT;
546 	}
547 
548 	biosdev = unit;
549 	switch (maj) {
550 	case 0:  /* wd */
551 	case 4:  /* sd */
552 	case 17: /* hd */
553 		biosdev |= 0x80;
554 		break;
555 	case 2:  /* fd */
556 		break;
557 	case 6:  /* cd */
558 		biosdev = bios_bootdev & 0xff;
559 		break;
560 	default:
561 		return ENXIO;
562 	}
563 
564 	/* Find device */
565 	dip = dklookup(biosdev);
566 	if (dip == NULL)
567 		return ENXIO;
568 	bootdev_dip = dip;
569 
570 	/* Fix up bootdev */
571 	{ dev_t bsd_dev;
572 		bsd_dev = dip->bios_info.bsd_dev;
573 		dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
574 		    B_CONTROLLER(bsd_dev), unit, part);
575 		dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
576 		    B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part);
577 	}
578 
579 #if 0
580 	dip->bios_info.bsd_dev = dip->bootdev;
581 	bootdev = dip->bootdev;
582 #endif
583 
584 #ifdef EFI_DEBUG
585 	if (debug) {
586 		printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n",
587 		    dip->bios_info.bios_heads, dip->bios_info.bios_sectors,
588 		    dip->bios_info.bios_edd);
589 	}
590 #endif
591 
592 #if 0
593 /*
594  * XXX In UEFI, media change can be detected by MediaID
595  */
596 	/* Try for disklabel again (might be removable media) */
597 	if (dip->bios_info.flags & BDI_BADLABEL) {
598 		st = efi_getdisklabel(dip->efi_info, &dip->disklabel);
599 #ifdef EFI_DEBUG
600 		if (debug && st)
601 			printf("%s\n", st);
602 #endif
603 		if (!st) {
604 			dip->bios_info.flags &= ~BDI_BADLABEL;
605 			dip->bios_info.flags |= BDI_GOODLABEL;
606 		} else
607 			return ERDLAB;
608 	}
609 #endif
610 	f->f_devdata = dip;
611 
612 	return 0;
613 }
614 
615 int
616 efistrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf,
617     size_t *rsize)
618 {
619 	struct diskinfo *dip = (struct diskinfo *)devdata;
620 	u_int8_t error = 0;
621 	size_t nsect;
622 
623 #ifdef SOFTRAID
624 	/* Intercept strategy for softraid volumes. */
625 	if (dip->sr_vol)
626 		return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize);
627 #endif
628 	nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
629 	blk += dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset;
630 
631 	if (blk < 0)
632 		error = EINVAL;
633 	else
634 		error = dip->diskio(rw, dip, blk, nsect, buf);
635 
636 #ifdef EFI_DEBUG
637 	if (debug) {
638 		if (error != 0)
639 			printf("=0x%x(%s)", error, error);
640 		putchar('\n');
641 	}
642 #endif
643 	if (rsize != NULL)
644 		*rsize = nsect * DEV_BSIZE;
645 
646 	return (error);
647 }
648 
649 int
650 eficlose(struct open_file *f)
651 {
652 	f->f_devdata = NULL;
653 
654 	return 0;
655 }
656 
657 int
658 efiioctl(struct open_file *f, u_long cmd, void *data)
659 {
660 
661 	return 0;
662 }
663 
664 void
665 efi_dump_diskinfo(void)
666 {
667 	efi_diskinfo_t	 ed;
668 	struct diskinfo	*dip;
669 	bios_diskinfo_t *bdi;
670 	uint64_t	 siz;
671 	const char	*sizu;
672 
673 	printf("Disk\tBlkSiz\tIoAlign\tSize\tFlags\tChecksum\n");
674 	TAILQ_FOREACH(dip, &disklist, list) {
675 		bdi = &dip->bios_info;
676 		ed = dip->efi_info;
677 
678 		siz = (ed->blkio->Media->LastBlock + 1) *
679 		    ed->blkio->Media->BlockSize;
680 		siz /= 1024 * 1024;
681 		if (siz < 10000)
682 			sizu = "MB";
683 		else {
684 			siz /= 1024;
685 			sizu = "GB";
686 		}
687 
688 		printf("hd%d\t%u\t%u\t%u%s\t0x%x\t0x%x\t%s\n",
689 		    (bdi->bios_number & 0x7f),
690 		    ed->blkio->Media->BlockSize,
691 		    ed->blkio->Media->IoAlign, siz, sizu,
692 		    bdi->flags, bdi->checksum,
693 		    (ed->blkio->Media->RemovableMedia)? "Removable" : "");
694 	}
695 }
696