Misaligned memory accesses handling & ARMv6/ARMv7 | |
| [Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] | |
Hi, Starting with ARMv6, unaligned memory accesses for the data types which have size up to 32-bit (halfwords and words) are supported when U bit is set in CP15 register c1 (and it is always set in linux). But unaligned doubleword or multiword reads or writes still generate an exception (regardless of the value in A bit). Results of unaligned memory accesses for various A and U bit combinations can be found in table 4-3 from ARM1136JF-S technical reference manual. And ARMv7 has unaligned memory access support permanently enabled, dropping legacy alignment model (with that weird bit rotation on unaligned accesses). The problem is that this new alignment support feature of ARMv6 and higher is not handled properly in 'alignment.c'. More specifically, if CPU encounters unaligned multiword memory access (a bug in the program), it results in exception which isn't handled properly in the kernel. The result is that the buggy program just gets stuck on the problematic instruction, constantly triggering exceptions. A testcase which can be used to reproduce this problem is attached (unaligned_multiword_testcase.c). One more testcase which uses only C code is in 'testalign.c', but it is less reliable as the presence/absence of problematic multiword memory access instruction depends on the optimizations done by the compiler and its version. The attached patch makes alignment logic behave more reasonably for ARMv6: echo 0 > /proc/cpu/alignment /media/mmc2/testalign i = 05040302 Bus error (core dumped) echo 1 > /proc/cpu/alignment /media/mmc2/testalign i = 05040302 [ 131.023437] Alignment trap: testalign (1629) PC=0x00008398 Instr=0xe8940003 Address=0x00010599 FSR 0x011 Bus error (core dumped) echo 2 > /proc/cpu/alignment /media/mmc2/testalign i = 05040302 s.a = 05040302, s.b = 09080706 echo 3 > /proc/cpu/alignment /media/mmc2/testalign i = 05040302 [ 148.453125] Alignment trap: testalign (1673) PC=0x00008398 Instr=0xe8940003 Address=0x00010599 FSR 0x011 s.a = 05040302, s.b = 09080706 So normal 32-bit unaligned memory accesses are still fine (by the way, just setting A bit we would get exceptions on every unaligned memory accesses, even those that could be correctly and efficiently handled by hardware). And multiword accesses are either emulated in the kernel or terminate application depending on the settings in /proc/cpu/alignment Please review the patch and let me know if anything is wrong with it. Having this issue fixed will make alignment problems debugging much easier as buggy applications will crash and generate core dumps instead of deadlocking, which is pretty confusing. -- Best regards, Siarhei Siamashka
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index aa109f0..a440177 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -768,6 +768,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
if (ai_usermode & 4)
force_sig(SIGBUS, current);
+ else if (cpu_architecture() >= CPU_ARCH_ARMv6) /* For ARMv6 we can't skip unaligned instruction */
+ force_sig(SIGBUS, current);
else
set_cr(cr_no_alignment);
@@ -800,6 +802,13 @@ static int __init alignment_init(void)
hook_fault_code(1, do_alignment, SIGILL, "alignment exception");
hook_fault_code(3, do_alignment, SIGILL, "alignment exception");
+ if (cpu_architecture() >= CPU_ARCH_ARMv6) {
+ /* ARMv6 does not particularly need A bit when U bit is set, we get alignment exceptions anyway */
+ cr_alignment &= ~CR_A;
+ cr_no_alignment &= ~CR_A;
+ set_cr(cr_alignment);
+ }
+
return 0;
}
int main()
{
int buffer[3];
asm volatile ("ldmia %0, {r1, r2}\r\n"
:
: "r" ((char *)buffer + 1)
: "r1", "r2");
return 0;
}
#include <stdio.h>
struct dword_struct
{
int a;
int b;
};
char __attribute__ ((aligned(32))) buffer[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 };
int main()
{
struct dword_struct s;
int i = *(int *)&buffer[1];
printf("i = %08X\n", i);
s = *(struct dword_struct *)&buffer[1];
printf("s.a = %08X, s.b = %08X\n", s.a, s.b);
}
------------------------------------------------------------------- List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
[Site Home] [Linux Arm] [Fedora ARM] [Gcc Help] [Git] [DCCP] [IETF Announce] [Security] [PDAs] [Linux] [Linux Book List] [Linux MIPS] [Yosemite Campsites] [Photos]
![]() |
|