[PATCH] ARM: Fix kernel stack offset calculations

Various places in the ARM kernel implicitly assumed that kernel
stacks are always 8K due to hard coded constants.  Replace these
constants with definitions.

Correct the allowable range of kernel stack pointer values within
the allocation.  Arrange for the entire kernel stack to be zeroed,
not just the upper 4K if CONFIG_DEBUG_STACK_USAGE is set.

Signed-off-by: Russell King <rmk@arm.linux.org.uk>
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 171b3e8..4733877 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -19,6 +19,7 @@
 #include <asm/procinfo.h>
 #include <asm/ptrace.h>
 #include <asm/constants.h>
+#include <asm/thread_info.h>
 #include <asm/system.h>
 
 #define PROCINFO_MMUFLAGS	8
@@ -131,7 +132,7 @@
 	.long	processor_id			@ r4
 	.long	__machine_arch_type		@ r5
 	.long	cr_alignment			@ r6
-	.long	init_thread_union+8192		@ sp
+	.long	init_thread_union + THREAD_START_SP @ sp
 
 /*
  * The following fragment of code is executed with the MMU on, and uses
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 26eacd3..8f146a4 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -256,8 +256,6 @@
 static unsigned int nr_thread_info;
 
 #define EXTRA_TASK_STRUCT	4
-#define ll_alloc_task_struct() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
-#define ll_free_task_struct(p) free_pages((unsigned long)(p),1)
 
 struct thread_info *alloc_thread_info(struct task_struct *task)
 {
@@ -274,17 +272,16 @@
 	}
 
 	if (!thread)
-		thread = ll_alloc_task_struct();
+		thread = (struct thread_info *)
+			   __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
 
-#ifdef CONFIG_MAGIC_SYSRQ
+#ifdef CONFIG_DEBUG_STACK_USAGE
 	/*
 	 * The stack must be cleared if you want SYSRQ-T to
 	 * give sensible stack usage information
 	 */
-	if (thread) {
-		char *p = (char *)thread;
-		memzero(p+KERNEL_STACK_SIZE, KERNEL_STACK_SIZE);
-	}
+	if (thread)
+		memzero(thread, THREAD_SIZE);
 #endif
 	return thread;
 }
@@ -297,7 +294,7 @@
 		thread_info_head = p;
 		nr_thread_info += 1;
 	} else
-		ll_free_task_struct(thread);
+		free_pages((unsigned long)thread, THREAD_SIZE_ORDER);
 }
 
 /*
@@ -350,7 +347,7 @@
 	struct thread_info *thread = p->thread_info;
 	struct pt_regs *childregs;
 
-	childregs = ((struct pt_regs *)((unsigned long)thread + THREAD_SIZE - 8)) - 1;
+	childregs = ((struct pt_regs *)((unsigned long)thread + THREAD_START_SP)) - 1;
 	*childregs = *regs;
 	childregs->ARM_r0 = 0;
 	childregs->ARM_sp = stack_start;
@@ -447,15 +444,17 @@
 unsigned long get_wchan(struct task_struct *p)
 {
 	unsigned long fp, lr;
-	unsigned long stack_page;
+	unsigned long stack_start, stack_end;
 	int count = 0;
 	if (!p || p == current || p->state == TASK_RUNNING)
 		return 0;
 
-	stack_page = 4096 + (unsigned long)p->thread_info;
+	stack_start = (unsigned long)(p->thread_info + 1);
+	stack_end = ((unsigned long)p->thread_info) + THREAD_SIZE;
+
 	fp = thread_saved_fp(p);
 	do {
-		if (fp < stack_page || fp > 4092+stack_page)
+		if (fp < stack_start || fp > stack_end)
 			return 0;
 		lr = pc_pointer (((unsigned long *)fp)[-1]);
 		if (!in_sched_functions(lr))
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index ef32577..f897ce2 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -302,7 +302,7 @@
 		"b	ret_to_user"
 		:
 		: "r" (current_thread_info()),
-		  "Ir" (THREAD_SIZE - 8 - sizeof(regs)),
+		  "Ir" (THREAD_START_SP - sizeof(regs)),
 		  "r" (&regs),
 		  "Ir" (sizeof(regs))
 		: "r0", "r1", "r2", "r3", "ip", "memory");
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 3a001fe..8988c02 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -218,7 +218,8 @@
 		tsk->comm, tsk->pid, tsk->thread_info + 1);
 
 	if (!user_mode(regs) || in_interrupt()) {
-		dump_mem("Stack: ", regs->ARM_sp, 8192+(unsigned long)tsk->thread_info);
+		dump_mem("Stack: ", regs->ARM_sp,
+			 THREAD_SIZE + (unsigned long)tsk->thread_info);
 		dump_backtrace(regs, tsk);
 		dump_instr(regs);
 	}
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index a39c6a4..ad2d66c 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -5,6 +5,7 @@
 
 #include <asm-generic/vmlinux.lds.h>
 #include <linux/config.h>
+#include <asm/thread_info.h>
 	
 OUTPUT_ARCH(arm)
 ENTRY(stext)
@@ -103,7 +104,7 @@
 	__data_loc = ALIGN(4);		/* location in binary */
 	. = DATAADDR;
 #else
-	. = ALIGN(8192);
+	. = ALIGN(THREAD_SIZE);
 	__data_loc = .;
 #endif
 
diff --git a/include/asm-arm/processor.h b/include/asm-arm/processor.h
index 4a98459..7d4118e 100644
--- a/include/asm-arm/processor.h
+++ b/include/asm-arm/processor.h
@@ -23,8 +23,6 @@
 #include <asm/procinfo.h>
 #include <asm/types.h>
 
-#define KERNEL_STACK_SIZE	PAGE_SIZE
-
 union debug_insn {
 	u32	arm;
 	u16	thumb;
@@ -87,8 +85,9 @@
  */
 extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
-#define KSTK_EIP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1019])
-#define KSTK_ESP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1017])
+#define KSTK_REGS(tsk)	(((struct pt_regs *)(THREAD_START_SP + (unsigned long)(tsk)->thread_info)) - 1)
+#define KSTK_EIP(tsk)	KSTK_REGS(tsk)->ARM_pc
+#define KSTK_ESP(tsk)	KSTK_REGS(tsk)->ARM_sp
 
 /*
  * Prefetching support - only ARMv5.
diff --git a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h
index a61618f..66c585c 100644
--- a/include/asm-arm/thread_info.h
+++ b/include/asm-arm/thread_info.h
@@ -14,6 +14,10 @@
 
 #include <asm/fpstate.h>
 
+#define THREAD_SIZE_ORDER	1
+#define THREAD_SIZE		8192
+#define THREAD_START_SP		(THREAD_SIZE - 8)
+
 #ifndef __ASSEMBLY__
 
 struct task_struct;
@@ -77,8 +81,6 @@
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
 
-#define THREAD_SIZE		8192
-
 /*
  * how to get the thread information struct from C
  */