Commit 1ab196f3 authored by Paul Mackerras's avatar Paul Mackerras Committed by Linus Torvalds

[PATCH] ppc64: Optimize exception/syscall entry/exit

This rewrites the PPC64 exception entry/exit routines to make them
smaller and faster.

In particular we no longer save all of the registers for the common
exceptions - system calls, hardware interrupts and decrementer (timer)
interrupts - only the volatile registers.  The other registers are saved
and restored (if used) by the C functions we call.  This involved
changing the registers we use in early exception processing from r20-r23
to r9-r12, which ended up changing quite a lot of code in head.S. 
Overall this gives us about a 20% reduction in null syscall time. 

Some system calls need all the registers (e.g.  fork/clone/vfork and
[rt_]sigsuspend).  For these the syscall dispatch code calls a stub that
saves the nonvolatile registers before calling the real handler.

This also implements the force_successful_syscall_return() thing for
ppc64.
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 23932693
...@@ -49,6 +49,7 @@ int main(void) ...@@ -49,6 +49,7 @@ int main(void)
DEFINE(THREAD_SIZE, THREAD_SIZE); DEFINE(THREAD_SIZE, THREAD_SIZE);
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror));
/* task_struct->thread */ /* task_struct->thread */
DEFINE(THREAD, offsetof(struct task_struct, thread)); DEFINE(THREAD, offsetof(struct task_struct, thread));
...@@ -100,7 +101,10 @@ int main(void) ...@@ -100,7 +101,10 @@ int main(void)
DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca)); DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca));
DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca)); DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav)); DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack)); DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi));
DEFINE(PACAGUARD, offsetof(struct paca_struct, guard)); DEFINE(PACAGUARD, offsetof(struct paca_struct, guard));
DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0)); DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1)); DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
...@@ -137,6 +141,10 @@ int main(void) ...@@ -137,6 +141,10 @@ int main(void)
DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7])); DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8])); DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9])); DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10]));
DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11]));
DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12]));
DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13]));
DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
...@@ -155,7 +163,7 @@ int main(void) ...@@ -155,7 +163,7 @@ int main(void)
DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe)); DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe));
/* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */ /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */
......
This diff is collapsed.
This diff is collapsed.
...@@ -85,16 +85,17 @@ _GLOBAL(local_irq_restore) ...@@ -85,16 +85,17 @@ _GLOBAL(local_irq_restore)
cmpw 0,r3,r5 cmpw 0,r3,r5
beqlr beqlr
/* are we enabling interrupts? */ /* are we enabling interrupts? */
cmpi 0,r3,0 cmpdi 0,r3,0
stb r3,PACAPROCENABLED(r13) stb r3,PACAPROCENABLED(r13)
beqlr beqlr
/* Check pending interrupts */ /* Check pending interrupts */
/* A decrementer, IPI or PMC interrupt may have occurred /* A decrementer, IPI or PMC interrupt may have occurred
* while we were in the hypervisor (which enables) */ * while we were in the hypervisor (which enables) */
CHECKANYINT(r4,r5) ld r4,PACALPPACA+LPPACAANYINT(r13)
cmpdi r4,0
beqlr beqlr
/* /*
* Handle pending interrupts in interrupt context * Handle pending interrupts in interrupt context
*/ */
li r0,0x5555 li r0,0x5555
...@@ -608,7 +609,7 @@ _GLOBAL(kernel_thread) ...@@ -608,7 +609,7 @@ _GLOBAL(kernel_thread)
_GLOBAL(sys_call_table32) _GLOBAL(sys_call_table32)
.llong .sys_restart_syscall /* 0 */ .llong .sys_restart_syscall /* 0 */
.llong .sys_exit .llong .sys_exit
.llong .sys_fork .llong .ppc_fork
.llong .sys_read .llong .sys_read
.llong .sys_write .llong .sys_write
.llong .sys32_open /* 5 */ .llong .sys32_open /* 5 */
...@@ -678,7 +679,7 @@ _GLOBAL(sys_call_table32) ...@@ -678,7 +679,7 @@ _GLOBAL(sys_call_table32)
.llong .sys32_ssetmask .llong .sys32_ssetmask
.llong .sys_setreuid /* 70 */ .llong .sys_setreuid /* 70 */
.llong .sys_setregid .llong .sys_setregid
.llong .sys32_sigsuspend .llong .ppc32_sigsuspend
.llong .compat_sys_sigpending .llong .compat_sys_sigpending
.llong .sys32_sethostname .llong .sys32_sethostname
.llong .compat_sys_setrlimit /* 75 */ .llong .compat_sys_setrlimit /* 75 */
...@@ -726,7 +727,7 @@ _GLOBAL(sys_call_table32) ...@@ -726,7 +727,7 @@ _GLOBAL(sys_call_table32)
.llong .sys32_ipc .llong .sys32_ipc
.llong .sys_fsync .llong .sys_fsync
.llong .ppc32_sigreturn .llong .ppc32_sigreturn
.llong .sys_clone /* 120 */ .llong .ppc_clone /* 120 */
.llong .sys32_setdomainname .llong .sys32_setdomainname
.llong .ppc64_newuname .llong .ppc64_newuname
.llong .sys_ni_syscall /* old modify_ldt syscall */ .llong .sys_ni_syscall /* old modify_ldt syscall */
...@@ -784,7 +785,7 @@ _GLOBAL(sys_call_table32) ...@@ -784,7 +785,7 @@ _GLOBAL(sys_call_table32)
.llong .sys32_rt_sigpending /* 175 */ .llong .sys32_rt_sigpending /* 175 */
.llong .sys32_rt_sigtimedwait .llong .sys32_rt_sigtimedwait
.llong .sys32_rt_sigqueueinfo .llong .sys32_rt_sigqueueinfo
.llong .sys32_rt_sigsuspend .llong .ppc32_rt_sigsuspend
.llong .sys32_pread64 .llong .sys32_pread64
.llong .sys32_pwrite64 /* 180 */ .llong .sys32_pwrite64 /* 180 */
.llong .sys_chown .llong .sys_chown
...@@ -795,7 +796,7 @@ _GLOBAL(sys_call_table32) ...@@ -795,7 +796,7 @@ _GLOBAL(sys_call_table32)
.llong .sys32_sendfile .llong .sys32_sendfile
.llong .sys_ni_syscall /* reserved for streams1 */ .llong .sys_ni_syscall /* reserved for streams1 */
.llong .sys_ni_syscall /* reserved for streams2 */ .llong .sys_ni_syscall /* reserved for streams2 */
.llong .sys_vfork .llong .ppc_vfork
.llong .compat_sys_getrlimit /* 190 */ .llong .compat_sys_getrlimit /* 190 */
.llong .sys32_readahead .llong .sys32_readahead
.llong .sys32_mmap2 .llong .sys32_mmap2
...@@ -880,7 +881,7 @@ _GLOBAL(sys_call_table32) ...@@ -880,7 +881,7 @@ _GLOBAL(sys_call_table32)
_GLOBAL(sys_call_table) _GLOBAL(sys_call_table)
.llong .sys_restart_syscall /* 0 */ .llong .sys_restart_syscall /* 0 */
.llong .sys_exit .llong .sys_exit
.llong .sys_fork .llong .ppc_fork
.llong .sys_read .llong .sys_read
.llong .sys_write .llong .sys_write
.llong .sys_open /* 5 */ .llong .sys_open /* 5 */
...@@ -998,7 +999,7 @@ _GLOBAL(sys_call_table) ...@@ -998,7 +999,7 @@ _GLOBAL(sys_call_table)
.llong .sys_ipc .llong .sys_ipc
.llong .sys_fsync .llong .sys_fsync
.llong .sys_ni_syscall .llong .sys_ni_syscall
.llong .sys_clone /* 120 */ .llong .ppc_clone /* 120 */
.llong .sys_setdomainname .llong .sys_setdomainname
.llong .ppc64_newuname .llong .ppc64_newuname
.llong .sys_ni_syscall /* old modify_ldt syscall */ .llong .sys_ni_syscall /* old modify_ldt syscall */
...@@ -1056,7 +1057,7 @@ _GLOBAL(sys_call_table) ...@@ -1056,7 +1057,7 @@ _GLOBAL(sys_call_table)
.llong .sys_rt_sigpending /* 175 */ .llong .sys_rt_sigpending /* 175 */
.llong .sys_rt_sigtimedwait .llong .sys_rt_sigtimedwait
.llong .sys_rt_sigqueueinfo .llong .sys_rt_sigqueueinfo
.llong .sys_rt_sigsuspend .llong .ppc64_rt_sigsuspend
.llong .sys_pread64 .llong .sys_pread64
.llong .sys_pwrite64 /* 180 */ .llong .sys_pwrite64 /* 180 */
.llong .sys_chown .llong .sys_chown
...@@ -1067,7 +1068,7 @@ _GLOBAL(sys_call_table) ...@@ -1067,7 +1068,7 @@ _GLOBAL(sys_call_table)
.llong .sys_sendfile64 .llong .sys_sendfile64
.llong .sys_ni_syscall /* reserved for streams1 */ .llong .sys_ni_syscall /* reserved for streams1 */
.llong .sys_ni_syscall /* reserved for streams2 */ .llong .sys_ni_syscall /* reserved for streams2 */
.llong .sys_vfork .llong .ppc_vfork
.llong .sys_getrlimit /* 190 */ .llong .sys_getrlimit /* 190 */
.llong .sys_readahead .llong .sys_readahead
.llong .sys_ni_syscall /* 32bit only mmap2 */ .llong .sys_ni_syscall /* 32bit only mmap2 */
......
...@@ -62,8 +62,6 @@ struct systemcfg *systemcfg; ...@@ -62,8 +62,6 @@ struct systemcfg *systemcfg;
.xDesc = 0xd397d9e2, /* "LpRS" */ \ .xDesc = 0xd397d9e2, /* "LpRS" */ \
.xSize = sizeof(struct ItLpRegSave) \ .xSize = sizeof(struct ItLpRegSave) \
}, \ }, \
.exception_sp = \
(&paca[number].exception_stack[0]) - EXC_FRAME_SIZE, \
} }
struct paca_struct paca[] __page_aligned = { struct paca_struct paca[] __page_aligned = {
......
...@@ -219,6 +219,7 @@ struct task_struct *__switch_to(struct task_struct *prev, ...@@ -219,6 +219,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
void show_regs(struct pt_regs * regs) void show_regs(struct pt_regs * regs)
{ {
int i; int i;
unsigned long trap;
printk("NIP: %016lX XER: %016lX LR: %016lX\n", printk("NIP: %016lX XER: %016lX LR: %016lX\n",
regs->nip, regs->xer, regs->link); regs->nip, regs->xer, regs->link);
...@@ -229,7 +230,8 @@ void show_regs(struct pt_regs * regs) ...@@ -229,7 +230,8 @@ void show_regs(struct pt_regs * regs)
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
regs->msr&MSR_IR ? 1 : 0, regs->msr&MSR_IR ? 1 : 0,
regs->msr&MSR_DR ? 1 : 0); regs->msr&MSR_DR ? 1 : 0);
if (regs->trap == 0x300 || regs->trap == 0x380 || regs->trap == 0x600) trap = TRAP(regs);
if (trap == 0x300 || trap == 0x380 || trap == 0x600)
printk("DAR: %016lx, DSISR: %016lx\n", regs->dar, regs->dsisr); printk("DAR: %016lx, DSISR: %016lx\n", regs->dar, regs->dsisr);
printk("TASK: %p[%d] '%s' THREAD: %p", printk("TASK: %p[%d] '%s' THREAD: %p",
current, current->pid, current->comm, current->thread_info); current, current->pid, current->comm, current->thread_info);
...@@ -244,6 +246,8 @@ void show_regs(struct pt_regs * regs) ...@@ -244,6 +246,8 @@ void show_regs(struct pt_regs * regs)
} }
printk("%016lX ", regs->gpr[i]); printk("%016lX ", regs->gpr[i]);
if (i == 13 && !FULL_REGS(regs))
break;
} }
printk("\n"); printk("\n");
/* /*
......
...@@ -528,13 +528,13 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) ...@@ -528,13 +528,13 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
struct k_sigaction *ka = &current->sighand->action[signr-1]; struct k_sigaction *ka = &current->sighand->action[signr-1];
/* Whee! Actually deliver the signal. */ /* Whee! Actually deliver the signal. */
if (regs->trap == 0x0C00) if (TRAP(regs) == 0x0C00)
syscall_restart(regs, ka); syscall_restart(regs, ka);
handle_signal(signr, ka, &info, oldset, regs); handle_signal(signr, ka, &info, oldset, regs);
return 1; return 1;
} }
if (regs->trap == 0x0C00) { /* System Call! */ if (TRAP(regs) == 0x0C00) { /* System Call! */
if ((int)regs->result == -ERESTARTNOHAND || if ((int)regs->result == -ERESTARTNOHAND ||
(int)regs->result == -ERESTARTSYS || (int)regs->result == -ERESTARTSYS ||
(int)regs->result == -ERESTARTNOINTR) { (int)regs->result == -ERESTARTNOINTR) {
......
...@@ -932,7 +932,7 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) ...@@ -932,7 +932,7 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
ka = (signr == 0)? NULL: &current->sighand->action[signr-1]; ka = (signr == 0)? NULL: &current->sighand->action[signr-1];
if (regs->trap == 0x0C00 /* System Call! */ if (TRAP(regs) == 0x0C00 /* System Call! */
&& regs->ccr & 0x10000000 /* error signalled */ && regs->ccr & 0x10000000 /* error signalled */
&& ((ret = regs->gpr[3]) == ERESTARTSYS && ((ret = regs->gpr[3]) == ERESTARTSYS
|| ret == ERESTARTNOHAND || ret == ERESTARTNOINTR || ret == ERESTARTNOHAND || ret == ERESTARTNOINTR
......
...@@ -237,5 +237,19 @@ asmlinkage time_t sys64_time(time_t __user * tloc) ...@@ -237,5 +237,19 @@ asmlinkage time_t sys64_time(time_t __user * tloc)
return secs; return secs;
} }
void do_show_syscall(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7, unsigned long r8,
struct pt_regs *regs)
{
printk("syscall %ld(%lx, %lx, %lx, %lx, %lx, %lx) regs=%p current=%p"
" cpu=%d\n", regs->gpr[0], r3, r4, r5, r6, r7, r8, regs,
current, smp_processor_id());
}
void do_show_syscall_exit(unsigned long r3)
{
printk(" -> %lx, current=%p cpu=%d\n", r3, current, smp_processor_id());
}
/* Only exists on P-series. */ /* Only exists on P-series. */
cond_syscall(ppc_rtas); cond_syscall(ppc_rtas);
...@@ -441,8 +441,22 @@ void KernelFPUnavailableException(struct pt_regs *regs) ...@@ -441,8 +441,22 @@ void KernelFPUnavailableException(struct pt_regs *regs)
die("Unrecoverable FP Unavailable Exception", regs, SIGABRT); die("Unrecoverable FP Unavailable Exception", regs, SIGABRT);
} }
void KernelAltivecUnavailableException(struct pt_regs *regs) void AltivecUnavailableException(struct pt_regs *regs)
{ {
#ifndef CONFIG_ALTIVEC
if (user_mode(regs)) {
/* A user program has executed an altivec instruction,
but this kernel doesn't support altivec. */
siginfo_t info;
memset(&info, 0, sizeof(info));
info.si_signo = SIGILL;
info.si_code = ILL_ILLOPC;
info.si_addr = (void *) regs->nip;
_exception(SIGILL, &info, regs);
return;
}
#endif
printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
"%lx at %lx\n", regs->trap, regs->nip); "%lx at %lx\n", regs->trap, regs->nip);
die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
......
...@@ -80,36 +80,45 @@ static int store_updates_sp(struct pt_regs *regs) ...@@ -80,36 +80,45 @@ static int store_updates_sp(struct pt_regs *regs)
* - DSISR for a non-SLB data access fault, * - DSISR for a non-SLB data access fault,
* - SRR1 & 0x08000000 for a non-SLB instruction access fault * - SRR1 & 0x08000000 for a non-SLB instruction access fault
* - 0 any SLB fault. * - 0 any SLB fault.
* The return value is 0 if the fault was handled, or the signal
* number if this is a kernel fault that can't be handled here.
*/ */
void do_page_fault(struct pt_regs *regs, unsigned long address, int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code) unsigned long error_code)
{ {
struct vm_area_struct * vma; struct vm_area_struct * vma;
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
siginfo_t info; siginfo_t info;
unsigned long code = SEGV_MAPERR; unsigned long code = SEGV_MAPERR;
unsigned long is_write = error_code & 0x02000000; unsigned long is_write = error_code & 0x02000000;
unsigned long trap = TRAP(regs);
if (regs->trap == 0x300 || regs->trap == 0x380) { if (trap == 0x300 || trap == 0x380) {
if (debugger_fault_handler(regs)) if (debugger_fault_handler(regs))
return; return 0;
} }
/* On a kernel SLB miss we can only check for a valid exception entry */ /* On a kernel SLB miss we can only check for a valid exception entry */
if (!user_mode(regs) && (regs->trap == 0x380)) { if (!user_mode(regs) && (trap == 0x380 || address >= TASK_SIZE))
bad_page_fault(regs, address, SIGSEGV); return SIGSEGV;
return;
}
if (error_code & 0x00400000) { if (error_code & 0x00400000) {
if (debugger_dabr_match(regs)) if (debugger_dabr_match(regs))
return; return 0;
} }
if (in_atomic() || mm == NULL) { if (in_atomic() || mm == NULL) {
bad_page_fault(regs, address, SIGSEGV); if (!user_mode(regs))
return; return SIGSEGV;
/* in_atomic() in user mode is really bad,
as is current->mm == NULL. */
printk(KERN_EMERG "Page fault in user mode with"
"in_atomic() = %d mm = %p\n", in_atomic(), mm);
printk(KERN_EMERG "NIP = %lx MSR = %lx\n",
regs->nip, regs->msr);
die("Weird page fault", regs, SIGSEGV);
} }
down_read(&mm->mmap_sem); down_read(&mm->mmap_sem);
vma = find_vma(mm, address); vma = find_vma(mm, address);
if (!vma) if (!vma)
...@@ -195,7 +204,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, ...@@ -195,7 +204,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
} }
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
return; return 0;
bad_area: bad_area:
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
...@@ -207,11 +216,10 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, ...@@ -207,11 +216,10 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
info.si_code = code; info.si_code = code;
info.si_addr = (void *) address; info.si_addr = (void *) address;
force_sig_info(SIGSEGV, &info, current); force_sig_info(SIGSEGV, &info, current);
return; return 0;
} }
bad_page_fault(regs, address, SIGSEGV); return SIGSEGV;
return;
/* /*
* We ran out of memory, or some other thing happened to us that made * We ran out of memory, or some other thing happened to us that made
...@@ -227,18 +235,19 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, ...@@ -227,18 +235,19 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
printk("VM: killing process %s\n", current->comm); printk("VM: killing process %s\n", current->comm);
if (user_mode(regs)) if (user_mode(regs))
do_exit(SIGKILL); do_exit(SIGKILL);
bad_page_fault(regs, address, SIGKILL); return SIGKILL;
return;
do_sigbus: do_sigbus:
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
info.si_signo = SIGBUS; if (user_mode(regs)) {
info.si_errno = 0; info.si_signo = SIGBUS;
info.si_code = BUS_ADRERR; info.si_errno = 0;
info.si_addr = (void *)address; info.si_code = BUS_ADRERR;
force_sig_info (SIGBUS, &info, current); info.si_addr = (void *)address;
if (!user_mode(regs)) force_sig_info(SIGBUS, &info, current);
bad_page_fault(regs, address, SIGBUS); return 0;
}
return SIGBUS;
} }
/* /*
......
...@@ -44,9 +44,6 @@ static int xmon_owner; ...@@ -44,9 +44,6 @@ static int xmon_owner;
static int xmon_gate; static int xmon_gate;
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
#define TRAP(regs) ((regs)->trap)
#define FULL_REGS(regs) 1
static unsigned long in_xmon = 0; static unsigned long in_xmon = 0;
static unsigned long adrs; static unsigned long adrs;
......
...@@ -136,23 +136,21 @@ struct paca_struct { ...@@ -136,23 +136,21 @@ struct paca_struct {
u8 rsvd6[0x500 - 0x8]; u8 rsvd6[0x500 - 0x8];
/*===================================================================================== /*=====================================================================================
* CACHE_LINE_31 0x0F00 - 0x0F7F Exception stack * CACHE_LINE_31-32 0x0F00 - 0x0FFF Exception register save areas
*===================================================================================== *=====================================================================================
*/ */
u8 exception_stack[N_EXC_STACK*EXC_FRAME_SIZE]; u64 exgen[8]; /* used for most interrupts/exceptions */
u64 exmc[8]; /* used for machine checks */
u64 exslb[8]; /* used for SLB/segment table misses
* on the linear mapping */
u64 exdsi[8]; /* used for linear mapping hash table misses */
/*===================================================================================== /*=====================================================================================
* CACHE_LINE_32 0x0F80 - 0x0FFF Reserved * Page 2 used as a stack when we detect a bad kernel stack pointer,
* and early in SMP boots before relocation is enabled.
*===================================================================================== *=====================================================================================
*/ */
u8 rsvd7[0x80]; /* Give the stack some rope ... */ u8 guard[0x1000];
/*=====================================================================================
* Page 2 Reserved for guard page. Also used as a stack early in SMP boots before
* relocation is enabled.
*=====================================================================================
*/
u8 guard[0x1000]; /* ... and then hang 'em */
}; };
#endif /* _PPC64_PACA_H */ #endif /* _PPC64_PACA_H */
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) #define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) #define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
#define SAVE_NVGPRS(base) SAVE_8GPRS(14, base); SAVE_10GPRS(22, base)
#define REST_NVGPRS(base) REST_8GPRS(14, base); REST_10GPRS(22, base)
#define SAVE_FPR(n, base) stfd n,THREAD_FPR0+8*(n)(base) #define SAVE_FPR(n, base) stfd n,THREAD_FPR0+8*(n)(base)
#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) #define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base)
#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) #define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
...@@ -54,11 +57,6 @@ ...@@ -54,11 +57,6 @@
#define REST_16VRS(n,b,base) REST_8VRS(n,b,base); REST_8VRS(n+8,b,base) #define REST_16VRS(n,b,base) REST_8VRS(n,b,base); REST_8VRS(n+8,b,base)
#define REST_32VRS(n,b,base) REST_16VRS(n,b,base); REST_16VRS(n+16,b,base) #define REST_32VRS(n,b,base) REST_16VRS(n,b,base); REST_16VRS(n+16,b,base)
#define CHECKANYINT(ra,rb) \
mfspr rb,SPRG3; /* Get Paca address */\
ld ra,PACALPPACA+LPPACAANYINT(rb); /* Get pending interrupt flags */\
cmpldi 0,ra,0;
/* Macros to adjust thread priority for Iseries hardware multithreading */ /* Macros to adjust thread priority for Iseries hardware multithreading */
#define HMT_LOW or 1,1,1 #define HMT_LOW or 1,1,1
#define HMT_MEDIUM or 2,2,2 #define HMT_MEDIUM or 2,2,2
......
...@@ -543,8 +543,7 @@ struct thread_struct { ...@@ -543,8 +543,7 @@ struct thread_struct {
double fpr[32]; /* Complete floating point set */ double fpr[32]; /* Complete floating point set */
unsigned long fpscr; /* Floating point status (plus pad) */ unsigned long fpscr; /* Floating point status (plus pad) */
unsigned long fpexc_mode; /* Floating-point exception mode */ unsigned long fpexc_mode; /* Floating-point exception mode */
unsigned long saved_msr; /* Save MSR across signal handlers */ unsigned long pad[3]; /* was saved_msr, saved_softe */
unsigned long saved_softe; /* Ditto for Soft Enable/Disable */
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
/* Complete AltiVec register set */ /* Complete AltiVec register set */
vector128 vr[32] __attribute((aligned(16))); vector128 vr[32] __attribute((aligned(16)));
......
...@@ -71,6 +71,18 @@ struct pt_regs32 { ...@@ -71,6 +71,18 @@ struct pt_regs32 {
#define instruction_pointer(regs) ((regs)->nip) #define instruction_pointer(regs) ((regs)->nip)
#define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1) #define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1)
#define force_successful_syscall_return() \
(current_thread_info()->syscall_noerror = 1)
/*
* We use the least-significant bit of the trap field to indicate
* whether we have saved the full set of registers, or only a
* partial set. A 1 there means the partial set.
*/
#define FULL_REGS(regs) (((regs)->trap & 1) == 0)
#define TRAP(regs) ((regs)->trap & ~0xF)
#define CHECK_FULL_REGS(regs) BUG_ON(regs->trap & 1)
/* /*
* Offsets used by 'ptrace' system call interface. * Offsets used by 'ptrace' system call interface.
*/ */
......
...@@ -26,6 +26,8 @@ struct thread_info { ...@@ -26,6 +26,8 @@ struct thread_info {
int cpu; /* cpu we're on */ int cpu; /* cpu we're on */
int preempt_count; int preempt_count;
struct restart_block restart_block; struct restart_block restart_block;
/* set by force_successful_syscall_return */
unsigned char syscall_noerror;
}; };
/* /*
...@@ -84,8 +86,6 @@ static inline struct thread_info *current_thread_info(void) ...@@ -84,8 +86,6 @@ static inline struct thread_info *current_thread_info(void)
/* /*
* thread information flag bit numbers * thread information flag bit numbers
* N.B. If TIF_SIGPENDING or TIF_NEED_RESCHED are changed
* to be >= 4, code in entry.S will need to be changed.
*/ */
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ #define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ #define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
......
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