From 7eaacdbf00ec29931553384f914c229c6078582e Mon Sep 17 00:00:00 2001 Message-Id: <7eaacdbf00ec29931553384f914c229c6078582e.1652945863.git.stefan@agner.ch> In-Reply-To: <184b6a054e04bb4c7fb4885a30d62314229dc551.1652945863.git.stefan@agner.ch> References: <184b6a054e04bb4c7fb4885a30d62314229dc551.1652945863.git.stefan@agner.ch> From: Stefan Agner Date: Thu, 5 May 2022 15:46:51 +0200 Subject: [PATCH] efidisk: pass buffers with higher alignment Some devices report a IoAlign value of 2, however seem to require a buffer with higher alignment. The UEFI specification is saying: "IoAlign values of 0 and 1 mean that the buffer can be placed anywhere in memory. Otherwise, IoAlign must be a power of 2, and the requirement is that the start address of a buffer must be evenly divisible by IoAlign with no remainder." It seems that this got misinterpreted by some vendors assuming IoAlign is 2^IoAlign. There is also such a hint in an example in earlier versions of the Driver Writer's Guide: ScsiPassThruMode.IoAlign = 2; // Data must be alligned on 4-byte boundary However, it is unsafe to just blindly align buffers by 2^IoAlign, as this would lead to an overflow for systems which use block size alignment (e.g. 512 bytes, for example U-Boot). Ontop of that, some devices seem to report no alignment requirements but seem to read corrupt data or report read errors if the buffer is not aligned. Work around by using an alignment of at least BlockSize (typically 512 bytes) in any casea. Also make sure that IoAlign is still respected as per UEFI specification if a higher alignment than block size is requested. Note: The problem has only noticed with compressed squashfs. It seems that ext4 (and presumably other file system drivers) pass buffers with a higher alignment already. Acked-by: Heinrich Schuchardt Signed-off-by: Stefan Agner --- grub-core/disk/efi/efidisk.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c index 9e20af70e..c6e37f131 100644 --- a/grub-core/disk/efi/efidisk.c +++ b/grub-core/disk/efi/efidisk.c @@ -553,8 +553,19 @@ grub_efidisk_readwrite (struct grub_disk *disk, grub_disk_addr_t sector, d = disk->data; bio = d->block_io; - /* Set alignment to 1 if 0 specified */ - io_align = bio->media->io_align ? bio->media->io_align : 1; + /* + * If IoAlign is > 1, it should represent the required alignment. However, + * some UEFI implementation on Intel NUC systems seem to use IoAlign=2 but + * require 2^IoAlign. Some implementation seem to require alignment despite + * not reporting any requirements. + * + * Make sure to align to at least block size in any case. + */ + if (bio->media->io_align < bio->media->block_size) + io_align = bio->media->block_size; + else + io_align = bio->media->io_align; + num_bytes = size << disk->log_sector_size; if ((grub_addr_t) buf & (io_align - 1)) -- 2.36.1