@@ -128,6 +128,7 @@ config ARM
select RTC_LIB
select SET_FS
select SYS_SUPPORTS_APM_EMULATION
+ select THREAD_INFO_IN_TASK if CURRENT_POINTER_IN_TPIDRPRW
# Above selects are sorted alphabetically; please add new ones
# according to that. Thanks.
help
@@ -203,10 +203,14 @@
* Get current thread_info.
*/
.macro get_thread_info, rd
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ mrc p15, 0, \rd, c13, c0, 4
+#else
ARM( mov \rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT )
THUMB( mov \rd, sp )
THUMB( lsr \rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT )
mov \rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
+#endif
.endm
/*
@@ -15,7 +15,11 @@
# error "<asm/smp.h> included in non-SMP build"
#endif
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+#define raw_smp_processor_id() (current->cpu)
+#else
#define raw_smp_processor_id() (current_thread_info()->cpu)
+#endif
struct seq_file;
@@ -55,8 +55,10 @@ struct thread_info {
unsigned long flags; /* low level flags */
int preempt_count; /* 0 => preemptable, <0 => bug */
mm_segment_t addr_limit; /* address limit */
+#ifndef CONFIG_THREAD_INFO_IN_TASK
struct task_struct *task; /* main task structure */
__u32 cpu; /* cpu */
+#endif
__u32 cpu_domain; /* cpu domain */
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
unsigned long stack_canary;
@@ -75,14 +77,21 @@ struct thread_info {
#endif
};
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+#define INIT_THREAD_INFO_TASK(tsk)
+#else
+#define INIT_THREAD_INFO_TASK(tsk) .task = &tsk,
+#endif
+
#define INIT_THREAD_INFO(tsk) \
{ \
- .task = &tsk, \
+ INIT_THREAD_INFO_TASK(tsk) \
.flags = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
.addr_limit = KERNEL_DS, \
}
+#ifndef CONFIG_THREAD_INFO_IN_TASK
/*
* how to get the thread information struct from C
*/
@@ -93,6 +102,7 @@ static inline struct thread_info *current_thread_info(void)
return (struct thread_info *)
(current_stack_pointer & ~(THREAD_SIZE - 1));
}
+#endif
#define thread_saved_pc(tsk) \
((unsigned long)(task_thread_info(tsk)->cpu_context.pc))
@@ -44,8 +44,12 @@ int main(void)
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ DEFINE(TI_CPU, offsetof(struct task_struct, cpu));
+#else
DEFINE(TI_TASK, offsetof(struct thread_info, task));
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
+#endif
DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain));
DEFINE(TI_CPU_SAVE, offsetof(struct thread_info, cpu_context));
DEFINE(TI_USED_CP, offsetof(struct thread_info, used_cp));
@@ -762,9 +762,13 @@ ENTRY(__switch_to)
#endif
switch_tls r1, r4, r5, r3, r7
#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRPRW
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ set_current r2
+#else
ldr r7, [r2, #TI_TASK]
set_current r7
#endif
+#endif
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
ldr r7, [r2, #TI_TASK]
ldr r8, =__stack_chk_guard
@@ -158,7 +158,12 @@ static void vfp_thread_copy(struct thread_info *thread)
*/
static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
{
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ struct task_struct *tsk = v;
+ struct thread_info *thread = &tsk->thread_info;
+#else
struct thread_info *thread = v;
+#endif
u32 fpexc;
#ifdef CONFIG_SMP
unsigned int cpu;
@@ -169,7 +174,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
fpexc = fmrx(FPEXC);
#ifdef CONFIG_SMP
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ cpu = tsk->cpu;
+#else
cpu = thread->cpu;
+#endif
/*
* On SMP, if VFP is enabled, save the old state in
This avoids many stack overflow attacks which modified the thread_info structure by moving that into the task_struct as is done is almost all other architectures. This also involved removing the 'cpu' member from the thread_info struct and using the one added to the task_struct instead by the THREAD_INFO_IN_TASK code. This code is currently enabled only for v7 hardware as most other ARM architectures do not have the TPIDRPRW register that is used to store the current value. It could probably be enabled for v6k architectures as well, but I haven't tested that. With the TPIDRPRW register, the kernel can identify the current cpu. Without that register, there's a circular dependency between the current cpu and 'current' — know one and you can find the other. Leaving the thread_info in the kernel stack lets you find the cpu number independently. Signed-off-by: Keith Packard <keithpac@amazon.com> --- arch/arm/Kconfig | 1 + arch/arm/include/asm/assembler.h | 4 ++++ arch/arm/include/asm/smp.h | 4 ++++ arch/arm/include/asm/thread_info.h | 12 +++++++++++- arch/arm/kernel/asm-offsets.c | 4 ++++ arch/arm/kernel/entry-armv.S | 4 ++++ arch/arm/vfp/vfpmodule.c | 9 +++++++++ 7 files changed, 37 insertions(+), 1 deletion(-)