[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Rob Clark
robdclark at gmail.com
Sat Aug 5 15:58:38 UTC 2017
Some arch's have trouble with unaligned accesses. Technically
EFI device-path structs should be byte aligned, and the next node
in the path starts immediately after the previous. Meaning that
a pointer to an 'struct efi_device_path' is not necessarily word
aligned. See section 10.3.1 in v2.7 of UEFI spec.
This causes problems not just for u-boot, but also most/all EFI
payloads loaded by u-boot on these archs. Fortunately the common
practice for traversing a device path is to rely on the length
field in the header, rather than the specified length of the
particular device path type+subtype. So the EFI_DP_PAD() macro
will add the specified number of bytes to the tail of device path
structs to pad them to word alignment.
Technically this is non-compliant, BROKEN_UNALIGNED should *only*
be defined on archs that cannot do unaligned accesses.
Signed-off-by: Rob Clark <robdclark at gmail.com>
---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
Mark, this is untested but I think it should solve your crash on the
Banana Pi. Could you give it a try when you get a chance?
arch/arm/config.mk | 2 +-
include/efi_api.h | 30 ++++++++++++++++++++++++++++++
lib/efi_loader/efi_device_path.c | 3 +++
3 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/arch/arm/config.mk b/arch/arm/config.mk
index 1a77779db4..067dc93a9d 100644
--- a/arch/arm/config.mk
+++ b/arch/arm/config.mk
@@ -28,7 +28,7 @@ LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \
$(call cc-option,-arm-use-movt=0,)
PLATFORM_RELFLAGS += $(LLVM_RELFLAGS)
-PLATFORM_CPPFLAGS += -D__ARM__
+PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
ifdef CONFIG_ARM64
PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64
diff --git a/include/efi_api.h b/include/efi_api.h
index ef91e34c7b..ddd1e6100a 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -284,6 +284,31 @@ struct efi_loaded_image {
#define DEVICE_PATH_TYPE_END 0x7f
# define DEVICE_PATH_SUB_TYPE_END 0xff
+/*
+ * Some arch's have trouble with unaligned accesses. Technically
+ * EFI device-path structs should be byte aligned, and the next node
+ * in the path starts immediately after the previous. Meaning that
+ * a pointer to an 'struct efi_device_path' is not necessarily word
+ * aligned. See section 10.3.1 in v2.7 of UEFI spec.
+ *
+ * This causes problems not just for u-boot, but also most/all EFI
+ * payloads loaded by u-boot on these archs. Fortunately the common
+ * practice for traversing a device path is to rely on the length
+ * field in the header, rather than the specified length of the
+ * particular device path type+subtype. So the EFI_DP_PAD() macro
+ * will add the specified number of bytes to the tail of device path
+ * structs to pad them to word alignment.
+ *
+ * Technically this is non-compliant, BROKEN_UNALIGNED should *only*
+ * be defined on archs that cannot do unaligned accesses.
+ */
+
+#ifdef BROKEN_UNALIGNED
+# define EFI_DP_PAD(n) u8 __pad[n]
+#else
+# define EFI_DP_PAD(n)
+#endif
+
struct efi_device_path {
u8 type;
u8 sub_type;
@@ -318,12 +343,14 @@ struct efi_device_path_usb {
struct efi_device_path dp;
u8 parent_port_number;
u8 usb_interface;
+ EFI_DP_PAD(2);
} __packed;
struct efi_device_path_mac_addr {
struct efi_device_path dp;
struct efi_mac_addr mac;
u8 if_type;
+ EFI_DP_PAD(3);
} __packed;
struct efi_device_path_usb_class {
@@ -333,11 +360,13 @@ struct efi_device_path_usb_class {
u8 device_class;
u8 device_subclass;
u8 device_protocol;
+ EFI_DP_PAD(1);
} __packed;
struct efi_device_path_sd_mmc_path {
struct efi_device_path dp;
u8 slot_number;
+ EFI_DP_PAD(3);
} __packed;
#define DEVICE_PATH_TYPE_MEDIA_DEVICE 0x04
@@ -353,6 +382,7 @@ struct efi_device_path_hard_drive_path {
u8 partition_signature[16];
u8 partmap_type;
u8 signature_type;
+ EFI_DP_PAD(1);
} __packed;
struct efi_device_path_cdrom_path {
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index b5acf73f98..515a1f4737 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -402,6 +402,9 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
// TODO efi_device_path_file_path should be variable length:
fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
+#ifdef BROKEN_UNALIGNED
+ fpsize = ALIGN(fpsize, 4);
+#endif
dpsize += fpsize;
start = buf = calloc(1, dpsize + sizeof(END));
--
2.13.0
More information about the U-Boot
mailing list