[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 16:16:24 UTC 2017
On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk at 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 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
>
> 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.
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));
>>
>
More information about the U-Boot
mailing list