
On 08/05/2017 06:19 PM, Rob Clark wrote:
On Sat, Aug 5, 2017 at 12:16 PM, Rob Clark robdclark@gmail.com wrote:
On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 08/05/2017 05:58 PM, Rob Clark wrote:
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@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
NAK
We have more then ARM. And other architectures also create exceptions for unaligned access.
I hate platform specific code. It should not be used outside /arch.
To play it save you should not use _packed at all! Use memcpy to transfer between aligned and unaligned memory.
except for reasons I explained in the thread on the patch that added the __packed in the first place. Sorry, this is ugly but we have to do it.
well, to be fair, we don't *have* to do it. The alternative is disable EFI_LOADER on archs that cannot do unaligned accesses. But this seemed like the better option.
In which UEFI protocol do you need the packed structures? Why can't you use memcpy to provide/read the data in these protocols? Why can't you use padding on all architectures?
Best regards
Heinrich
BR, -R
Best regards
Heinrich
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));