summaryrefslogtreecommitdiff
path: root/packages/linux/linux-handhelds-2.6-2.6.16/pitre-tls-2651.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/linux-handhelds-2.6-2.6.16/pitre-tls-2651.patch')
-rw-r--r--packages/linux/linux-handhelds-2.6-2.6.16/pitre-tls-2651.patch294
1 files changed, 294 insertions, 0 deletions
diff --git a/packages/linux/linux-handhelds-2.6-2.6.16/pitre-tls-2651.patch b/packages/linux/linux-handhelds-2.6-2.6.16/pitre-tls-2651.patch
new file mode 100644
index 0000000000..5ef318e4ac
--- /dev/null
+++ b/packages/linux/linux-handhelds-2.6-2.6.16/pitre-tls-2651.patch
@@ -0,0 +1,294 @@
+--- linux-2.6.orig/arch/arm/kernel/entry-armv.S
++++ linux-2.6/arch/arm/kernel/entry-armv.S
+@@ -269,6 +269,12 @@
+ add r5, sp, #S_PC
+ ldmia r7, {r2 - r4} @ Get USR pc, cpsr
+
++#if __LINUX_ARM_ARCH__ < 6
++ @ make sure our user space atomic helper is aborted
++ cmp r2, #VIRT_OFFSET
++ bichs r3, r3, #PSR_Z_BIT
++#endif
++
+ @
+ @ We are now ready to fill in the remaining blanks on the stack:
+ @
+@@ -499,8 +505,12 @@
+ mra r4, r5, acc0
+ stmia ip, {r4, r5}
+ #endif
++#ifdef CONFIG_HAS_TLS_REG
++ mcr p15, 0, r3, c13, c0, 3 @ set TLS register
++#else
+ mov r4, #0xffff0fff
+- str r3, [r4, #-3] @ Set TLS ptr
++ str r3, [r4, #-15] @ TLS val at 0xffff0ff0
++#endif
+ mcr p15, 0, r6, c3, c0, 0 @ Set domain register
+ #ifdef CONFIG_VFP
+ @ Always disable VFP so we can lazily save/restore the old
+@@ -519,6 +529,196 @@
+ ldmib r2, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
+
+ __INIT
++
++/*
++ * User helpers.
++ *
++ * These are segment of kernel provided user code reachable from user space
++ * at a fixed address in kernel memory. This is used to provide user space
++ * with some operations which require kernel help because of unimplemented
++ * native feature and/or instructions in many ARM CPUs. The idea is for
++ * this code to be executed directly in user mode for best efficiency but
++ * which is too intimate with the kernel counter part to be left to user
++ * libraries. In fact this code might even differ from one CPU to another
++ * depending on the available instruction set and restrictions like on
++ * SMP systems. In other words, the kernel reserves the right to change
++ * this code as needed without warning. Only the entry points and their
++ * results are guaranteed to be stable.
++ *
++ * Each segment is 32-byte aligned and will be moved to the top of the high
++ * vector page. New segments (if ever needed) must be added in front of
++ * existing ones. This mechanism should be used only for things that are
++ * really small and justified, and not be abused freely.
++ *
++ * User space is expected to implement those things inline when optimizing
++ * for a processor that has the necessary native support, but only if such
++ * resulting binaries are already to be incompatible with earlier ARM
++ * processors due to the use of unsupported instructions other than what
++ * is provided here. In other words don't make binaries unable to run on
++ * earlier processors just for the sake of not using these kernel helpers
++ * if your compiled code is not going to use the new instructions for other
++ * purpose.
++ */
++
++ .align 5
++__kuser_helper_start:
++
++/*
++ * Reference prototype:
++ *
++ * int __kernel_cmpxchg(int oldval, int newval, int *ptr)
++ *
++ * Input:
++ *
++ * r0 = oldval
++ * r1 = newval
++ * r2 = ptr
++ * lr = return address
++ *
++ * Output:
++ *
++ * r0 = returned value (zero or non-zero)
++ * C flag = set if r0 == 0, clear if r0 != 0
++ *
++ * Clobbered:
++ *
++ * r3, ip, flags
++ *
++ * Definition and user space usage example:
++ *
++ * typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
++ * #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
++ *
++ * Atomically store newval in *ptr if *ptr is equal to oldval for user space.
++ * Return zero if *ptr was changed or non-zero if no exchange happened.
++ * The C flag is also set if *ptr was changed to allow for assembly
++ * optimization in the calling code.
++ *
++ * For example, a user space atomic_add implementation could look like this:
++ *
++ * #define atomic_add(ptr, val) \
++ * ({ register unsigned int *__ptr asm("r2") = (ptr); \
++ * register unsigned int __result asm("r1"); \
++ * asm volatile ( \
++ * "1: @ atomic_add\n\t" \
++ * "ldr r0, [r2]\n\t" \
++ * "mov r3, #0xffff0fff\n\t" \
++ * "add lr, pc, #4\n\t" \
++ * "add r1, r0, %2\n\t" \
++ * "add pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \
++ * "bcc 1b" \
++ * : "=&r" (__result) \
++ * : "r" (__ptr), "rIL" (val) \
++ * : "r0","r3","ip","lr","cc","memory" ); \
++ * __result; })
++ */
++
++__kuser_cmpxchg: @ 0xffff0fc0
++
++#if __LINUX_ARM_ARCH__ < 6
++
++ /*
++ * Theory of operation:
++ *
++ * We set the Z flag before loading oldval. If ever an exception
++ * occurs we can not be sure the loaded value will still be the same
++ * when the exception returns, therefore the user exception handler
++ * will clear the Z flag whenever the interrupted user code was
++ * actually from the kernel address space (see the usr_entry macro).
++ *
++ * The post-increment on the str is used to prevent a race with an
++ * exception happening just after the str instruction which would
++ * clear the Z flag although the exchange was done.
++ */
++ teq ip, ip @ set Z flag
++ ldr ip, [r2] @ load current val
++ add r3, r2, #1 @ prepare store ptr
++ teqeq ip, r0 @ compare with oldval if still allowed
++ streq r1, [r3, #-1]! @ store newval if still allowed
++ subs r0, r2, r3 @ if r2 == r3 the str occured
++ mov pc, lr
++
++#else
++
++ ldrex r3, [r2]
++ subs r3, r3, r0
++ strexeq r3, r1, [r2]
++ rsbs r0, r3, #0
++ mov pc, lr
++
++#endif
++
++ .align 5
++
++/*
++ * Reference prototype:
++ *
++ * int __kernel_get_tls(void)
++ *
++ * Input:
++ *
++ * lr = return address
++ *
++ * Output:
++ *
++ * r0 = TLS value
++ *
++ * Clobbered:
++ *
++ * the Z flag might be lost
++ *
++ * Definition and user space usage example:
++ *
++ * typedef int (__kernel_get_tls_t)(void);
++ * #define __kernel_get_tls (*(__kernel_get_tls_t *)0xffff0fe0)
++ *
++ * Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
++ *
++ * This could be used as follows:
++ *
++ * #define __kernel_get_tls() \
++ * ({ register unsigned int __val asm("r0"); \
++ * asm( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #31" \
++ * : "=r" (__val) : : "lr","cc" ); \
++ * __val; })
++ */
++
++__kuser_get_tls: @ 0xffff0fe0
++
++#ifndef CONFIG_HAS_TLS_REG
++
++ ldr r0, [pc, #(16 - 8)] @ TLS stored at 0xffff0ff0
++ mov pc, lr
++
++#else
++
++ mrc p15, 0, r0, c13, c0, 3 @ read TLS register
++ mov pc, lr
++
++#endif
++
++ .rep 5
++ .word 0 @ pad up to __kuser_helper_version
++ .endr
++
++/*
++ * Reference declaration:
++ *
++ * extern unsigned int __kernel_helper_version;
++ *
++ * Definition and user space usage example:
++ *
++ * #define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
++ *
++ * User space may read this to determine the curent number of helpers
++ * available.
++ */
++
++__kuser_helper_version: @ 0xffff0ffc
++ .word ((__kuser_helper_end - __kuser_helper_start) >> 5)
++__kuser_helper_end:
++
++
+ /*
+ * Vector stubs.
+ *
+@@ -710,12 +910,21 @@
+ stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr}
+
+ add r2, r0, #0x200
+- adr r0, __stubs_start @ copy stubs to 0x200
+- adr r1, __stubs_end
+-1: ldr r3, [r0], #4
++ adr r1, __stubs_start @ copy stubs to 0x200
++ adr r4, __stubs_end
++1: ldr r3, [r1], #4
+ str r3, [r2], #4
+- cmp r0, r1
+- blt 1b
++ cmp r1, r4
++ blo 1b
++
++ add r2, r0, #0x1000 @ top of high vector page
++ adr r4, __kuser_helper_end @ user helpers to top of page
++ adr r1, __kuser_helper_start @ going downwards.
++1: ldr r3, [r4, #-4]!
++ str r3, [r2, #-4]!
++ cmp r4, r1
++ bhi 1b
++
+ LOADREGS(fd, sp!, {r4 - r6, pc})
+
+ .data
+Index: linux-2.6/arch/arm/kernel/traps.c
+===================================================================
+--- linux-2.6.orig/arch/arm/kernel/traps.c
++++ linux-2.6/arch/arm/kernel/traps.c
+@@ -454,13 +454,17 @@
+
+ case NR(set_tls):
+ thread->tp_value = regs->ARM_r0;
++#ifdef CONFIG_HAS_TLS_REG
++ asm ("mcr p15, 0, %0, c13, c0, 3" : : "r" (regs->ARM_r0) );
++#else
+ /*
+- * Our user accessible TLS ptr is located at 0xffff0ffc.
+- * On SMP read access to this address must raise a fault
+- * and be emulated from the data abort handler.
+- * m
++ * User space must never try to access this directly.
++ * Expect your app to break eventually if you do so.
++ * The user helper at 0xffff0fe0 must be used instead.
++ * (see entry-armv.S for details)
+ */
+- *((unsigned long *)0xffff0ffc) = thread->tp_value;
++ *((unsigned int *)0xffff0ff0) = regs->ARM_r0;
++#endif
+ return 0;
+
+ default:
+--- kernel26/include/asm-arm/unistd.h.old 2005-04-16 05:17:08.344899152 +0100
++++ kernel26/include/asm-arm/unistd.h 2005-04-16 05:17:54.027954272 +0100
+@@ -315,10 +315,9 @@
+ #define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
+ #define __ARM_NR_usr26 (__ARM_NR_BASE+3)
+ #define __ARM_NR_usr32 (__ARM_NR_BASE+4)
++#define __ARM_NR_set_tls (__ARM_NR_BASE+5)
+ #define __ARM_NR_lbl (__ARM_NR_BASE+9)
+
+-#define __ARM_NR_set_tls (__ARM_NR_BASE+0x800)
+-
+ #define __sys2(x) #x
+ #define __sys1(x) __sys2(x)
+