Commit 415395e1 authored by Russell King's avatar Russell King

[ARM] Context switch improvements

 - We don't need to save the CPSR.
 - Rearrange thread_info members so we can pull the fields out of
   thread_info more efficiently.
 - Allocate a couple of extra words for CPU specific context saving
   (eg, for Xscale ACC registers)
 - Always leave 8 bytes free at the top of the kernel stack.  This
   prevents the stack becoming completely empty when do_exit() is
   called from an exiting nfsd() thread, and causing the wrong
   pointer to be returned from current_thread_info()
parent baa522c8
......@@ -958,20 +958,15 @@ ENTRY(fp_enter)
.text
/*
* Register switch for ARMv3 and ARMv4 processors
* r0 = previous thread_info, r1 = next thread_info, return previous.
* r0 = previous thread_info, r1 = next thread_info
* previous and next are guaranteed not to be the same.
*/
ENTRY(__switch_to)
stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack
mrs ip, cpsr
str ip, [sp, #-4]! @ Save cpsr_SVC
str sp, [r0, #TI_CPU_SAVE] @ Save sp_SVC
ldr sp, [r1, #TI_CPU_SAVE] @ Get saved sp_SVC
ldr r2, [r1, #TI_CPU_DOMAIN]
ldr ip, [sp], #4
add ip, r0, #TI_CPU_SAVE
ldr r2, [r1, #TI_CPU_DOMAIN]!
stmia ip, {r4 - sl, fp, sp, lr} @ Store most regs on stack
mcr p15, 0, r2, c3, c0 @ Set domain register
msr spsr, ip @ Save tasks CPSR into SPSR for this return
ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously
ldmib r1, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
.section ".text.init",#alloc,#execinstr
/*
......
......@@ -185,7 +185,7 @@ void show_regs(struct pt_regs * regs)
get_fs() == get_ds() ? "kernel" : "user");
#if defined(CONFIG_CPU_32)
{
int ctrl, transbase, dac;
unsigned int ctrl, transbase, dac;
__asm__ (
" mrc p15, 0, %0, c1, c0\n"
" mrc p15, 0, %1, c2, c0\n"
......@@ -314,19 +314,17 @@ int
copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
unsigned long unused, struct task_struct *p, struct pt_regs *regs)
{
struct thread_info *thread = p->thread_info;
struct pt_regs *childregs;
struct cpu_context_save *save;
childregs = ((struct pt_regs *)((unsigned long)p->thread_info + THREAD_SIZE)) - 1;
childregs = ((struct pt_regs *)((unsigned long)thread + THREAD_SIZE - 8)) - 1;
*childregs = *regs;
childregs->ARM_r0 = 0;
childregs->ARM_sp = esp;
save = ((struct cpu_context_save *)(childregs)) - 1;
memset(save, 0, sizeof(struct cpu_context_save));
init_pc_psr(save, ret_from_fork);
p->thread_info->cpu_context = save;
memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
thread->cpu_context.sp = (unsigned long)childregs;
thread->cpu_context.pc = (unsigned long)ret_from_fork;
return 0;
}
......
......@@ -20,27 +20,9 @@
#define __ASM_PROC_PROCESSOR_H
#include <linux/string.h>
#include <asm/proc/ptrace.h>
#define KERNEL_STACK_SIZE 4096
struct cpu_context_save {
unsigned long r4;
unsigned long r5;
unsigned long r6;
unsigned long r7;
unsigned long r8;
unsigned long r9;
unsigned long sl;
unsigned long fp;
unsigned long pc;
};
static inline void init_pc_psr(struct cpu_context_save *s, void *fn)
{
s->pc = ((unsigned long)fn) | PSR_I_BIT | SVC26_MODE;
}
typedef struct {
void (*put_byte)(void); /* Special calling convention */
void (*get_byte)(void); /* Special calling convention */
......@@ -75,7 +57,7 @@ extern uaccess_t uaccess_user, uaccess_kernel;
regs->ARM_r0 = stack[0]; /* r0 (argc) */ \
})
#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1018])
#endif
......@@ -19,29 +19,9 @@
#define __ASM_PROC_PROCESSOR_H
#include <asm/proc/domain.h>
#include <asm/proc/ptrace.h>
#define KERNEL_STACK_SIZE PAGE_SIZE
struct cpu_context_save {
unsigned long cpsr;
unsigned long r4;
unsigned long r5;
unsigned long r6;
unsigned long r7;
unsigned long r8;
unsigned long r9;
unsigned long sl;
unsigned long fp;
unsigned long pc;
};
static inline void init_pc_psr(struct cpu_context_save *s, void *fn)
{
s->pc = (unsigned long)fn;
s->cpsr = PSR_I_BIT | SVC_MODE;
}
#define INIT_EXTRA_THREAD_INFO \
cpu_domain: domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
......@@ -63,7 +43,7 @@ static inline void init_pc_psr(struct cpu_context_save *s, void *fn)
regs->ARM_r0 = stack[0]; /* r0 (argc) */ \
})
#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1021])
#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1017])
#endif
......@@ -22,20 +22,35 @@ struct exec_domain;
#include <asm/ptrace.h>
#include <asm/types.h>
typedef unsigned long mm_segment_t; /* domain register */
typedef unsigned long mm_segment_t;
struct cpu_context_save {
__u32 r4;
__u32 r5;
__u32 r6;
__u32 r7;
__u32 r8;
__u32 r9;
__u32 sl;
__u32 fp;
__u32 sp;
__u32 pc;
__u32 extra[2]; /* Xscale 'acc' register, etc */
};
/*
* low level task data that entry.S needs immediate access to.
* We assume cpu_context follows immedately after cpu_domain.
*/
struct thread_info {
unsigned long flags; /* low level flags */
__s32 preempt_count; /* 0 => preemptable, <0 => bug */
mm_segment_t addr_limit; /* address limit */
__u32 cpu; /* cpu */
struct cpu_context_save *cpu_context; /* cpu context */
__u32 cpu_domain; /* cpu domain */
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
__u32 cpu; /* cpu */
__u32 cpu_domain; /* cpu domain */
struct cpu_context_save cpu_context; /* cpu context */
union fp_state fpstate;
};
......@@ -71,34 +86,20 @@ extern void free_thread_info(struct thread_info *);
#define get_thread_info(ti) get_task_struct((ti)->task)
#define put_thread_info(ti) put_task_struct((ti)->task)
static inline unsigned long __thread_saved_pc(struct thread_info *thread)
{
struct cpu_context_save *context = thread->cpu_context;
return context ? pc_pointer(context->pc) : 0;
}
static inline unsigned long __thread_saved_fp(struct thread_info *thread)
{
struct cpu_context_save *context = thread->cpu_context;
return context ? context->fp : 0;
}
#define thread_saved_pc(tsk) __thread_saved_pc((tsk)->thread_info)
#define thread_saved_fp(tsk) __thread_saved_fp((tsk)->thread_info)
#define thread_saved_pc(tsk) (pc_pointer((tsk)->thread_info->cpu_context.pc))
#define thread_saved_fp(tsk) ((tsk)->thread_info->cpu_context.fp)
#else /* !__ASSEMBLY__ */
#define TI_FLAGS 0
#define TI_PREEMPT 4
#define TI_ADDR_LIMIT 8
#define TI_CPU 12
#define TI_CPU_SAVE 16
#define TI_CPU_DOMAIN 20
#define TI_TASK 24
#define TI_EXEC_DOMAIN 28
#define TI_FPSTATE 32
#define TI_TASK 12
#define TI_EXEC_DOMAIN 16
#define TI_CPU 20
#define TI_CPU_DOMAIN 24
#define TI_CPU_SAVE 28
#define TI_FPSTATE 76
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment