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) ...@@ -958,20 +958,15 @@ ENTRY(fp_enter)
.text .text
/* /*
* Register switch for ARMv3 and ARMv4 processors * 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. * previous and next are guaranteed not to be the same.
*/ */
ENTRY(__switch_to) ENTRY(__switch_to)
stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack add ip, r0, #TI_CPU_SAVE
mrs ip, cpsr ldr r2, [r1, #TI_CPU_DOMAIN]!
str ip, [sp, #-4]! @ Save cpsr_SVC stmia ip, {r4 - sl, fp, sp, lr} @ Store most regs on stack
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
mcr p15, 0, r2, c3, c0 @ Set domain register mcr p15, 0, r2, c3, c0 @ Set domain register
msr spsr, ip @ Save tasks CPSR into SPSR for this return ldmib r1, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously
.section ".text.init",#alloc,#execinstr .section ".text.init",#alloc,#execinstr
/* /*
......
...@@ -185,7 +185,7 @@ void show_regs(struct pt_regs * regs) ...@@ -185,7 +185,7 @@ void show_regs(struct pt_regs * regs)
get_fs() == get_ds() ? "kernel" : "user"); get_fs() == get_ds() ? "kernel" : "user");
#if defined(CONFIG_CPU_32) #if defined(CONFIG_CPU_32)
{ {
int ctrl, transbase, dac; unsigned int ctrl, transbase, dac;
__asm__ ( __asm__ (
" mrc p15, 0, %0, c1, c0\n" " mrc p15, 0, %0, c1, c0\n"
" mrc p15, 0, %1, c2, c0\n" " mrc p15, 0, %1, c2, c0\n"
...@@ -314,19 +314,17 @@ int ...@@ -314,19 +314,17 @@ int
copy_thread(int nr, unsigned long clone_flags, unsigned long esp, copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
unsigned long unused, struct task_struct *p, struct pt_regs *regs) unsigned long unused, struct task_struct *p, struct pt_regs *regs)
{ {
struct thread_info *thread = p->thread_info;
struct pt_regs *childregs; 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 = *regs;
childregs->ARM_r0 = 0; childregs->ARM_r0 = 0;
childregs->ARM_sp = esp; childregs->ARM_sp = esp;
save = ((struct cpu_context_save *)(childregs)) - 1; memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
memset(save, 0, sizeof(struct cpu_context_save)); thread->cpu_context.sp = (unsigned long)childregs;
init_pc_psr(save, ret_from_fork); thread->cpu_context.pc = (unsigned long)ret_from_fork;
p->thread_info->cpu_context = save;
return 0; return 0;
} }
......
...@@ -20,27 +20,9 @@ ...@@ -20,27 +20,9 @@
#define __ASM_PROC_PROCESSOR_H #define __ASM_PROC_PROCESSOR_H
#include <linux/string.h> #include <linux/string.h>
#include <asm/proc/ptrace.h>
#define KERNEL_STACK_SIZE 4096 #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 { typedef struct {
void (*put_byte)(void); /* Special calling convention */ void (*put_byte)(void); /* Special calling convention */
void (*get_byte)(void); /* Special calling convention */ void (*get_byte)(void); /* Special calling convention */
...@@ -75,7 +57,7 @@ extern uaccess_t uaccess_user, uaccess_kernel; ...@@ -75,7 +57,7 @@ extern uaccess_t uaccess_user, uaccess_kernel;
regs->ARM_r0 = stack[0]; /* r0 (argc) */ \ regs->ARM_r0 = stack[0]; /* r0 (argc) */ \
}) })
#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022]) #define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020]) #define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1018])
#endif #endif
...@@ -19,29 +19,9 @@ ...@@ -19,29 +19,9 @@
#define __ASM_PROC_PROCESSOR_H #define __ASM_PROC_PROCESSOR_H
#include <asm/proc/domain.h> #include <asm/proc/domain.h>
#include <asm/proc/ptrace.h>
#define KERNEL_STACK_SIZE PAGE_SIZE #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 \ #define INIT_EXTRA_THREAD_INFO \
cpu_domain: domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \ cpu_domain: domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
...@@ -63,7 +43,7 @@ static inline void init_pc_psr(struct cpu_context_save *s, void *fn) ...@@ -63,7 +43,7 @@ static inline void init_pc_psr(struct cpu_context_save *s, void *fn)
regs->ARM_r0 = stack[0]; /* r0 (argc) */ \ regs->ARM_r0 = stack[0]; /* r0 (argc) */ \
}) })
#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1021]) #define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019]) #define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1017])
#endif #endif
...@@ -22,20 +22,35 @@ struct exec_domain; ...@@ -22,20 +22,35 @@ struct exec_domain;
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/types.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. * low level task data that entry.S needs immediate access to.
* We assume cpu_context follows immedately after cpu_domain.
*/ */
struct thread_info { struct thread_info {
unsigned long flags; /* low level flags */ unsigned long flags; /* low level flags */
__s32 preempt_count; /* 0 => preemptable, <0 => bug */ __s32 preempt_count; /* 0 => preemptable, <0 => bug */
mm_segment_t addr_limit; /* address limit */ 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 task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */ 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; union fp_state fpstate;
}; };
...@@ -71,34 +86,20 @@ extern void free_thread_info(struct thread_info *); ...@@ -71,34 +86,20 @@ extern void free_thread_info(struct thread_info *);
#define get_thread_info(ti) get_task_struct((ti)->task) #define get_thread_info(ti) get_task_struct((ti)->task)
#define put_thread_info(ti) put_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) #define thread_saved_pc(tsk) (pc_pointer((tsk)->thread_info->cpu_context.pc))
{ #define thread_saved_fp(tsk) ((tsk)->thread_info->cpu_context.fp)
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)
#else /* !__ASSEMBLY__ */ #else /* !__ASSEMBLY__ */
#define TI_FLAGS 0 #define TI_FLAGS 0
#define TI_PREEMPT 4 #define TI_PREEMPT 4
#define TI_ADDR_LIMIT 8 #define TI_ADDR_LIMIT 8
#define TI_CPU 12 #define TI_TASK 12
#define TI_CPU_SAVE 16 #define TI_EXEC_DOMAIN 16
#define TI_CPU_DOMAIN 20 #define TI_CPU 20
#define TI_TASK 24 #define TI_CPU_DOMAIN 24
#define TI_EXEC_DOMAIN 28 #define TI_CPU_SAVE 28
#define TI_FPSTATE 32 #define TI_FPSTATE 76
#endif #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