Module Name:    src
Committed By:   jmcneill
Date:           Mon Jun 21 11:11:33 UTC 2021

Modified Files:
        src/sys/stand/efiboot: efiblock.c efiblock.h version

Log Message:
efiboot: Use disk I/O protocol for block device access.

EFI_DISK_IO_PROTOCOL is a simplified interface to block devices. Use this
instead of EFI_BLOCK_IO_PROTOCOL for accessing block devices to simplify
the code -- we no longer need to worry about the underlying media's block
I/O size and alignment requirements.


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sys/stand/efiboot/efiblock.c
cvs rdiff -u -r1.4 -r1.5 src/sys/stand/efiboot/efiblock.h
cvs rdiff -u -r1.26 -r1.27 src/sys/stand/efiboot/version

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/stand/efiboot/efiblock.c
diff -u src/sys/stand/efiboot/efiblock.c:1.12 src/sys/stand/efiboot/efiblock.c:1.13
--- src/sys/stand/efiboot/efiblock.c:1.12	Sun Jun 20 19:10:47 2021
+++ src/sys/stand/efiboot/efiblock.c	Mon Jun 21 11:11:33 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: efiblock.c,v 1.12 2021/06/20 19:10:47 jmcneill Exp $ */
+/* $NetBSD: efiblock.c,v 1.13 2021/06/21 11:11:33 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -110,68 +110,41 @@ efi_block_generate_hash_mbr(struct efi_b
 	MD5Final(bpart->hash, &md5ctx);
 }
 
-static void *
-efi_block_allocate_device_buffer(struct efi_block_dev *bdev, UINTN size,
-	void **buf_start)
+static EFI_STATUS
+efi_block_disk_read(struct efi_block_dev *bdev, UINT64 off, void *buf,
+    UINTN bufsize)
 {
-	void *buf;
-
-	if (bdev->bio->Media->IoAlign <= 1)
-		*buf_start = buf = AllocatePool(size);
-	else {
-		buf = AllocatePool(size + bdev->bio->Media->IoAlign - 1);
-		*buf_start = (buf == NULL) ? NULL :
-		    (void *)roundup2((intptr_t)buf, bdev->bio->Media->IoAlign);
-	}
-
-	return buf;
+	return uefi_call_wrapper(bdev->dio->ReadDisk, 5, bdev->dio,
+	    bdev->media_id, off, bufsize, buf);
 }
 
 static int
 efi_block_find_partitions_cd9660(struct efi_block_dev *bdev)
 {
 	struct efi_block_part *bpart;
-	struct iso_primary_descriptor *vd;
-	void *buf, *buf_start;
+	struct iso_primary_descriptor vd;
 	EFI_STATUS status;
 	EFI_LBA lba;
-	UINT32 sz;
-
-	if (bdev->bio->Media->BlockSize != DEV_BSIZE &&
-	    bdev->bio->Media->BlockSize != ISO_DEFAULT_BLOCK_SIZE) {
-		return ENXIO;
-	}
-
-	sz = __MAX(sizeof(*vd), bdev->bio->Media->BlockSize);
-	sz = roundup(sz, bdev->bio->Media->BlockSize);
-	if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL) {
-		return ENOMEM;
-	}
 
 	for (lba = 16;; lba++) {
-		status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5,
-		    bdev->bio,
-		    bdev->media_id,
-		    lba * ISO_DEFAULT_BLOCK_SIZE / bdev->bio->Media->BlockSize,
-		    sz,
-		    buf_start);
+		status = efi_block_disk_read(bdev,
+		    lba * ISO_DEFAULT_BLOCK_SIZE, &vd, sizeof(vd));
 		if (EFI_ERROR(status)) {
 			goto io_error;
 		}
 
-		vd = (struct iso_primary_descriptor *)buf_start;
-		if (memcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) {
+		if (memcmp(vd.id, ISO_STANDARD_ID, sizeof vd.id) != 0) {
 			goto io_error;
 		}
-		if (isonum_711(vd->type) == ISO_VD_END) {
+		if (isonum_711(vd.type) == ISO_VD_END) {
 			goto io_error;
 		}
-		if (isonum_711(vd->type) == ISO_VD_PRIMARY) {
+		if (isonum_711(vd.type) == ISO_VD_PRIMARY) {
 			break;
 		}
 	}
 
-	if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) {
+	if (isonum_723(vd.logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) {
 		goto io_error;
 	}
 
@@ -181,39 +154,29 @@ efi_block_find_partitions_cd9660(struct 
 	bpart->type = EFI_BLOCK_PART_CD9660;
 	TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
 
-	FreePool(buf);
 	return 0;
 
 io_error:
-	FreePool(buf);
 	return EIO;
 }
 
 static int
-efi_block_find_partitions_disklabel(struct efi_block_dev *bdev, struct mbr_sector *mbr, uint32_t start, uint32_t size)
+efi_block_find_partitions_disklabel(struct efi_block_dev *bdev,
+    struct mbr_sector *mbr, uint32_t start, uint32_t size)
 {
 	struct efi_block_part *bpart;
+	char buf[DEV_BSIZE];
 	struct disklabel d;
 	struct partition *p;
 	EFI_STATUS status;
-	EFI_LBA lba;
-	void *buf, *buf_start;
-	UINT32 sz;
 	int n;
 
-	sz = __MAX(sizeof(d), bdev->bio->Media->BlockSize);
-	sz = roundup(sz, bdev->bio->Media->BlockSize);
-	if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
-		return ENOMEM;
-
-	lba = (((EFI_LBA)start + LABELSECTOR) * DEV_BSIZE) / bdev->bio->Media->BlockSize;
-	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
-		lba, sz, buf_start);
-	if (EFI_ERROR(status) || getdisklabel(buf_start, &d) != NULL) {
+	status = efi_block_disk_read(bdev,
+	    ((EFI_LBA)start + LABELSECTOR) * DEV_BSIZE, buf, sizeof(buf));
+	if (EFI_ERROR(status) || getdisklabel(buf, &d) != NULL) {
 		FreePool(buf);
 		return EIO;
 	}
-	FreePool(buf);
 
 	if (le32toh(d.d_magic) != DISKMAGIC || le32toh(d.d_magic2) != DISKMAGIC)
 		return EINVAL;
@@ -254,23 +217,11 @@ efi_block_find_partitions_mbr(struct efi
 	struct mbr_sector mbr;
 	struct mbr_partition *mbr_part;
 	EFI_STATUS status;
-	void *buf, *buf_start;
-	UINT32 sz;
 	int n;
 
-	sz = __MAX(sizeof(mbr), bdev->bio->Media->BlockSize);
-	sz = roundup(sz, bdev->bio->Media->BlockSize);
-	if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
-		return ENOMEM;
-
-	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
-		0, sz, buf_start);
-	if (EFI_ERROR(status)) {
-		FreePool(buf);
+	status = efi_block_disk_read(bdev, 0, &mbr, sizeof(mbr));
+	if (EFI_ERROR(status))
 		return EIO;
-	}
-	memcpy(&mbr, buf_start, sizeof(mbr));
-	FreePool(buf);
 
 	if (le32toh(mbr.mbr_magic) != MBR_MAGIC)
 		return ENOENT;
@@ -280,7 +231,9 @@ efi_block_find_partitions_mbr(struct efi
 		if (le32toh(mbr_part->mbrp_size) == 0)
 			continue;
 		if (mbr_part->mbrp_type == MBR_PTYPE_NETBSD) {
-			efi_block_find_partitions_disklabel(bdev, &mbr, le32toh(mbr_part->mbrp_start), le32toh(mbr_part->mbrp_size));
+			efi_block_find_partitions_disklabel(bdev, &mbr,
+			    le32toh(mbr_part->mbrp_start),
+			    le32toh(mbr_part->mbrp_size));
 			break;
 		}
 	}
@@ -302,7 +255,8 @@ static const struct {
 };
 
 static int
-efi_block_find_partitions_gpt_entry(struct efi_block_dev *bdev, struct gpt_hdr *hdr, struct gpt_ent *ent, UINT32 index)
+efi_block_find_partitions_gpt_entry(struct efi_block_dev *bdev,
+    struct gpt_hdr *hdr, struct gpt_ent *ent, UINT32 index)
 {
 	struct efi_block_part *bpart;
 	uint8_t fstype = FS_UNUSED;
@@ -311,7 +265,8 @@ efi_block_find_partitions_gpt_entry(stru
 
 	memcpy(&uuid, ent->ent_type, sizeof(uuid));
 	for (n = 0; n < __arraycount(gpt_guid_to_str); n++)
-		if (memcmp(ent->ent_type, &gpt_guid_to_str[n].guid, sizeof(ent->ent_type)) == 0) {
+		if (memcmp(ent->ent_type, &gpt_guid_to_str[n].guid,
+		    sizeof(ent->ent_type)) == 0) {
 			fstype = gpt_guid_to_str[n].fstype;
 			break;
 		}
@@ -340,42 +295,35 @@ efi_block_find_partitions_gpt(struct efi
 	struct gpt_hdr hdr;
 	struct gpt_ent ent;
 	EFI_STATUS status;
-	void *buf, *buf_start;
-	UINT32 sz, entry;
-
-	sz = __MAX(sizeof(hdr), bdev->bio->Media->BlockSize);
-	sz = roundup(sz, bdev->bio->Media->BlockSize);
-	if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
-		return ENOMEM;
+	UINT32 entry;
+	void *buf;
+	UINTN sz;
 
-	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
-		GPT_HDR_BLKNO, sz, buf_start);
+	status = efi_block_disk_read(bdev, GPT_HDR_BLKNO * DEV_BSIZE, &hdr,
+	    sizeof(hdr));
 	if (EFI_ERROR(status)) {
-		FreePool(buf);
 		return EIO;
 	}
-	memcpy(&hdr, buf_start, sizeof(hdr));
-	FreePool(buf);
 
 	if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0)
 		return ENOENT;
 	if (le32toh(hdr.hdr_entsz) < sizeof(ent))
 		return EINVAL;
 
-	sz = __MAX(le32toh(hdr.hdr_entsz) * le32toh(hdr.hdr_entries), bdev->bio->Media->BlockSize);
-	sz = roundup(sz, bdev->bio->Media->BlockSize);
-	if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
+	sz = le32toh(hdr.hdr_entsz) * le32toh(hdr.hdr_entries);
+	buf = AllocatePool(sz);
+	if (buf == NULL)
 		return ENOMEM;
 
-	status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
-		le64toh(hdr.hdr_lba_table), sz, buf_start);
+	status = efi_block_disk_read(bdev,
+	    le64toh(hdr.hdr_lba_table) * DEV_BSIZE, buf, sz);
 	if (EFI_ERROR(status)) {
 		FreePool(buf);
 		return EIO;
 	}
 
 	for (entry = 0; entry < le32toh(hdr.hdr_entries); entry++) {
-		memcpy(&ent, buf_start + (entry * le32toh(hdr.hdr_entsz)),
+		memcpy(&ent, buf + (entry * le32toh(hdr.hdr_entsz)),
 			sizeof(ent));
 		efi_block_find_partitions_gpt_entry(bdev, &hdr, &ent, entry);
 	}
@@ -405,6 +353,7 @@ efi_block_probe(void)
 	struct efi_block_dev *bdev;
 	struct efi_block_part *bpart;
 	EFI_BLOCK_IO *bio;
+	EFI_DISK_IO *dio;
 	EFI_STATUS status;
 	uint16_t devindex = 0;
 	int depth = -1;
@@ -423,16 +372,23 @@ efi_block_probe(void)
 	}
 
 	for (n = 0; n < efi_nblock; n++) {
-		status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_block[n], &BlockIoProtocol, (void **)&bio);
+		status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_block[n],
+		    &BlockIoProtocol, (void **)&bio);
 		if (EFI_ERROR(status) || !bio->Media->MediaPresent)
 			continue;
 
 		if (bio->Media->LogicalPartition)
 			continue;
 
+		status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_block[n],
+		    &DiskIoProtocol, (void **)&dio);
+		if (EFI_ERROR(status))
+			continue;
+
 		bdev = alloc(sizeof(*bdev));
 		bdev->index = devindex++;
 		bdev->bio = bio;
+		bdev->dio = dio;
 		bdev->media_id = bio->Media->MediaId;
 		bdev->path = DevicePathFromHandle(efi_block[n]);
 		TAILQ_INIT(&bdev->partitions);
@@ -529,7 +485,7 @@ efi_block_show(void)
 				} else {
 					Print(L"\"%s\"", bpart->gpt.ent.ent_name);
 				}
-			
+
 				/* Size in MB */
 				size = (le64toh(bpart->gpt.ent.ent_lba_end) - le64toh(bpart->gpt.ent.ent_lba_start)) * bdev->bio->Media->BlockSize;
 				size /= (1024 * 1024);
