@@ -79,6 +79,9 @@ struct cpu_context {
struct thread_struct {
struct cpu_context cpu_context; /* cpu context */
unsigned long tp_value;
+#ifdef CONFIG_COMPAT
+ unsigned long tp_compat;
+#endif
struct fpsimd_state fpsimd_state;
unsigned long fault_address; /* fault info */
unsigned long fault_code; /* ESR_EL1 value */
@@ -58,6 +58,22 @@ unsigned long __stack_chk_guard __read_mostly;
EXPORT_SYMBOL(__stack_chk_guard);
#endif
+static unsigned long get_tp_compat(struct thread_struct *p)
+{
+#ifdef CONFIG_COMPAT
+ return p->tp_compat;
+#else
+ return 0;
+#endif
+}
+
+static void set_tp_compat(struct thread_struct *p, unsigned long tpidr)
+{
+#ifdef CONFIG_COMPAT
+ p->tp_compat = tpidr;
+#endif
+}
+
void soft_restart(unsigned long addr)
{
setup_mm_for_reboot();
@@ -219,6 +235,7 @@ static void tls_thread_flush(void)
if (is_compat_task()) {
current->thread.tp_value = 0;
+ set_tp_compat(¤t->thread, 0);
/*
* We need to ensure ordering between the shadow state and the
@@ -259,17 +276,22 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
if (likely(!(p->flags & PF_KTHREAD))) {
+ unsigned long tpidr;
*childregs = *current_pt_regs();
childregs->regs[0] = 0;
+ /*
+ * Read the current TLS pointer from tpidr_el0 as it may be
+ * out-of-sync with the saved value.
+ */
+ asm("mrs %0, tpidr_el0" : "=r" (tpidr));
if (is_compat_thread(task_thread_info(p))) {
+ set_tp_compat(&p->thread, tpidr);
+
if (stack_start)
childregs->compat_sp = stack_start;
} else {
- /*
- * Read the current TLS pointer from tpidr_el0 as it may be
- * out-of-sync with the saved value.
- */
- asm("mrs %0, tpidr_el0" : "=r" (tls));
+ tls = tpidr;
+
if (stack_start) {
/* 16-byte aligned stack mandatory on AArch64 */
if (stack_start & 15)
@@ -302,13 +324,14 @@ static void tls_thread_switch(struct task_struct *next)
{
unsigned long tpidr, tpidrro;
- if (!is_compat_task()) {
- asm("mrs %0, tpidr_el0" : "=r" (tpidr));
+ asm("mrs %0, tpidr_el0" : "=r" (tpidr));
+ if (is_compat_task())
+ set_tp_compat(¤t->thread, tpidr);
+ else
current->thread.tp_value = tpidr;
- }
if (is_compat_thread(task_thread_info(next))) {
- tpidr = 0;
+ tpidr = get_tp_compat(&next->thread);
tpidrro = next->thread.tp_value;
} else {
tpidr = next->thread.tp_value;