I am working on a low level trusted bootloader (written in C) running on an ARM Cortex-A53 at EL3. The MMU is not setup and the bootloader is running out of ROM. We are linking in the CC712 TEE-SBROM library, and running into alignment exceptions when performing a load. Prior to Arm compiler 6.13, I was able to force strict alignment using the -mno-unaligned-access. The Alignment Data Abort Exception has returned with the 6.13. More specifically, the exception happens when trying to initialize a local function variable:
char header[] = CC_SB_CERT_UTIL_PEM_HEADER; // value of pem header ends with "0x0a" == line feed char footer[] = CC_SB_CERT_UTIL_PEM_FOOTER; // value of pem footer ends with "0x0a" == line feed
The constant string is stored at a 16-bit aligned address. When it tries to load the address, it generates an alignment exception.Here's a snippet of the assembly:# the address assigned (2-byte aligned) EL3:0x000000000000E640 : ADRP x8,{pc}+0x5000 ; 0x13640 EL3:0x000000000000E644 : ADD x8,x8,#0x50a # * * * # the load command EL3:0x000000000000E668 : LDR x12,[x8,#0]Using ARM Compiler 6.12, the beginning of the string is placed on a 64-bit boundary. Any suggestions on how to do this on 6.13? here are the compiler flags:--target=aarch64-arm-none-eabi -mcpu=cortex-a53 -DARM_V8A -D__A53__ -D__64_BIT__ -DNO_MMU -c -DLITTLE__ENDIAN -DHASLONGLONG -Wall -Werror -Wno-self-assign -mno-unaligned-access -m -D__arm64__ -O0 -DDEBUG -g3 And the Exception:ESR_EL3: 96000021 FAR_EL3: 1334a, Stack Ptr = 34077024
# the address assigned (2-byte aligned) EL3:0x000000000000E640 : ADRP x8,{pc}+0x5000 ; 0x13640 EL3:0x000000000000E644 : ADD x8,x8,#0x50a # * * * # the load command EL3:0x000000000000E668 : LDR x12,[x8,#0]
--target=aarch64-arm-none-eabi -mcpu=cortex-a53 -DARM_V8A -D__A53__ -D__64_BIT__ -DNO_MMU -c -DLITTLE__ENDIAN -DHASLONGLONG -Wall -Werror -Wno-self-assign -mno-unaligned-access -m -D__arm64__ -O0 -DDEBUG -g3
ESR_EL3: 96000021 FAR_EL3: 1334a, Stack Ptr = 34077024
Hi Dave,
I built an admittedly trivial example, but cannot replicate this behavior:
#include <stdio.h> #include <string.h> volatile char *hello = "Hello World"; volatile char *goodbye = "Goodbye now"; int main() { printf("The string is: %s\n", hello); memcpy(hello, goodbye, 12); printf("The string is: %s\n", hello); return 0; }
Testing with the Cortex-A53 FVP, and setting $SCTLR_EL3.A = 1 to catch unaligned accesses, it does indeed trigger when -mno-unaligned-access is not used.I fear that there is a deeper issue here, and you are perhaps simply lucky that the 6.12 build happens to fall on a boundary?
Thank you for looking in to this Ronan. What I have found out with further investigation is that when we hit this scenario, the MMU is disabled. In order for unaligned loads to be supported, the MMU needs to be enabled and the memory region defined as "Normal". My guess is that your test has the MMU enabled.
Since this is happening in 3rd party code that I do not want to modify if at all possible, I was hoping that there would be some compiler option to force strict alignment for the target CPU. Arm Compiler 6.12 seems works, but when I add --no_unassigned_access to the linker, it still complains that the objects are not aligned properly.
Note - this so only happens with optimization turned off. If enable optimization, the issue goes away. I could just be getting lucky vs. something to rely on. The ROM is embedded into the HW, so not something we can change.
I guess my questions is if it is possible for the compiler to generate code that does strict aligned access via command option, or do I need to update the code itself to use attributes? If there is no command option, I may have to enable the MMU in reset vector before jumping to the entry point. We were hoping to not have to do this until we start the next stage bootloader, which is upgrade-able.
Hi again Dave,
I made a more complex example, but still cannot replicate your issue. The -mno-unaligned-access option protects me :(Some potential workarounds are listed below, they will all require some (minor) changes to source...1) Use __attribute__((aligned(x))) in the data definition:
volatile char __attribute__((aligned(4))) hello[] = "Hello World";
2) Use __attribute__((packed)) when referencing data
extern __attribute__((packed)) char hello[];
3) Separate the data into it's own ELF section, and place it in its own region with scatterloading, with something like:
#pragma clang section data = "Howdy" volatile char hello[] = "Hello World";
; scatter file ... DATA1 +0 ALIGN 1024 { main.o (Howdy) } ...
If you would like Arm to investigate more formally, please raise a support case via the link above.
Thanks again Ronan. Enabling the MMU before we initialize the Trustzone CC712 library did fix the issue and allow unassigned loads of memory addresses not on a 64-bit boundary. When you tried to reproduce the problem, did you have the MMU disabled? It is pretty easy to reproduce.
Reading the description of -mno-unaligned-access is a bit confusing. It doesn't necessarily force strict alignment, but pulls in standard libraries that will do byte reads. The problem I have is in the 3rd party ARM CC712Tee libraries. It also seems to only fail using ARM Compiler 6.13. when I build it using 6.12, I don't get these problems using the same compiler options.
I will put in a support request to verify that the cc712tee and tee-sbrom libraries must be run with MMU enabled. our own code is properly aligned (using attributes) so it can run without the MMU enabled.
You are correct that -mno-unaligned-access will not force alignment of data, just that it will not generate such accesses (for example, by doing 4xbyte access rather than a single word load).I'm not familiar (at all!) with the CC712Tee code... are you able to debug which variable is causing the unaligned access, and from there compare its location in the 6.12 and 6.13 build?
Aside, FYI, we have recently released Arm Compiler 6.14.