Home | History | Annotate | Line # | Download | only in efiboot
efiblock.c revision 1.15
      1 /* $NetBSD: efiblock.c,v 1.15 2021/06/22 21:56:51 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
      5  * Copyright (c) 2018 Jared McNeill <jmcneill (at) invisible.ca>
      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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED 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 #define FSTYPENAMES
     31 
     32 #include <sys/param.h>
     33 #include <sys/md5.h>
     34 #include <sys/uuid.h>
     35 
     36 #include <fs/cd9660/iso.h>
     37 
     38 #include "efiboot.h"
     39 #include "efiblock.h"
     40 
     41 #define	EFI_BLOCK_READAHEAD	(64 * 1024)
     42 #define	EFI_BLOCK_TIMEOUT	120
     43 #define	EFI_BLOCK_TIMEOUT_CODE	0x810c0000
     44 
     45 /*
     46  * The raidframe support is basic.  Ideally, it should be expanded to
     47  * consider raid volumes a first-class citizen like the x86 efiboot does,
     48  * but for now, we simply assume each RAID is potentially bootable.
     49  */
     50 #define	RF_PROTECTED_SECTORS	64	/* XXX refer to <.../rf_optnames.h> */
     51 
     52 static EFI_HANDLE *efi_block;
     53 static UINTN efi_nblock;
     54 static struct efi_block_part *efi_block_booted = NULL;
     55 
     56 static bool efi_ra_enable = false;
     57 static UINT8 *efi_ra_buffer = NULL;
     58 static UINT32 efi_ra_media_id;
     59 static UINT64 efi_ra_start = 0;
     60 static UINT64 efi_ra_length = 0;
     61 
     62 static TAILQ_HEAD(, efi_block_dev) efi_block_devs = TAILQ_HEAD_INITIALIZER(efi_block_devs);
     63 
     64 static int
     65 efi_block_parse(const char *fname, struct efi_block_part **pbpart, char **pfile)
     66 {
     67 	struct efi_block_dev *bdev;
     68 	struct efi_block_part *bpart;
     69 	char pathbuf[PATH_MAX], *default_device, *ep = NULL;
     70 	const char *full_path;
     71 	intmax_t dev;
     72 	int part;
     73 
     74 	default_device = get_default_device();
     75 	if (strchr(fname, ':') == NULL) {
     76 		if (strlen(default_device) > 0) {
     77 			snprintf(pathbuf, sizeof(pathbuf), "%s:%s", default_device, fname);
     78 			full_path = pathbuf;
     79 			*pfile = __UNCONST(fname);
     80 		} else {
     81 			return EINVAL;
     82 		}
     83 	} else {
     84 		full_path = fname;
     85 		*pfile = strchr(fname, ':') + 1;
     86 	}
     87 
     88 	if (strncasecmp(full_path, "hd", 2) != 0)
     89 		return EINVAL;
     90 	dev = strtoimax(full_path + 2, &ep, 10);
     91 	if (dev < 0 || dev >= efi_nblock)
     92 		return ENXIO;
     93 	if (ep[0] < 'a' || ep[0] >= 'a' + MAXPARTITIONS || ep[1] != ':')
     94 		return EINVAL;
     95 	part = ep[0] - 'a';
     96 	TAILQ_FOREACH(bdev, &efi_block_devs, entries) {
     97 		if (bdev->index == dev) {
     98 			TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
     99 				if (bpart->index == part) {
    100 					*pbpart = bpart;
    101 					return 0;
    102 				}
    103 			}
    104 		}
    105 	}
    106 
    107 	return ENOENT;
    108 }
    109 
    110 static void
    111 efi_block_generate_hash_mbr(struct efi_block_part *bpart, struct mbr_sector *mbr)
    112 {
    113 	MD5_CTX md5ctx;
    114 
    115 	MD5Init(&md5ctx);
    116 	MD5Update(&md5ctx, (void *)mbr, sizeof(*mbr));
    117 	MD5Final(bpart->hash, &md5ctx);
    118 }
    119 
    120 static EFI_STATUS
    121 efi_block_do_read_blockio(struct efi_block_dev *bdev, UINT64 off, void *buf,
    122     UINTN bufsize)
    123 {
    124 	UINT8 *blkbuf, *blkbuf_start;
    125 	EFI_STATUS status;
    126 	EFI_LBA lba_start, lba_end;
    127 	UINT64 blkbuf_offset;
    128 	UINT64 blkbuf_size;
    129 
    130 	lba_start = off / bdev->bio->Media->BlockSize;
    131 	lba_end = (off + bufsize + bdev->bio->Media->BlockSize - 1) /
    132 	    bdev->bio->Media->BlockSize;
    133 	blkbuf_offset = off % bdev->bio->Media->BlockSize;
    134 	blkbuf_size = (lba_end - lba_start) * bdev->bio->Media->BlockSize;
    135 	if (bdev->bio->Media->IoAlign > 1) {
    136 		blkbuf_size += bdev->bio->Media->IoAlign - 1;
    137 	}
    138 
    139 	blkbuf = AllocatePool(blkbuf_size);
    140 	if (blkbuf == NULL) {
    141 		return EFI_OUT_OF_RESOURCES;
    142 	}
    143 
    144 	if (bdev->bio->Media->IoAlign > 1) {
    145 		blkbuf_start = (void *)roundup2((intptr_t)blkbuf,
    146 		    bdev->bio->Media->IoAlign);
    147 	} else {
    148 		blkbuf_start = blkbuf;
    149 	}
    150 
    151 	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio,
    152 	    bdev->media_id, lba_start, blkbuf_size, blkbuf_start);
    153 	if (EFI_ERROR(status)) {
    154 		goto done;
    155 	}
    156 
    157 	memcpy(buf, blkbuf_start + blkbuf_offset, bufsize);
    158 
    159 done:
    160 	FreePool(blkbuf);
    161 	return status;
    162 }
    163 
    164 static EFI_STATUS
    165 efi_block_do_read_diskio(struct efi_block_dev *bdev, UINT64 off, void *buf,
    166     UINTN bufsize)
    167 {
    168 	return uefi_call_wrapper(bdev->dio->ReadDisk, 5, bdev->dio,
    169 	    bdev->media_id, off, bufsize, buf);
    170 }
    171 
    172 static EFI_STATUS
    173 efi_block_do_read(struct efi_block_dev *bdev, UINT64 off, void *buf,
    174     UINTN bufsize)
    175 {
    176 	/*
    177 	 * Perform read access using EFI_DISK_IO_PROTOCOL if available,
    178 	 * otherwise use EFI_BLOCK_IO_PROTOCOL.
    179 	 */
    180 	if (bdev->dio != NULL) {
    181 		return efi_block_do_read_diskio(bdev, off, buf, bufsize);
    182 	} else {
    183 		return efi_block_do_read_blockio(bdev, off, buf, bufsize);
    184 	}
    185 }
    186 
    187 static EFI_STATUS
    188 efi_block_readahead(struct efi_block_dev *bdev, UINT64 off, void *buf,
    189     UINTN bufsize)
    190 {
    191 	EFI_STATUS status;
    192 	UINT64 mediasize, len;
    193 
    194 	if (efi_ra_buffer == NULL) {
    195 		efi_ra_buffer = AllocatePool(EFI_BLOCK_READAHEAD);
    196 		if (efi_ra_buffer == NULL) {
    197 			return EFI_OUT_OF_RESOURCES;
    198 		}
    199 	}
    200 
    201 	if (bdev->media_id != efi_ra_media_id ||
    202 	    off < efi_ra_start ||
    203 	    off + bufsize > efi_ra_start + efi_ra_length) {
    204 		mediasize = bdev->bio->Media->BlockSize *
    205 		    (bdev->bio->Media->LastBlock + 1);
    206 		len = EFI_BLOCK_READAHEAD;
    207 		if (len > mediasize - off) {
    208 			len = mediasize - off;
    209 		}
    210 		status = efi_block_do_read(bdev, off, efi_ra_buffer, len);
    211 		if (EFI_ERROR(status)) {
    212 			efi_ra_start = efi_ra_length = 0;
    213 			return status;
    214 		}
    215 		efi_ra_start = off;
    216 		efi_ra_length = len;
    217 		efi_ra_media_id = bdev->media_id;
    218 	}
    219 
    220 	memcpy(buf, &efi_ra_buffer[off - efi_ra_start], bufsize);
    221 	return EFI_SUCCESS;
    222 }
    223 
    224 static EFI_STATUS
    225 efi_block_read(struct efi_block_dev *bdev, UINT64 off, void *buf,
    226     UINTN bufsize)
    227 {
    228 	if (efi_ra_enable) {
    229 		return efi_block_readahead(bdev, off, buf, bufsize);
    230 	}
    231 
    232 	return efi_block_do_read(bdev, off, buf, bufsize);
    233 }
    234 
    235 static int
    236 efi_block_find_partitions_cd9660(struct efi_block_dev *bdev)
    237 {
    238 	struct efi_block_part *bpart;
    239 	struct iso_primary_descriptor vd;
    240 	EFI_STATUS status;
    241 	EFI_LBA lba;
    242 
    243 	for (lba = 16;; lba++) {
    244 		status = efi_block_read(bdev,
    245 		    lba * ISO_DEFAULT_BLOCK_SIZE, &vd, sizeof(vd));
    246 		if (EFI_ERROR(status)) {
    247 			goto io_error;
    248 		}
    249 
    250 		if (memcmp(vd.id, ISO_STANDARD_ID, sizeof vd.id) != 0) {
    251 			goto io_error;
    252 		}
    253 		if (isonum_711(vd.type) == ISO_VD_END) {
    254 			goto io_error;
    255 		}
    256 		if (isonum_711(vd.type) == ISO_VD_PRIMARY) {
    257 			break;
    258 		}
    259 	}
    260 
    261 	if (isonum_723(vd.logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) {
    262 		goto io_error;
    263 	}
    264 
    265 	bpart = alloc(sizeof(*bpart));
    266 	bpart->index = 0;
    267 	bpart->bdev = bdev;
    268 	bpart->type = EFI_BLOCK_PART_CD9660;
    269 	TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
    270 
    271 	return 0;
    272 
    273 io_error:
    274 	return EIO;
    275 }
    276 
    277 static int
    278 efi_block_find_partitions_disklabel(struct efi_block_dev *bdev,
    279     struct mbr_sector *mbr, uint32_t start, uint32_t size)
    280 {
    281 	struct efi_block_part *bpart;
    282 	char buf[DEV_BSIZE];
    283 	struct disklabel d;
    284 	struct partition *p;
    285 	EFI_STATUS status;
    286 	int n;
    287 
    288 	status = efi_block_read(bdev,
    289 	    ((EFI_LBA)start + LABELSECTOR) * DEV_BSIZE, buf, sizeof(buf));
    290 	if (EFI_ERROR(status) || getdisklabel(buf, &d) != NULL) {
    291 		FreePool(buf);
    292 		return EIO;
    293 	}
    294 
    295 	if (le32toh(d.d_magic) != DISKMAGIC || le32toh(d.d_magic2) != DISKMAGIC)
    296 		return EINVAL;
    297 	if (le16toh(d.d_npartitions) > MAXPARTITIONS)
    298 		return EINVAL;
    299 
    300 	for (n = 0; n < le16toh(d.d_npartitions); n++) {
    301 		p = &d.d_partitions[n];
    302 		switch (p->p_fstype) {
    303 		case FS_BSDFFS:
    304 		case FS_MSDOS:
    305 		case FS_BSDLFS:
    306 			break;
    307 		case FS_RAID:
    308 			p->p_size -= RF_PROTECTED_SECTORS;
    309 			p->p_offset += RF_PROTECTED_SECTORS;
    310 			break;
    311 		default:
    312 			continue;
    313 		}
    314 
    315 		bpart = alloc(sizeof(*bpart));
    316 		bpart->index = n;
    317 		bpart->bdev = bdev;
    318 		bpart->type = EFI_BLOCK_PART_DISKLABEL;
    319 		bpart->disklabel.secsize = d.d_secsize;
    320 		bpart->disklabel.part = *p;
    321 		efi_block_generate_hash_mbr(bpart, mbr);
    322 		TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
    323 	}
    324 
    325 	return 0;
    326 }
    327 
    328 static int
    329 efi_block_find_partitions_mbr(struct efi_block_dev *bdev)
    330 {
    331 	struct mbr_sector mbr;
    332 	struct mbr_partition *mbr_part;
    333 	EFI_STATUS status;
    334 	int n;
    335 
    336 	status = efi_block_read(bdev, 0, &mbr, sizeof(mbr));
    337 	if (EFI_ERROR(status))
    338 		return EIO;
    339 
    340 	if (le32toh(mbr.mbr_magic) != MBR_MAGIC)
    341 		return ENOENT;
    342 
    343 	for (n = 0; n < MBR_PART_COUNT; n++) {
    344 		mbr_part = &mbr.mbr_parts[n];
    345 		if (le32toh(mbr_part->mbrp_size) == 0)
    346 			continue;
    347 		if (mbr_part->mbrp_type == MBR_PTYPE_NETBSD) {
    348 			efi_block_find_partitions_disklabel(bdev, &mbr,
    349 			    le32toh(mbr_part->mbrp_start),
    350 			    le32toh(mbr_part->mbrp_size));
    351 			break;
    352 		}
    353 	}
    354 
    355 	return 0;
    356 }
    357 
    358 static const struct {
    359 	struct uuid guid;
    360 	uint8_t fstype;
    361 } gpt_guid_to_str[] = {
    362 	{ GPT_ENT_TYPE_NETBSD_FFS,		FS_BSDFFS },
    363 	{ GPT_ENT_TYPE_NETBSD_LFS,		FS_BSDLFS },
    364 	{ GPT_ENT_TYPE_NETBSD_RAIDFRAME,	FS_RAID },
    365 	{ GPT_ENT_TYPE_NETBSD_CCD,		FS_CCD },
    366 	{ GPT_ENT_TYPE_NETBSD_CGD,		FS_CGD },
    367 	{ GPT_ENT_TYPE_MS_BASIC_DATA,		FS_MSDOS },	/* or NTFS? ambiguous */
    368 	{ GPT_ENT_TYPE_EFI,			FS_MSDOS },
    369 };
    370 
    371 static int
    372 efi_block_find_partitions_gpt_entry(struct efi_block_dev *bdev,
    373     struct gpt_hdr *hdr, struct gpt_ent *ent, UINT32 index)
    374 {
    375 	struct efi_block_part *bpart;
    376 	uint8_t fstype = FS_UNUSED;
    377 	struct uuid uuid;
    378 	int n;
    379 
    380 	memcpy(&uuid, ent->ent_type, sizeof(uuid));
    381 	for (n = 0; n < __arraycount(gpt_guid_to_str); n++)
    382 		if (memcmp(ent->ent_type, &gpt_guid_to_str[n].guid,
    383 		    sizeof(ent->ent_type)) == 0) {
    384 			fstype = gpt_guid_to_str[n].fstype;
    385 			break;
    386 		}
    387 	if (fstype == FS_UNUSED)
    388 		return 0;
    389 
    390 	bpart = alloc(sizeof(*bpart));
    391 	bpart->index = index;
    392 	bpart->bdev = bdev;
    393 	bpart->type = EFI_BLOCK_PART_GPT;
    394 	bpart->gpt.fstype = fstype;
    395 	bpart->gpt.ent = *ent;
    396 	if (fstype == FS_RAID) {
    397 		bpart->gpt.ent.ent_lba_start += RF_PROTECTED_SECTORS;
    398 		bpart->gpt.ent.ent_lba_end -= RF_PROTECTED_SECTORS;
    399 	}
    400 	memcpy(bpart->hash, ent->ent_guid, sizeof(bpart->hash));
    401 	TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
    402 
    403 	return 0;
    404 }
    405 
    406 static int
    407 efi_block_find_partitions_gpt(struct efi_block_dev *bdev)
    408 {
    409 	struct gpt_hdr hdr;
    410 	struct gpt_ent ent;
    411 	EFI_STATUS status;
    412 	UINT32 entry;
    413 	void *buf;
    414 	UINTN sz;
    415 
    416 	status = efi_block_read(bdev, GPT_HDR_BLKNO * DEV_BSIZE, &hdr,
    417 	    sizeof(hdr));
    418 	if (EFI_ERROR(status)) {
    419 		return EIO;
    420 	}
    421 
    422 	if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0)
    423 		return ENOENT;
    424 	if (le32toh(hdr.hdr_entsz) < sizeof(ent))
    425 		return EINVAL;
    426 
    427 	sz = le32toh(hdr.hdr_entsz) * le32toh(hdr.hdr_entries);
    428 	buf = AllocatePool(sz);
    429 	if (buf == NULL)
    430 		return ENOMEM;
    431 
    432 	status = efi_block_read(bdev,
    433 	    le64toh(hdr.hdr_lba_table) * DEV_BSIZE, buf, sz);
    434 	if (EFI_ERROR(status)) {
    435 		FreePool(buf);
    436 		return EIO;
    437 	}
    438 
    439 	for (entry = 0; entry < le32toh(hdr.hdr_entries); entry++) {
    440 		memcpy(&ent, buf + (entry * le32toh(hdr.hdr_entsz)),
    441 			sizeof(ent));
    442 		efi_block_find_partitions_gpt_entry(bdev, &hdr, &ent, entry);
    443 	}
    444 
    445 	FreePool(buf);
    446 
    447 	return 0;
    448 }
    449 
    450 static int
    451 efi_block_find_partitions(struct efi_block_dev *bdev)
    452 {
    453 	int error;
    454 
    455 	error = efi_block_find_partitions_gpt(bdev);
    456 	if (error)
    457 		error = efi_block_find_partitions_mbr(bdev);
    458 	if (error)
    459 		error = efi_block_find_partitions_cd9660(bdev);
    460 
    461 	return error;
    462 }
    463 
    464 void
    465 efi_block_probe(void)
    466 {
    467 	struct efi_block_dev *bdev;
    468 	struct efi_block_part *bpart;
    469 	EFI_BLOCK_IO *bio;
    470 	EFI_DISK_IO *dio;
    471 	EFI_STATUS status;
    472 	uint16_t devindex = 0;
    473 	int depth = -1;
    474 	int n;
    475 
    476 	status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &efi_nblock, &efi_block);
    477 	if (EFI_ERROR(status))
    478 		return;
    479 
    480 	if (efi_bootdp) {
    481 		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
    482 		if (depth == 0)
    483 			depth = 1;
    484 		else if (depth == -1)
    485 			depth = 2;
    486 	}
    487 
    488 	for (n = 0; n < efi_nblock; n++) {
    489 		/* EFI_BLOCK_IO_PROTOCOL is required */
    490 		status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_block[n],
    491 		    &BlockIoProtocol, (void **)&bio);
    492 		if (EFI_ERROR(status) || !bio->Media->MediaPresent)
    493 			continue;
    494 
    495 		/* Ignore logical partitions (we do our own partition discovery) */
    496 		if (bio->Media->LogicalPartition)
    497 			continue;
    498 
    499 		/* EFI_DISK_IO_PROTOCOL is optional */
    500 		status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_block[n],
    501 		    &DiskIoProtocol, (void **)&dio);
    502 		if (EFI_ERROR(status)) {
    503 			dio = NULL;
    504 		}
    505 
    506 		bdev = alloc(sizeof(*bdev));
    507 		bdev->index = devindex++;
    508 		bdev->bio = bio;
    509 		bdev->dio = dio;
    510 		bdev->media_id = bio->Media->MediaId;
    511 		bdev->path = DevicePathFromHandle(efi_block[n]);
    512 		TAILQ_INIT(&bdev->partitions);
    513 		TAILQ_INSERT_TAIL(&efi_block_devs, bdev, entries);
    514 
    515 		efi_block_find_partitions(bdev);
    516 
    517 		if (depth > 0 && efi_device_path_ncmp(efi_bootdp, DevicePathFromHandle(efi_block[n]), depth) == 0) {
    518 			TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
    519 				uint8_t fstype = FS_UNUSED;
    520 				switch (bpart->type) {
    521 				case EFI_BLOCK_PART_DISKLABEL:
    522 					fstype = bpart->disklabel.part.p_fstype;
    523 					break;
    524 				case EFI_BLOCK_PART_GPT:
    525 					fstype = bpart->gpt.fstype;
    526 					break;
    527 				case EFI_BLOCK_PART_CD9660:
    528 					fstype = FS_ISO9660;
    529 					break;
    530 				}
    531 				if (fstype == FS_BSDFFS || fstype == FS_ISO9660 || fstype == FS_RAID) {
    532 					char devname[9];
    533 					snprintf(devname, sizeof(devname), "hd%u%c", bdev->index, bpart->index + 'a');
    534 					set_default_device(devname);
    535 					set_default_fstype(fstype);
    536 					break;
    537 				}
    538 			}
    539 		}
    540 	}
    541 }
    542 
    543 static void
    544 print_guid(const uint8_t *guid)
    545 {
    546 	const int index[] = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 };
    547 	int i;
    548 
    549 	for (i = 0; i < 16; i++) {
    550 		printf("%02x", guid[index[i]]);
    551 		if (i == 3 || i == 5 || i == 7 || i == 9)
    552 			printf("-");
    553 	}
    554 }
    555 
    556 void
    557 efi_block_show(void)
    558 {
    559 	struct efi_block_dev *bdev;
    560 	struct efi_block_part *bpart;
    561 	uint64_t size;
    562 	CHAR16 *path;
    563 
    564 	TAILQ_FOREACH(bdev, &efi_block_devs, entries) {
    565 		printf("hd%u (", bdev->index);
    566 
    567 		/* Size in MB */
    568 		size = ((bdev->bio->Media->LastBlock + 1) * bdev->bio->Media->BlockSize) / (1024 * 1024);
    569 		if (size >= 10000)
    570 			printf("%"PRIu64" GB", size / 1024);
    571 		else
    572 			printf("%"PRIu64" MB", size);
    573 		printf("): ");
    574 
    575 		path = DevicePathToStr(bdev->path);
    576 		Print(L"%s", path);
    577 		FreePool(path);
    578 
    579 		printf("\n");
    580 
    581 		TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
    582 			switch (bpart->type) {
    583 			case EFI_BLOCK_PART_DISKLABEL:
    584 				printf("  hd%u%c (", bdev->index, bpart->index + 'a');
    585 
    586 				/* Size in MB */
    587 				size = ((uint64_t)bpart->disklabel.secsize * bpart->disklabel.part.p_size) / (1024 * 1024);
    588 				if (size >= 10000)
    589 					printf("%"PRIu64" GB", size / 1024);
    590 				else
    591 					printf("%"PRIu64" MB", size);
    592 				printf("): ");
    593 
    594 				printf("%s\n", fstypenames[bpart->disklabel.part.p_fstype]);
    595 				break;
    596 			case EFI_BLOCK_PART_GPT:
    597 				printf("  hd%u%c ", bdev->index, bpart->index + 'a');
    598 
    599 				if (bpart->gpt.ent.ent_name[0] == 0x0000) {
    600 					printf("\"");
    601 					print_guid(bpart->gpt.ent.ent_guid);
    602 					printf("\"");
    603 				} else {
    604 					Print(L"\"%s\"", bpart->gpt.ent.ent_name);
    605 				}
    606 
    607 				/* Size in MB */
    608 				size = (le64toh(bpart->gpt.ent.ent_lba_end) - le64toh(bpart->gpt.ent.ent_lba_start)) * bdev->bio->Media->BlockSize;
    609 				size /= (1024 * 1024);
    610 				if (size >= 10000)
    611 					printf(" (%"PRIu64" GB): ", size / 1024);
    612 				else
    613 					printf(" (%"PRIu64" MB): ", size);
    614 
    615 				printf("%s\n", fstypenames[bpart->gpt.fstype]);
    616 				break;
    617 			case EFI_BLOCK_PART_CD9660:
    618 				printf("  hd%u%c %s\n", bdev->index, bpart->index + 'a', fstypenames[FS_ISO9660]);
    619 				break;
    620 			default:
    621 				break;
    622 			}
    623 		}
    624 	}
    625 }
    626 
    627 struct efi_block_part *
    628 efi_block_boot_part(void)
    629 {
    630 	return efi_block_booted;
    631 }
    632 
    633 int
    634 efi_block_open(struct open_file *f, ...)
    635 {
    636 	struct efi_block_part *bpart;
    637 	const char *fname;
    638 	char **file;
    639 	char *path;
    640 	va_list ap;
    641 	int rv, n;
    642 
    643 	va_start(ap, f);
    644 	fname = va_arg(ap, const char *);
    645 	file = va_arg(ap, char **);
    646 	va_end(ap);
    647 
    648 	rv = efi_block_parse(fname, &bpart, &path);
    649 	if (rv != 0)
    650 		return rv;
    651 
    652 	for (n = 0; n < ndevs; n++)
    653 		if (strcmp(DEV_NAME(&devsw[n]), "efiblock") == 0) {
    654 			f->f_dev = &devsw[n];
    655 			break;
    656 		}
    657 	if (n == ndevs)
    658 		return ENXIO;
    659 
    660 	f->f_devdata = bpart;
    661 
    662 	*file = path;
    663 
    664 	efi_block_booted = bpart;
    665 
    666 	return 0;
    667 }
    668 
    669 int
    670 efi_block_close(struct open_file *f)
    671 {
    672 	return 0;
    673 }
    674 
    675 int
    676 efi_block_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
    677 {
    678 	struct efi_block_part *bpart = devdata;
    679 	EFI_STATUS status;
    680 	UINT64 off;
    681 
    682 	if (rw != F_READ)
    683 		return EROFS;
    684 
    685 	efi_set_watchdog(EFI_BLOCK_TIMEOUT, EFI_BLOCK_TIMEOUT_CODE);
    686 
    687 	switch (bpart->type) {
    688 	case EFI_BLOCK_PART_DISKLABEL:
    689 		off = (dblk + bpart->disklabel.part.p_offset) * DEV_BSIZE;
    690 		break;
    691 	case EFI_BLOCK_PART_GPT:
    692 		off = (dblk + le64toh(bpart->gpt.ent.ent_lba_start)) * DEV_BSIZE;
    693 		break;
    694 	case EFI_BLOCK_PART_CD9660:
    695 		off = dblk * ISO_DEFAULT_BLOCK_SIZE;
    696 		break;
    697 	default:
    698 		return EINVAL;
    699 	}
    700 
    701 	status = efi_block_read(bpart->bdev, off, buf, size);
    702 	if (EFI_ERROR(status))
    703 		return EIO;
    704 
    705 	*rsize = size;
    706 
    707 	return 0;
    708 }
    709 
    710 void
    711 efi_block_set_readahead(bool onoff)
    712 {
    713 	efi_ra_enable = onoff;
    714 }
    715