mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-12-30 01:46:30 -05:00
217 lines
7.3 KiB
Diff
217 lines
7.3 KiB
Diff
From 4f57652fcd2dce7741f1ac6dc0417e2f265cd1de Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Andr=C3=A9=20Hentschel?= <nerv@dawncrow.de>
|
|
Date: Tue, 18 Jun 2013 23:23:26 +0100
|
|
Subject: ARM: 7735/2: Preserve the user r/w register TPIDRURW on context
|
|
switch and fork
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Since commit 6a1c53124aa1 the user writeable TLS register was zeroed to
|
|
prevent it from being used as a covert channel between two tasks.
|
|
|
|
There are more and more applications coming to Windows RT,
|
|
Wine could support them, but mostly they expect to have
|
|
the thread environment block (TEB) in TPIDRURW.
|
|
|
|
This patch preserves that register per thread instead of clearing it.
|
|
Unlike the TPIDRURO, which is already switched, the TPIDRURW
|
|
can be updated from userspace so needs careful treatment in the case that we
|
|
modify TPIDRURW and call fork(). To avoid this we must always read
|
|
TPIDRURW in copy_thread.
|
|
|
|
Change-Id: Ib1e25be7b9faa846ba5335aad2574e21a1246066
|
|
Signed-off-by: André Hentschel <nerv@dawncrow.de>
|
|
Signed-off-by: Will Deacon <will.deacon@arm.com>
|
|
Signed-off-by: Jonathan Austin <jonathan.austin@arm.com>
|
|
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
|
|
Git-commit: a4780adeefd042482f624f5e0d577bf9cdcbb760
|
|
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
|
[joonwoop@codeaurora.org: fixed merge conflict]
|
|
CRs-fixed: 561044
|
|
Signed-off-by: Joonwoo Park <joonwoop@codeaurora.org>
|
|
---
|
|
arch/arm/include/asm/thread_info.h | 2 +-
|
|
arch/arm/include/asm/tls.h | 40 +++++++++++++++++++++++++-------------
|
|
arch/arm/kernel/entry-armv.S | 5 +++--
|
|
arch/arm/kernel/process.c | 4 +++-
|
|
arch/arm/kernel/ptrace.c | 2 +-
|
|
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 67d6443..2eb0c2c 100644
|
|
--- a/arch/arm/include/asm/thread_info.h
|
|
+++ b/arch/arm/include/asm/thread_info.h
|
|
@@ -58,7 +58,7 @@ struct thread_info {
|
|
struct cpu_context_save cpu_context; /* cpu context */
|
|
__u32 syscall; /* syscall number */
|
|
__u8 used_cp[16]; /* thread used copro */
|
|
- unsigned long tp_value;
|
|
+ unsigned long tp_value[2]; /* TLS registers */
|
|
struct crunch_state crunchstate;
|
|
union fp_state fpstate __attribute__((aligned(8)));
|
|
union vfp_state vfpstate;
|
|
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h
|
|
index 73409e6..83259b8 100644
|
|
--- a/arch/arm/include/asm/tls.h
|
|
+++ b/arch/arm/include/asm/tls.h
|
|
@@ -2,27 +2,30 @@
|
|
#define __ASMARM_TLS_H
|
|
|
|
#ifdef __ASSEMBLY__
|
|
- .macro set_tls_none, tp, tmp1, tmp2
|
|
+#include <asm/asm-offsets.h>
|
|
+ .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2
|
|
.endm
|
|
|
|
- .macro set_tls_v6k, tp, tmp1, tmp2
|
|
+ .macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2
|
|
+ mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
|
|
mcr p15, 0, \tp, c13, c0, 3 @ set TLS register
|
|
- mov \tmp1, #0
|
|
- mcr p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register
|
|
+ mcr p15, 0, \tpuser, c13, c0, 2 @ and the user r/w register
|
|
+ str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
|
|
.endm
|
|
|
|
- .macro set_tls_v6, tp, tmp1, tmp2
|
|
+ .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
|
|
ldr \tmp1, =elf_hwcap
|
|
ldr \tmp1, [\tmp1, #0]
|
|
mov \tmp2, #0xffff0fff
|
|
tst \tmp1, #HWCAP_TLS @ hardware TLS available?
|
|
- mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
|
|
- movne \tmp1, #0
|
|
- mcrne p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register
|
|
streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
|
|
+ mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
|
|
+ mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
|
|
+ mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register
|
|
+ strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
|
|
.endm
|
|
|
|
- .macro set_tls_software, tp, tmp1, tmp2
|
|
+ .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
|
|
mov \tmp1, #0xffff0fff
|
|
str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0
|
|
.endm
|
|
@@ -31,19 +34,30 @@
|
|
#ifdef CONFIG_TLS_REG_EMUL
|
|
#define tls_emu 1
|
|
#define has_tls_reg 1
|
|
-#define set_tls set_tls_none
|
|
+#define switch_tls switch_tls_none
|
|
#elif defined(CONFIG_CPU_V6)
|
|
#define tls_emu 0
|
|
#define has_tls_reg (elf_hwcap & HWCAP_TLS)
|
|
-#define set_tls set_tls_v6
|
|
+#define switch_tls switch_tls_v6
|
|
#elif defined(CONFIG_CPU_32v6K)
|
|
#define tls_emu 0
|
|
#define has_tls_reg 1
|
|
-#define set_tls set_tls_v6k
|
|
+#define switch_tls switch_tls_v6k
|
|
#else
|
|
#define tls_emu 0
|
|
#define has_tls_reg 0
|
|
-#define set_tls set_tls_software
|
|
+#define switch_tls switch_tls_software
|
|
#endif
|
|
|
|
+#ifndef __ASSEMBLY__
|
|
+static inline unsigned long get_tpuser(void)
|
|
+{
|
|
+ unsigned long reg = 0;
|
|
+
|
|
+ if (has_tls_reg && !tls_emu)
|
|
+ __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (reg));
|
|
+
|
|
+ return reg;
|
|
+}
|
|
+#endif
|
|
#endif /* __ASMARM_TLS_H */
|
|
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
|
|
index 7a8c2d6..0bdba55 100644
|
|
--- a/arch/arm/kernel/entry-armv.S
|
|
+++ b/arch/arm/kernel/entry-armv.S
|
|
@@ -698,15 +698,16 @@ ENTRY(__switch_to)
|
|
UNWIND(.fnstart )
|
|
UNWIND(.cantunwind )
|
|
add ip, r1, #TI_CPU_SAVE
|
|
- ldr r3, [r2, #TI_TP_VALUE]
|
|
ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack
|
|
THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack
|
|
THUMB( str sp, [ip], #4 )
|
|
THUMB( str lr, [ip], #4 )
|
|
+ ldr r4, [r2, #TI_TP_VALUE]
|
|
+ ldr r5, [r2, #TI_TP_VALUE + 4]
|
|
#ifdef CONFIG_CPU_USE_DOMAINS
|
|
ldr r6, [r2, #TI_CPU_DOMAIN]
|
|
#endif
|
|
- set_tls r3, r4, r5
|
|
+ switch_tls r1, r4, r5, r3, r7
|
|
#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
|
|
ldr r7, [r2, #TI_TASK]
|
|
ldr r8, =__stack_chk_guard
|
|
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
|
|
index 0ff45bd..18e92f6 100644
|
|
--- a/arch/arm/kernel/process.c
|
|
+++ b/arch/arm/kernel/process.c
|
|
@@ -38,6 +38,7 @@
|
|
#include <asm/thread_notify.h>
|
|
#include <asm/stacktrace.h>
|
|
#include <asm/mach/time.h>
|
|
+#include <asm/tls.h>
|
|
|
|
#ifdef CONFIG_CC_STACKPROTECTOR
|
|
#include <linux/stackprotector.h>
|
|
@@ -558,7 +559,8 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
|
|
clear_ptrace_hw_breakpoint(p);
|
|
|
|
if (clone_flags & CLONE_SETTLS)
|
|
- thread->tp_value = regs->ARM_r3;
|
|
+ thread->tp_value[0] = childregs->ARM_r3;
|
|
+ thread->tp_value[1] = get_tpuser();
|
|
|
|
thread_notify(THREAD_NOTIFY_COPY, thread);
|
|
|
|
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
|
|
index 9650c14..c6c6be7 100644
|
|
--- a/arch/arm/kernel/ptrace.c
|
|
+++ b/arch/arm/kernel/ptrace.c
|
|
@@ -844,7 +844,7 @@ long arch_ptrace(struct task_struct *child, long request,
|
|
#endif
|
|
|
|
case PTRACE_GET_THREAD_AREA:
|
|
- ret = put_user(task_thread_info(child)->tp_value,
|
|
+ ret = put_user(task_thread_info(child)->tp_value[0],
|
|
datap);
|
|
break;
|
|
|
|
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
|
|
index 12e6fcb..e0a066b 100644
|
|
--- a/arch/arm/kernel/traps.c
|
|
+++ b/arch/arm/kernel/traps.c
|
|
@@ -593,7 +593,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
|
|
return regs->ARM_r0;
|
|
|
|
case NR(set_tls):
|
|
- thread->tp_value = regs->ARM_r0;
|
|
+ thread->tp_value[0] = regs->ARM_r0;
|
|
if (tls_emu)
|
|
return 0;
|
|
if (has_tls_reg) {
|
|
@@ -711,7 +711,7 @@ static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
|
|
int reg = (instr >> 12) & 15;
|
|
if (reg == 15)
|
|
return 1;
|
|
- regs->uregs[reg] = current_thread_info()->tp_value;
|
|
+ regs->uregs[reg] = current_thread_info()->tp_value[0];
|
|
regs->ARM_pc += 4;
|
|
return 0;
|
|
}
|
|
--
|
|
cgit v1.1
|
|
|