diff options
-rw-r--r-- | arch/arm/include/asm/thread_info.h | 2 | ||||
-rw-r--r-- | arch/arm/include/asm/tls.h | 40 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 5 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 4 |
6 files changed, 37 insertions, 20 deletions
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 1995d1a84060..214d4158089a 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h | |||
@@ -58,7 +58,7 @@ struct thread_info { | |||
58 | struct cpu_context_save cpu_context; /* cpu context */ | 58 | struct cpu_context_save cpu_context; /* cpu context */ |
59 | __u32 syscall; /* syscall number */ | 59 | __u32 syscall; /* syscall number */ |
60 | __u8 used_cp[16]; /* thread used copro */ | 60 | __u8 used_cp[16]; /* thread used copro */ |
61 | unsigned long tp_value; | 61 | unsigned long tp_value[2]; /* TLS registers */ |
62 | #ifdef CONFIG_CRUNCH | 62 | #ifdef CONFIG_CRUNCH |
63 | struct crunch_state crunchstate; | 63 | struct crunch_state crunchstate; |
64 | #endif | 64 | #endif |
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h index 73409e6c0251..83259b873333 100644 --- a/arch/arm/include/asm/tls.h +++ b/arch/arm/include/asm/tls.h | |||
@@ -2,27 +2,30 @@ | |||
2 | #define __ASMARM_TLS_H | 2 | #define __ASMARM_TLS_H |
3 | 3 | ||
4 | #ifdef __ASSEMBLY__ | 4 | #ifdef __ASSEMBLY__ |
5 | .macro set_tls_none, tp, tmp1, tmp2 | 5 | #include <asm/asm-offsets.h> |
6 | .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2 | ||
6 | .endm | 7 | .endm |
7 | 8 | ||
8 | .macro set_tls_v6k, tp, tmp1, tmp2 | 9 | .macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2 |
10 | mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register | ||
9 | mcr p15, 0, \tp, c13, c0, 3 @ set TLS register | 11 | mcr p15, 0, \tp, c13, c0, 3 @ set TLS register |
10 | mov \tmp1, #0 | 12 | mcr p15, 0, \tpuser, c13, c0, 2 @ and the user r/w register |
11 | mcr p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register | 13 | str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it |
12 | .endm | 14 | .endm |
13 | 15 | ||
14 | .macro set_tls_v6, tp, tmp1, tmp2 | 16 | .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2 |
15 | ldr \tmp1, =elf_hwcap | 17 | ldr \tmp1, =elf_hwcap |
16 | ldr \tmp1, [\tmp1, #0] | 18 | ldr \tmp1, [\tmp1, #0] |
17 | mov \tmp2, #0xffff0fff | 19 | mov \tmp2, #0xffff0fff |
18 | tst \tmp1, #HWCAP_TLS @ hardware TLS available? | 20 | tst \tmp1, #HWCAP_TLS @ hardware TLS available? |
19 | mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register | ||
20 | movne \tmp1, #0 | ||
21 | mcrne p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register | ||
22 | streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0 | 21 | streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0 |
22 | mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register | ||
23 | mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register | ||
24 | mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register | ||
25 | strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it | ||
23 | .endm | 26 | .endm |
24 | 27 | ||
25 | .macro set_tls_software, tp, tmp1, tmp2 | 28 | .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2 |
26 | mov \tmp1, #0xffff0fff | 29 | mov \tmp1, #0xffff0fff |
27 | str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0 | 30 | str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0 |
28 | .endm | 31 | .endm |
@@ -31,19 +34,30 @@ | |||
31 | #ifdef CONFIG_TLS_REG_EMUL | 34 | #ifdef CONFIG_TLS_REG_EMUL |
32 | #define tls_emu 1 | 35 | #define tls_emu 1 |
33 | #define has_tls_reg 1 | 36 | #define has_tls_reg 1 |
34 | #define set_tls set_tls_none | 37 | #define switch_tls switch_tls_none |
35 | #elif defined(CONFIG_CPU_V6) | 38 | #elif defined(CONFIG_CPU_V6) |
36 | #define tls_emu 0 | 39 | #define tls_emu 0 |
37 | #define has_tls_reg (elf_hwcap & HWCAP_TLS) | 40 | #define has_tls_reg (elf_hwcap & HWCAP_TLS) |
38 | #define set_tls set_tls_v6 | 41 | #define switch_tls switch_tls_v6 |
39 | #elif defined(CONFIG_CPU_32v6K) | 42 | #elif defined(CONFIG_CPU_32v6K) |
40 | #define tls_emu 0 | 43 | #define tls_emu 0 |
41 | #define has_tls_reg 1 | 44 | #define has_tls_reg 1 |
42 | #define set_tls set_tls_v6k | 45 | #define switch_tls switch_tls_v6k |
43 | #else | 46 | #else |
44 | #define tls_emu 0 | 47 | #define tls_emu 0 |
45 | #define has_tls_reg 0 | 48 | #define has_tls_reg 0 |
46 | #define set_tls set_tls_software | 49 | #define switch_tls switch_tls_software |
47 | #endif | 50 | #endif |
48 | 51 | ||
52 | #ifndef __ASSEMBLY__ | ||
53 | static inline unsigned long get_tpuser(void) | ||
54 | { | ||
55 | unsigned long reg = 0; | ||
56 | |||
57 | if (has_tls_reg && !tls_emu) | ||
58 | __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (reg)); | ||
59 | |||
60 | return reg; | ||
61 | } | ||
62 | #endif | ||
49 | #endif /* __ASMARM_TLS_H */ | 63 | #endif /* __ASMARM_TLS_H */ |
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 582b405befc5..a39cfc2a1f90 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -685,15 +685,16 @@ ENTRY(__switch_to) | |||
685 | UNWIND(.fnstart ) | 685 | UNWIND(.fnstart ) |
686 | UNWIND(.cantunwind ) | 686 | UNWIND(.cantunwind ) |
687 | add ip, r1, #TI_CPU_SAVE | 687 | add ip, r1, #TI_CPU_SAVE |
688 | ldr r3, [r2, #TI_TP_VALUE] | ||
689 | ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack | 688 | ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack |
690 | THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack | 689 | THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack |
691 | THUMB( str sp, [ip], #4 ) | 690 | THUMB( str sp, [ip], #4 ) |
692 | THUMB( str lr, [ip], #4 ) | 691 | THUMB( str lr, [ip], #4 ) |
692 | ldr r4, [r2, #TI_TP_VALUE] | ||
693 | ldr r5, [r2, #TI_TP_VALUE + 4] | ||
693 | #ifdef CONFIG_CPU_USE_DOMAINS | 694 | #ifdef CONFIG_CPU_USE_DOMAINS |
694 | ldr r6, [r2, #TI_CPU_DOMAIN] | 695 | ldr r6, [r2, #TI_CPU_DOMAIN] |
695 | #endif | 696 | #endif |
696 | set_tls r3, r4, r5 | 697 | switch_tls r1, r4, r5, r3, r7 |
697 | #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) | 698 | #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) |
698 | ldr r7, [r2, #TI_TASK] | 699 | ldr r7, [r2, #TI_TASK] |
699 | ldr r8, =__stack_chk_guard | 700 | ldr r8, =__stack_chk_guard |
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index f21970316836..087064148ebf 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <asm/thread_notify.h> | 39 | #include <asm/thread_notify.h> |
40 | #include <asm/stacktrace.h> | 40 | #include <asm/stacktrace.h> |
41 | #include <asm/mach/time.h> | 41 | #include <asm/mach/time.h> |
42 | #include <asm/tls.h> | ||
42 | 43 | ||
43 | #ifdef CONFIG_CC_STACKPROTECTOR | 44 | #ifdef CONFIG_CC_STACKPROTECTOR |
44 | #include <linux/stackprotector.h> | 45 | #include <linux/stackprotector.h> |
@@ -343,7 +344,8 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start, | |||
343 | clear_ptrace_hw_breakpoint(p); | 344 | clear_ptrace_hw_breakpoint(p); |
344 | 345 | ||
345 | if (clone_flags & CLONE_SETTLS) | 346 | if (clone_flags & CLONE_SETTLS) |
346 | thread->tp_value = childregs->ARM_r3; | 347 | thread->tp_value[0] = childregs->ARM_r3; |
348 | thread->tp_value[1] = get_tpuser(); | ||
347 | 349 | ||
348 | thread_notify(THREAD_NOTIFY_COPY, thread); | 350 | thread_notify(THREAD_NOTIFY_COPY, thread); |
349 | 351 | ||
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 03deeffd9f6d..2bc1514d6dbe 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c | |||
@@ -849,7 +849,7 @@ long arch_ptrace(struct task_struct *child, long request, | |||
849 | #endif | 849 | #endif |
850 | 850 | ||
851 | case PTRACE_GET_THREAD_AREA: | 851 | case PTRACE_GET_THREAD_AREA: |
852 | ret = put_user(task_thread_info(child)->tp_value, | 852 | ret = put_user(task_thread_info(child)->tp_value[0], |
853 | datap); | 853 | datap); |
854 | break; | 854 | break; |
855 | 855 | ||
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 18b32e8e4497..517bfd4da1c9 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -581,7 +581,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) | |||
581 | return regs->ARM_r0; | 581 | return regs->ARM_r0; |
582 | 582 | ||
583 | case NR(set_tls): | 583 | case NR(set_tls): |
584 | thread->tp_value = regs->ARM_r0; | 584 | thread->tp_value[0] = regs->ARM_r0; |
585 | if (tls_emu) | 585 | if (tls_emu) |
586 | return 0; | 586 | return 0; |
587 | if (has_tls_reg) { | 587 | if (has_tls_reg) { |
@@ -699,7 +699,7 @@ static int get_tp_trap(struct pt_regs *regs, unsigned int instr) | |||
699 | int reg = (instr >> 12) & 15; | 699 | int reg = (instr >> 12) & 15; |
700 | if (reg == 15) | 700 | if (reg == 15) |
701 | return 1; | 701 | return 1; |
702 | regs->uregs[reg] = current_thread_info()->tp_value; | 702 | regs->uregs[reg] = current_thread_info()->tp_value[0]; |
703 | regs->ARM_pc += 4; | 703 | regs->ARM_pc += 4; |
704 | return 0; | 704 | return 0; |
705 | } | 705 | } |