IPC SHM alignment on ARMv7
Alexander Kartashov
alekskartashov at parallels.com
Thu Jan 31 08:32:18 EST 2013
Dear colleagues,
It tuned out that IPC SHM works in a bit strange way on ARMv7:
the syscall sys_shmat() requires the argument shmaddr to be SHMLBA-aligned:
[ipc/shm.c]
[...]
979 else if ((addr = (ulong)shmaddr)) {
980 if (addr & (shmlba - 1)) {
981 if (shmflg & SHM_RND)
982 addr &= ~(shmlba - 1); /* round down */
983 else
984 #ifndef __ARCH_FORCE_SHMLBA
985 if (addr & ~PAGE_MASK)
986 #endif
987 goto out;
988 }
989 flags = MAP_SHARED | MAP_FIXED;
[...]
since macro __ARCH_FORCE_SHMLBA is unconditionally defined for the ARM
architecture. However it uses the function arch_get_unmapped_area()
introduced in the commit 4197692eef113eeb8e3e413cc70993a5e667e5b8
in the mainstream kernel to allocate memory for a SHM segment.
However the function allocates SHMLBA-aligned memory only if
I or D caches alias as the following comment reads:
[arch/arm/mm/mmap.c]
[...]
54 unsigned long
55 arch_get_unmapped_area(struct file *filp, unsigned long addr,
56 unsigned long len, unsigned long pgoff, unsigned long flags)
57 {
58 struct mm_struct *mm = current->mm;
59 struct vm_area_struct *vma;
60 int do_align = 0;
61 int aliasing = cache_is_vipt_aliasing();
62 struct vm_unmapped_area_info info;
63
64 /*
65 * We only need to do colour alignment if either the I or D
66 * caches alias.
67 */
68 if (aliasing)
69 do_align = filp || (flags & MAP_SHARED);
[...]
So a SHM segment isn't always SHMLBA-aligned.
This results in the following inconvenience: the address returned
by the syscall sys_shmat() may not be passed as its argument
later. This is however crucial for implementing IPC SHM
checkpoint/restore for the ARM architecture I'm currently working on.
As far as I can see from the commit c0e9587841a0fd79bbf8296034faefb9afe72fb4
in the mainstream kernel:
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 1939c90..5b121d8 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -67,6 +67,8 @@ unsigned int processor_id;
EXPORT_SYMBOL(processor_id);
unsigned int __machine_arch_type;
EXPORT_SYMBOL(__machine_arch_type);
+unsigned int cacheid;
+EXPORT_SYMBOL(cacheid);
unsigned int __atags_pointer __initdata;
@@ -229,6 +231,25 @@ int cpu_architecture(void)
return cpu_arch;
}
+static void __init cacheid_init(void)
+{
+ unsigned int cachetype = read_cpuid_cachetype();
+ unsigned int arch = cpu_architecture();
+
+ if (arch >= CPU_ARCH_ARMv7) {
+ cacheid = CACHEID_VIPT_NONALIASING;
+ if ((cachetype & (3 << 14)) == 1 << 14)
+ cacheid |= CACHEID_ASID_TAGGED;
+ } else if (arch >= CPU_ARCH_ARMv6) {
+ if (cachetype & (1 << 23))
+ cacheid = CACHEID_VIPT_ALIASING;
+ else
+ cacheid = CACHEID_VIPT_NONALIASING;
+ } else {
+ cacheid = CACHEID_VIVT;
+ }
+}
+
/*
* These functions re-use the assembly code in head.S, which
the flag CACHEID_VIPT_ALIASING is never set for ARMv7
so it's impossible to guarantee that a IPC SHM segment
is always SHMLBA-aligned.
Is it true that the desired SHM alignment is impossible
to be achieved on the ARMv7 architecture?
--
Sincerely yours,
Alexander Kartashov
Intern
Core team
www.parallels.com
Skype: aleksandr.kartashov
Email: alekskartashov at parallels.com
More information about the linux-arm-kernel
mailing list