@@ -565,7 +521,7 @@ efi_block_open(struct open_file *f, ...)
 	char *path;
 	va_list ap;
 	int rv, n;
-	
+
 	va_start(ap, f);
 	fname = va_arg(ap, const char *);
 	file = va_arg(ap, char **);
@@ -603,7 +559,7 @@ efi_block_strategy(void *devdata, int rw
 {
 	struct efi_block_part *bpart = devdata;
 	EFI_STATUS status;
-	void *allocated_buf, *aligned_buf;
+	UINT64 off;
 
 	if (rw != F_READ)
 		return EROFS;
@@ -612,48 +568,21 @@ efi_block_strategy(void *devdata, int rw
 
 	switch (bpart->type) {
 	case EFI_BLOCK_PART_DISKLABEL:
-		if (bpart->bdev->bio->Media->BlockSize != bpart->disklabel.secsize) {
-			printf("%s: unsupported block size %d (expected %d)\n", __func__,
-			    bpart->bdev->bio->Media->BlockSize, bpart->disklabel.secsize);
-			return EIO;
-		}
-		dblk += bpart->disklabel.part.p_offset;
+		off = (dblk + bpart->disklabel.part.p_offset) * DEV_BSIZE;
 		break;
 	case EFI_BLOCK_PART_GPT:
-		if (bpart->bdev->bio->Media->BlockSize != DEV_BSIZE) {
-			printf("%s: unsupported block size %d (expected %d)\n", __func__,
-			    bpart->bdev->bio->Media->BlockSize, DEV_BSIZE);
-			return EIO;
-		}
-		dblk += le64toh(bpart->gpt.ent.ent_lba_start);
+		off = (dblk + le64toh(bpart->gpt.ent.ent_lba_start)) * DEV_BSIZE;
 		break;
 	case EFI_BLOCK_PART_CD9660:
-		dblk *= ISO_DEFAULT_BLOCK_SIZE / bpart->bdev->bio->Media->BlockSize;
+		off = dblk * ISO_DEFAULT_BLOCK_SIZE;
 		break;
 	default:
 		return EINVAL;
 	}
 
-	if ((bpart->bdev->bio->Media->IoAlign <= 1) ||
-		((intptr_t)buf & (bpart->bdev->bio->Media->IoAlign - 1)) == 0) {
-		allocated_buf = NULL;
-		aligned_buf = buf;
-	} else if ((allocated_buf = efi_block_allocate_device_buffer(bpart->bdev,
-		size, &aligned_buf)) == NULL) {
-		return ENOMEM;
-	}
-
-	status = uefi_call_wrapper(bpart->bdev->bio->ReadBlocks, 5,
-		bpart->bdev->bio, bpart->bdev->media_id, dblk, size, aligned_buf);
-	if (EFI_ERROR(status)) {
-		if (allocated_buf != NULL)
-			FreePool(allocated_buf);
+	status = efi_block_disk_read(bpart->bdev, off, buf, size);
+	if (EFI_ERROR(status))
 		return EIO;
-	}
-	if (allocated_buf != NULL) {
-		memcpy(buf, aligned_buf, size);
-		FreePool(allocated_buf);
-	}
 
 	*rsize = size;
 

Index: src/sys/stand/efiboot/efiblock.h
diff -u src/sys/stand/efiboot/efiblock.h:1.4 src/sys/stand/efiboot/efiblock.h:1.5
--- src/sys/stand/efiboot/efiblock.h:1.4	Sun Oct 11 14:03:33 2020
+++ src/sys/stand/efiboot/efiblock.h	Mon Jun 21 11:11:33 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: efiblock.h,v 1.4 2020/10/11 14:03:33 jmcneill Exp $ */
+/* $NetBSD: efiblock.h,v 1.5 2021/06/21 11:11:33 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -43,6 +43,7 @@ struct efi_block_dev {
 	uint16_t index;
 	EFI_DEVICE_PATH *path;
 	EFI_BLOCK_IO *bio;
+	EFI_DISK_IO *dio;
 	UINT32 media_id;
 	TAILQ_HEAD(, efi_block_part) partitions;
 

Index: src/sys/stand/efiboot/version
diff -u src/sys/stand/efiboot/version:1.26 src/sys/stand/efiboot/version:1.27
--- src/sys/stand/efiboot/version:1.26	Sun Jun 20 19:10:47 2021
+++ src/sys/stand/efiboot/version	Mon Jun 21 11:11:33 2021
@@ -1,4 +1,4 @@
-$NetBSD: version,v 1.26 2021/06/20 19:10:47 jmcneill Exp $
+$NetBSD: version,v 1.27 2021/06/21 11:11:33 jmcneill Exp $
 
 NOTE ANY CHANGES YOU MAKE TO THE EFI BOOTLOADER HERE.  The format of this
 file is important - make sure the entries are appended on end, last item
@@ -30,3 +30,4 @@ is taken as the current.
 2.7:	Add basic support for booting from RAID1 volumes.
 2.8:	Add bi-endian disklabel and FFS support.
 2.9:	Watchdog support.
+2.10:	Use disk I/O protocol for block devices.

Reply via email to