Home | History | Annotate | Line # | Download | only in efiboot
efiblock.c revision 1.9
      1 /* $NetBSD: efiblock.c,v 1.9 2020/10/18 18:05:48 tnn 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 static EFI_HANDLE *efi_block;
     42 static UINTN efi_nblock;
     43 static struct efi_block_part *efi_block_booted = NULL;
     44 
     45 static TAILQ_HEAD(, efi_block_dev) efi_block_devs = TAILQ_HEAD_INITIALIZER(efi_block_devs);
     46 
     47 static int
     48 efi_block_parse(const char *fname, struct efi_block_part **pbpart, char **pfile)
     49 {
     50 	struct efi_block_dev *bdev;
     51 	struct efi_block_part *bpart;
     52 	char pathbuf[PATH_MAX], *default_device, *ep = NULL;
     53 	const char *full_path;
     54 	intmax_t dev;
     55 	int part;
     56 
     57 	default_device = get_default_device();
     58 	if (strchr(fname, ':') == NULL) {
     59 		if (strlen(default_device) > 0) {
     60 			snprintf(pathbuf, sizeof(pathbuf), "%s:%s", default_device, fname);
     61 			full_path = pathbuf;
     62 			*pfile = __UNCONST(fname);
     63 		} else {
     64 			return EINVAL;
     65 		}
     66 	} else {
     67 		full_path = fname;
     68 		*pfile = strchr(fname, ':') + 1;
     69 	}
     70 
     71 	if (strncasecmp(full_path, "hd", 2) != 0)
     72 		return EINVAL;
     73 	dev = strtoimax(full_path + 2, &ep, 10);
     74 	if (dev < 0 || dev >= efi_nblock)
     75 		return ENXIO;
     76 	if (ep[0] < 'a' || ep[0] >= 'a' + MAXPARTITIONS || ep[1] != ':')
     77 		return EINVAL;
     78 	part = ep[0] - 'a';
     79 	TAILQ_FOREACH(bdev, &efi_block_devs, entries) {
     80 		if (bdev->index == dev) {
     81 			TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
     82 				if (bpart->index == part) {
     83 					*pbpart = bpart;
     84 					return 0;
     85 				}
     86 			}
     87 		}
     88 	}
     89 
     90 	return ENOENT;
     91 }
     92 
     93 static void
     94 efi_block_generate_hash_mbr(struct efi_block_part *bpart, struct mbr_sector *mbr)
     95 {
     96 	MD5_CTX md5ctx;
     97 
     98 	MD5Init(&md5ctx);
     99 	MD5Update(&md5ctx, (void *)mbr, sizeof(*mbr));
    100 	MD5Final(bpart->hash, &md5ctx);
    101 }
    102 
    103 static void *
    104 efi_block_allocate_device_buffer(struct efi_block_dev *bdev, UINTN size,
    105 	void **buf_start)
    106 {
    107 	void *buf;
    108 
    109 	if (bdev->bio->Media->IoAlign <= 1)
    110 		*buf_start = buf = AllocatePool(size);
    111 	else {
    112 		buf = AllocatePool(size + bdev->bio->Media->IoAlign - 1);
    113 		*buf_start = (buf == NULL) ? NULL :
    114 		    (void *)roundup2((intptr_t)buf, bdev->bio->Media->IoAlign);
    115 	}
    116 
    117 	return buf;
    118 }
    119 
    120 static int
    121 efi_block_find_partitions_cd9660(struct efi_block_dev *bdev)
    122 {
    123 	struct efi_block_part *bpart;
    124 	struct iso_primary_descriptor *vd;
    125 	void *buf, *buf_start;
    126 	EFI_STATUS status;
    127 	EFI_LBA lba;
    128 	UINT32 sz;
    129 
    130 	sz = __MAX(sizeof(*vd), bdev->bio->Media->BlockSize);
    131 	sz = roundup(sz, bdev->bio->Media->BlockSize);
    132 	if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
    133 		return ENOMEM;
    134 
    135 	for (lba = 16;; lba++) {
    136 		status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
    137 		    lba, sz, buf_start);
    138 		if (EFI_ERROR(status))
    139 			goto io_error;
    140 
    141 		vd = (struct iso_primary_descriptor *)buf_start;
    142 		if (memcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0)
    143 			goto io_error;
    144 		if (isonum_711(vd->type) == ISO_VD_END)
    145 			goto io_error;
    146 		if (isonum_711(vd->type) == ISO_VD_PRIMARY)
    147 			break;
    148 	}
    149 
    150 	if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE)
    151 		goto io_error;
    152 
    153 	bpart = alloc(sizeof(*bpart));
    154 	bpart->index = 0;
    155 	bpart->bdev = bdev;
    156 	bpart->type = EFI_BLOCK_PART_CD9660;
    157 	TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
    158 
    159 	FreePool(buf);
    160 	return 0;
    161 
    162 io_error:
    163 	FreePool(buf);
    164 	return EIO;
    165 }
    166 
    167 static int
    168 efi_block_find_partitions_disklabel(struct efi_block_dev *bdev, struct mbr_sector *mbr, uint32_t start, uint32_t size)
    169 {
    170 	struct efi_block_part *bpart;
    171 	struct disklabel d;
    172 	struct partition *p;
    173 	EFI_STATUS status;
    174 	EFI_LBA lba;
    175 	void *buf, *buf_start;
    176 	UINT32 sz;
    177 	int n;
    178 
    179 	sz = __MAX(sizeof(d), bdev->bio->Media->BlockSize);
    180 	sz = roundup(sz, bdev->bio->Media->BlockSize);
    181 	if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
    182 		return ENOMEM;
    183 
    184 	lba = (((EFI_LBA)start + LABELSECTOR) * DEV_BSIZE) / bdev->bio->Media->BlockSize;
    185 	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
    186 		lba, sz, buf_start);
    187 	if (EFI_ERROR(status) || getdisklabel(buf_start, &d) != NULL) {
    188 		FreePool(buf);
    189 		return EIO;
    190 	}
    191 	FreePool(buf);
    192 
    193 	if (le32toh(d.d_magic) != DISKMAGIC || le32toh(d.d_magic2) != DISKMAGIC)
    194 		return EINVAL;
    195 	if (le16toh(d.d_npartitions) > MAXPARTITIONS)
    196 		return EINVAL;
    197 
    198 	for (n = 0; n < le16toh(d.d_npartitions); n++) {
    199 		p = &d.d_partitions[n];
    200 		switch (p->p_fstype) {
    201 		case FS_BSDFFS:
    202 		case FS_MSDOS:
    203 		case FS_BSDLFS:
    204 			break;
    205 		default:
    206 			continue;
    207 		}
    208 
    209 		bpart = alloc(sizeof(*bpart));
    210 		bpart->index = n;
    211 		bpart->bdev = bdev;
    212 		bpart->type = EFI_BLOCK_PART_DISKLABEL;
    213 		bpart->disklabel.secsize = le32toh(d.d_secsize);
    214 		bpart->disklabel.part = *p;
    215 		efi_block_generate_hash_mbr(bpart, mbr);
    216 		TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
    217 	}
    218 
    219 	return 0;
    220 }
    221 
    222 static int
    223 efi_block_find_partitions_mbr(struct efi_block_dev *bdev)
    224 {
    225 	struct mbr_sector mbr;
    226 	struct mbr_partition *mbr_part;
    227 	EFI_STATUS status;
    228 	void *buf, *buf_start;
    229 	UINT32 sz;
    230 	int n;
    231 
    232 	sz = __MAX(sizeof(mbr), bdev->bio->Media->BlockSize);
    233 	sz = roundup(sz, bdev->bio->Media->BlockSize);
    234 	if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
    235 		return ENOMEM;
    236 
    237 	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
    238 		0, sz, buf_start);
    239 	if (EFI_ERROR(status)) {
    240 		FreePool(buf);
    241 		return EIO;
    242 	}
    243 	memcpy(&mbr, buf_start, sizeof(mbr));
    244 	FreePool(buf);
    245 
    246 	if (le32toh(mbr.mbr_magic) != MBR_MAGIC)
    247 		return ENOENT;
    248 
    249 	for (n = 0; n < MBR_PART_COUNT; n++) {
    250 		mbr_part = &mbr.mbr_parts[n];
    251 		if (le32toh(mbr_part->mbrp_size) == 0)
    252 			continue;
    253 		if (mbr_part->mbrp_type == MBR_PTYPE_NETBSD) {
    254 			efi_block_find_partitions_disklabel(bdev, &mbr, le32toh(mbr_part->mbrp_start), le32toh(mbr_part->mbrp_size));
    255 			break;
    256 		}
    257 	}
    258 
    259 	return 0;
    260 }
    261 
    262 static const struct {
    263 	struct uuid guid;
    264 	uint8_t fstype;
    265 } gpt_guid_to_str[] = {
    266 	{ GPT_ENT_TYPE_NETBSD_FFS,		FS_BSDFFS },
    267 	{ GPT_ENT_TYPE_NETBSD_LFS,		FS_BSDLFS },
    268 	{ GPT_ENT_TYPE_NETBSD_RAIDFRAME,	FS_RAID },
    269 	{ GPT_ENT_TYPE_NETBSD_CCD,		FS_CCD },
    270 	{ GPT_ENT_TYPE_NETBSD_CGD,		FS_CGD },
    271 	{ GPT_ENT_TYPE_MS_BASIC_DATA,		FS_MSDOS },	/* or NTFS? ambiguous */
    272 	{ GPT_ENT_TYPE_EFI,			FS_MSDOS },
    273 };
    274 
    275 static int
    276 efi_block_find_partitions_gpt_entry(struct efi_block_dev *bdev, struct gpt_hdr *hdr, struct gpt_ent *ent, UINT32 index)
    277 {
    278 	struct efi_block_part *bpart;
    279 	uint8_t fstype = FS_UNUSED;
    280 	struct uuid uuid;
    281 	int n;
    282 
    283 	memcpy(&uuid, ent->ent_type, sizeof(uuid));
    284 	for (n = 0; n < __arraycount(gpt_guid_to_str); n++)
    285 		if (memcmp(ent->ent_type, &gpt_guid_to_str[n].guid, sizeof(ent->ent_type)) == 0) {
    286 			fstype = gpt_guid_to_str[n].fstype;
    287 			break;
    288 		}
    289 	if (fstype == FS_UNUSED)
    290 		return 0;
    291 
    292 	bpart = alloc(sizeof(*bpart));
    293 	bpart->index = index;
    294 	bpart->bdev = bdev;
    295 	bpart->type = EFI_BLOCK_PART_GPT;
    296 	bpart->gpt.fstype = fstype;
    297 	bpart->gpt.ent = *ent;
    298 	memcpy(bpart->hash, ent->ent_guid, sizeof(bpart->hash));
    299 	TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
    300 
    301 	return 0;
    302 }
    303 
    304 static int
    305 efi_block_find_partitions_gpt(struct efi_block_dev *bdev)
    306 {
    307 	struct gpt_hdr hdr;
    308 	struct gpt_ent ent;
    309 	EFI_STATUS status;
    310 	void *buf, *buf_start;
    311 	UINT32 sz, entry;
    312 
    313 	sz = __MAX(sizeof(hdr), bdev->bio->Media->BlockSize);
    314 	sz = roundup(sz, bdev->bio->Media->BlockSize);
    315 	if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
    316 		return ENOMEM;
    317 
    318 	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
    319 		GPT_HDR_BLKNO, sz, buf_start);
    320 	if (EFI_ERROR(status)) {
    321 		FreePool(buf);
    322 		return EIO;
    323 	}
    324 	memcpy(&hdr, buf_start, sizeof(hdr));
    325 	FreePool(buf);
    326 
    327 	if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0)
    328 		return ENOENT;
    329 	if (le32toh(hdr.hdr_entsz) < sizeof(ent))
    330 		return EINVAL;
    331 
    332 	sz = __MAX(le32toh(hdr.hdr_entsz) * le32toh(hdr.hdr_entries), bdev->bio->Media->BlockSize);
    333 	sz = roundup(sz, bdev->bio->Media->BlockSize);
    334 	if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
    335 		return ENOMEM;
    336 
    337 	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
    338 		le64toh(hdr.hdr_lba_table), sz, buf_start);
    339 	if (EFI_ERROR(status)) {
    340 		FreePool(buf);
    341 		return EIO;
    342 	}
    343 
    344 	for (entry = 0; entry < le32toh(hdr.hdr_entries); entry++) {
    345 		memcpy(&ent, buf_start + (entry * le32toh(hdr.hdr_entsz)),
    346 			sizeof(ent));
    347 		efi_block_find_partitions_gpt_entry(bdev, &hdr, &ent, entry);
    348 	}
    349 
    350 	FreePool(buf);
    351 
    352 	return 0;
    353 }
    354 
    355 static int
    356 efi_block_find_partitions(struct efi_block_dev *bdev)
    357 {
    358 	int error;
    359 
    360 	error = efi_block_find_partitions_gpt(bdev);
    361 	if (error)
    362 		error = efi_block_find_partitions_mbr(bdev);
    363 	if (error)
    364 		error = efi_block_find_partitions_cd9660(bdev);
    365 
    366 	return error;
    367 }
    368 
    369 void
    370 efi_block_probe(void)
    371 {
    372 	struct efi_block_dev *bdev;
    373 	struct efi_block_part *bpart;
    374 	EFI_BLOCK_IO *bio;
    375 	EFI_STATUS status;
    376 	uint16_t devindex = 0;
    377 	int depth = -1;
    378 	int n;
    379 
    380 	status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &efi_nblock, &efi_block);
    381 	if (EFI_ERROR(status))
    382 		return;
    383 
    384 	if (efi_bootdp) {
    385 		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
    386 		if (depth == 0)
    387 			depth = 1;
    388 		else if (depth == -1)
    389 			depth = 2;
    390 	}
    391 
    392 	for (n = 0; n < efi_nblock; n++) {
    393 		status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_block[n], &BlockIoProtocol, (void **)&bio);
    394 		if (EFI_ERROR(status) || !bio->Media->MediaPresent)
    395 			continue;
    396 
    397 		if (bio->Media->LogicalPartition)
    398 			continue;
    399 
    400 		bdev = alloc(sizeof(*bdev));
    401 		bdev->index = devindex++;
    402 		bdev->bio = bio;
    403 		bdev->media_id = bio->Media->MediaId;
    404 		bdev->path = DevicePathFromHandle(efi_block[n]);
    405 		TAILQ_INIT(&bdev->partitions);
    406 		TAILQ_INSERT_TAIL(&efi_block_devs, bdev, entries);
    407 
    408 		efi_block_find_partitions(bdev);
    409 
    410 		if (depth > 0 && efi_device_path_ncmp(efi_bootdp, DevicePathFromHandle(efi_block[n]), depth) == 0) {
    411 			TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
    412 				uint8_t fstype = FS_UNUSED;
    413 				switch (bpart->type) {
    414 				case EFI_BLOCK_PART_DISKLABEL:
    415 					fstype = bpart->disklabel.part.p_fstype;
    416 					break;
    417 				case EFI_BLOCK_PART_GPT:
    418 					fstype = bpart->gpt.fstype;
    419 					break;
    420 				case EFI_BLOCK_PART_CD9660:
    421 					fstype = FS_ISO9660;
    422 					break;
    423 				}
    424 				if (fstype == FS_BSDFFS || fstype == FS_ISO9660) {
    425 					char devname[9];
    426 					snprintf(devname, sizeof(devname), "hd%u%c", bdev->index, bpart->index + 'a');
    427 					set_default_device(devname);
    428 					set_default_fstype(fstype);
    429 					break;
    430 				}
    431 			}
    432 		}
    433 	}
    434 }
    435 
    436 static void
    437 print_guid(const uint8_t *guid)
    438 {
    439 	const int index[] = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 };
    440 	int i;
    441 
    442 	for (i = 0; i < 16; i++) {
    443 		printf("%02x", guid[index[i]]);
    444 		if (i == 3 || i == 5 || i == 7 || i == 9)
    445 			printf("-");
    446 	}
    447 }
    448 
    449 void
    450 efi_block_show(void)
    451 {
    452 	struct efi_block_dev *bdev;
    453 	struct efi_block_part *bpart;
    454 	uint64_t size;
    455 	CHAR16 *path;
    456 
    457 	TAILQ_FOREACH(bdev, &efi_block_devs, entries) {
    458 		printf("hd%u (", bdev->index);
    459 
    460 		/* Size in MB */
    461 		size = ((bdev->bio->Media->LastBlock + 1) * bdev->bio->Media->BlockSize) / (1024 * 1024);
    462 		if (size >= 10000)
    463 			printf("%"PRIu64" GB", size / 1024);
    464 		else
    465 			printf("%"PRIu64" MB", size);
    466 		printf("): ");
    467 
    468 		path = DevicePathToStr(bdev->path);
    469 		Print(L"%s", path);
    470 		FreePool(path);
    471 
    472 		printf("\n");
    473 
    474 		TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
    475 			switch (bpart->type) {
    476 			case EFI_BLOCK_PART_DISKLABEL:
    477 				printf("  hd%u%c (", bdev->index, bpart->index + 'a');
    478 
    479 				/* Size in MB */
    480 				size = ((uint64_t)bpart->disklabel.secsize * bpart->disklabel.part.p_size) / (1024 * 1024);
    481 				if (size >= 10000)
    482 					printf("%"PRIu64" GB", size / 1024);
    483 				else
    484 					printf("%"PRIu64" MB", size);
    485 				printf("): ");
    486 
    487 				printf("%s\n", fstypenames[bpart->disklabel.part.p_fstype]);
    488 				break;
    489 			case EFI_BLOCK_PART_GPT:
    490 				printf("  hd%u%c ", bdev->index, bpart->index + 'a');
    491 
    492 				if (bpart->gpt.ent.ent_name[0] == 0x0000) {
    493 					printf("\"");
    494 					print_guid(bpart->gpt.ent.ent_guid);
    495 					printf("\"");
    496 				} else {
    497 					Print(L"\"%s\"", bpart->gpt.ent.ent_name);
    498 				}
    499 
    500 				/* Size in MB */
    501 				size = (le64toh(bpart->gpt.ent.ent_lba_end) - le64toh(bpart->gpt.ent.ent_lba_start)) * bdev->bio->Media->BlockSize;
    502 				size /= (1024 * 1024);
    503 				if (size >= 10000)
    504 					printf(" (%"PRIu64" GB): ", size / 1024);
    505 				else
    506 					printf(" (%"PRIu64" MB): ", size);
    507 
    508 				printf("%s\n", fstypenames[bpart->gpt.fstype]);
    509 				break;
    510 			case EFI_BLOCK_PART_CD9660:
    511 				printf("  hd%u%c %s\n", bdev->index, bpart->index + 'a', fstypenames[FS_ISO9660]);
    512 				break;
    513 			default:
    514 				break;
    515 			}
    516 		}
    517 	}
    518 }
    519 
    520 struct efi_block_part *
    521 efi_block_boot_part(void)
    522 {
    523 	return efi_block_booted;
    524 }
    525 
    526 int
    527 efi_block_open(struct open_file *f, ...)
    528 {
    529 	struct efi_block_part *bpart;
    530 	const char *fname;
    531 	char **file;
    532 	char *path;
    533 	va_list ap;
    534 	int rv, n;
    535 
    536 	va_start(ap, f);
    537 	fname = va_arg(ap, const char *);
    538 	file = va_arg(ap, char **);
    539 	va_end(ap);
    540 
    541 	rv = efi_block_parse(fname, &bpart, &path);
    542 	if (rv != 0)
    543 		return rv;
    544 
    545 	for (n = 0; n < ndevs; n++)
    546 		if (strcmp(DEV_NAME(&devsw[n]), "efiblock") == 0) {
    547 			f->f_dev = &devsw[n];
    548 			break;
    549 		}
    550 	if (n == ndevs)
    551 		return ENXIO;
    552 
    553 	f->f_devdata = bpart;
    554 
    555 	*file = path;
    556 
    557 	efi_block_booted = bpart;
    558 
    559 	return 0;
    560 }
    561 
    562 int
    563 efi_block_close(struct open_file *f)
    564 {
    565 	return 0;
    566 }
    567 
    568 int
    569 efi_block_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
    570 {
    571 	struct efi_block_part *bpart = devdata;
    572 	EFI_STATUS status;
    573 	void *allocated_buf, *aligned_buf;
    574 
    575 	if (rw != F_READ)
    576 		return EROFS;
    577 
    578 	switch (bpart->type) {
    579 	case EFI_BLOCK_PART_DISKLABEL:
    580 		if (bpart->bdev->bio->Media->BlockSize != bpart->disklabel.secsize) {
    581 			printf("%s: unsupported block size %d (expected %d)\n", __func__,
    582 			    bpart->bdev->bio->Media->BlockSize, bpart->disklabel.secsize);
    583 			return EIO;
    584 		}
    585 		dblk += bpart->disklabel.part.p_offset;
    586 		break;
    587 	case EFI_BLOCK_PART_GPT:
    588 		if (bpart->bdev->bio->Media->BlockSize != DEV_BSIZE) {
    589 			printf("%s: unsupported block size %d (expected %d)\n", __func__,
    590 			    bpart->bdev->bio->Media->BlockSize, DEV_BSIZE);
    591 			return EIO;
    592 		}
    593 		dblk += le64toh(bpart->gpt.ent.ent_lba_start);
    594 		break;
    595 	case EFI_BLOCK_PART_CD9660:
    596 		break;
    597 	default:
    598 		return EINVAL;
    599 	}
    600 
    601 	if ((bpart->bdev->bio->Media->IoAlign <= 1) ||
    602 		((intptr_t)buf & (bpart->bdev->bio->Media->IoAlign - 1)) == 0) {
    603 		allocated_buf = NULL;
    604 		aligned_buf = buf;
    605 	} else if ((allocated_buf = efi_block_allocate_device_buffer(bpart->bdev,
    606 		size, &aligned_buf)) == NULL)
    607 		return ENOMEM;
    608 
    609 	status = uefi_call_wrapper(bpart->bdev->bio->ReadBlocks, 5,
    610 		bpart->bdev->bio, bpart->bdev->media_id, dblk, size, aligned_buf);
    611 	if (EFI_ERROR(status)) {
    612 		if (allocated_buf != NULL)
    613 			FreePool(allocated_buf);
    614 		return EIO;
    615 	}
    616 	if (allocated_buf != NULL) {
    617 		memcpy(buf, aligned_buf, size);
    618 		FreePool(allocated_buf);
    619 	}
    620 
    621 	*rsize = size;
    622 
    623 	return 0;
    624 }
    625