Skip to content

Commit

Permalink
[PATCH] ARM: Fix kernel stack offset calculations
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Russell King committed May 5, 2005
1 parent 897f5ab commit 4f7a181
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 23 deletions.
3 changes: 2 additions & 1 deletion arch/arm/kernel/head.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -131,7 +132,7 @@ __switch_data:
.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
Expand Down
25 changes: 12 additions & 13 deletions arch/arm/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,6 @@ static unsigned long *thread_info_head;
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)
{
Expand All @@ -274,17 +272,16 @@ struct thread_info *alloc_thread_info(struct task_struct *task)
}

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;
}
Expand All @@ -297,7 +294,7 @@ void free_thread_info(struct thread_info *thread)
thread_info_head = p;
nr_thread_info += 1;
} else
ll_free_task_struct(thread);
free_pages((unsigned long)thread, THREAD_SIZE_ORDER);
}

/*
Expand Down Expand Up @@ -350,7 +347,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long stack_start,
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;
Expand Down Expand Up @@ -447,15 +444,17 @@ EXPORT_SYMBOL(kernel_thread);
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))
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/kernel/sys_arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ long execve(const char *filename, char **argv, char **envp)
"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");
Expand Down
3 changes: 2 additions & 1 deletion arch/arm/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
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);
}
Expand Down
3 changes: 2 additions & 1 deletion arch/arm/kernel/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <asm-generic/vmlinux.lds.h>
#include <linux/config.h>
#include <asm/thread_info.h>

OUTPUT_ARCH(arm)
ENTRY(stext)
Expand Down Expand Up @@ -103,7 +104,7 @@ SECTIONS
__data_loc = ALIGN(4); /* location in binary */
. = DATAADDR;
#else
. = ALIGN(8192);
. = ALIGN(THREAD_SIZE);
__data_loc = .;
#endif

Expand Down
7 changes: 3 additions & 4 deletions include/asm-arm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -87,8 +85,9 @@ unsigned long get_wchan(struct task_struct *p);
*/
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.
Expand Down
6 changes: 4 additions & 2 deletions include/asm-arm/thread_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -77,8 +81,6 @@ struct thread_info {
#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
*/
Expand Down

0 comments on commit 4f7a181

Please sign in to comment.