Commit 4e416e98 authored by Paul Mackerras's avatar Paul Mackerras

PPC32: This changeset adds preemptible kernel support for ppc32

and also streamlines the exception entry/exit code by not saving
all the GPRs on the common exceptions (system call, external
interrupt and decrementer).
parent bb3ffc11
......@@ -165,7 +165,9 @@ bool 'Symmetric multi-processing support' CONFIG_SMP
if [ "$CONFIG_SMP" = "y" ]; then
bool ' Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
fi
define_bool CONFIG_PREEMPT n
if [ "$CONFIG_SMP" != "y" ]; then
bool 'Preemptible Kernel' CONFIG_PREEMPT
fi
if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then
bool 'AltiVec Support' CONFIG_ALTIVEC
......
......@@ -200,6 +200,8 @@ fix_alignment(struct pt_regs *regs)
unsigned char v[8];
} data;
CHECK_FULL_REGS(regs);
#if defined(CONFIG_4xx)
/* The 4xx-family processors have no DSISR register,
* so we emulate it.
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -1017,20 +1017,28 @@ _GLOBAL(cvt_df)
* kernel_thread(fn, arg, flags)
*/
_GLOBAL(kernel_thread)
mr r6,r3 /* function */
stwu r1,-16(r1)
stw r30,8(r1)
stw r31,12(r1)
mr r30,r3 /* function */
mr r31,r4 /* argument */
ori r3,r5,CLONE_VM /* flags */
li r0,__NR_clone
sc
cmpi 0,r3,0 /* parent or child? */
bnelr /* return if parent */
bne 1f /* return if parent */
li r0,0 /* make top-level stack frame */
stwu r0,-16(r1)
mtlr r6 /* fn addr in lr */
mr r3,r4 /* load arg and call fn */
mtlr r30 /* fn addr in lr */
mr r3,r31 /* load arg and call fn */
blrl
li r0,__NR_exit /* exit after child exits */
li r0,__NR_exit /* exit if function returns */
li r3,0
sc
1: lwz r30,8(r1)
lwz r31,12(r1)
addi r1,r1,16
blr
/*
* This routine is just here to keep GCC happy - sigh...
......@@ -1050,19 +1058,15 @@ _GLOBAL(name) \
#define __NR__exit __NR_exit
SYSCALL(sync)
SYSCALL(setsid)
SYSCALL(open)
SYSCALL(read)
SYSCALL(write)
SYSCALL(lseek)
SYSCALL(close)
SYSCALL(dup)
SYSCALL(execve)
SYSCALL(open)
SYSCALL(close)
SYSCALL(waitpid)
SYSCALL(fork)
SYSCALL(delete_module)
SYSCALL(_exit)
SYSCALL(lseek)
SYSCALL(read)
/* Why isn't this a) automatic, b) written in 'C'? */
.data
......@@ -1070,7 +1074,7 @@ SYSCALL(read)
_GLOBAL(sys_call_table)
.long sys_ni_syscall /* 0 - old "setup()" system call */
.long sys_exit
.long sys_fork
.long ppc_fork
.long sys_read
.long sys_write
.long sys_open /* 5 */
......@@ -1140,7 +1144,7 @@ _GLOBAL(sys_call_table)
.long sys_ssetmask
.long sys_setreuid /* 70 */
.long sys_setregid
.long sys_sigsuspend
.long ppc_sigsuspend
.long sys_sigpending
.long sys_sethostname
.long sys_setrlimit /* 75 */
......@@ -1188,7 +1192,7 @@ _GLOBAL(sys_call_table)
.long sys_ipc
.long sys_fsync
.long sys_sigreturn
.long sys_clone /* 120 */
.long ppc_clone /* 120 */
.long sys_setdomainname
.long sys_newuname
.long sys_modify_ldt
......@@ -1246,7 +1250,7 @@ _GLOBAL(sys_call_table)
.long sys_rt_sigpending /* 175 */
.long sys_rt_sigtimedwait
.long sys_rt_sigqueueinfo
.long sys_rt_sigsuspend
.long ppc_rt_sigsuspend
.long sys_pread
.long sys_pwrite /* 180 */
.long sys_chown
......@@ -1257,7 +1261,7 @@ _GLOBAL(sys_call_table)
.long sys_sendfile
.long sys_ni_syscall /* streams1 */
.long sys_ni_syscall /* streams2 */
.long sys_vfork
.long ppc_vfork
.long sys_getrlimit /* 190 */
.long sys_readahead
.long sys_mmap2
......
......@@ -107,10 +107,13 @@ main(void)
DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
/* The PowerPC 400-class processors have neither the DAR nor the DSISR
* SPRs. Hence, we overload them to hold the similar DEAR and ESR SPRs
* for such processors.
* for such processors. For critical interrupts we use them to
* hold SRR0 and SRR1.
*/
DEFINE(_DEAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
DEFINE(_ESR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
DEFINE(_SRR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
DEFINE(_SRR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
......
......@@ -75,7 +75,6 @@ int abs(int);
extern unsigned char __res[];
extern unsigned long ret_to_user_hook;
extern unsigned long mm_ptov (unsigned long paddr);
extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle);
......@@ -313,9 +312,7 @@ EXPORT_SYMBOL(__save_flags_ptr_end);
EXPORT_SYMBOL(__restore_flags);
EXPORT_SYMBOL(__restore_flags_end);
#endif
EXPORT_SYMBOL(timer_interrupt_intercept);
EXPORT_SYMBOL(timer_interrupt);
EXPORT_SYMBOL(do_IRQ_intercept);
EXPORT_SYMBOL(irq_desc);
void ppc_irq_dispatch_handler(struct pt_regs *, int);
EXPORT_SYMBOL(ppc_irq_dispatch_handler);
......@@ -356,7 +353,6 @@ EXPORT_SYMBOL(cpm_free_handler);
EXPORT_SYMBOL(request_8xxirq);
#endif
EXPORT_SYMBOL(ret_to_user_hook);
EXPORT_SYMBOL(next_mmu_context);
EXPORT_SYMBOL(set_context);
EXPORT_SYMBOL(handle_mm_fault); /* For MOL */
......@@ -366,8 +362,6 @@ EXPORT_SYMBOL(flush_hash_pages); /* For MOL */
extern long *intercept_table;
EXPORT_SYMBOL(intercept_table);
#endif
extern long *ret_from_intercept;
EXPORT_SYMBOL(ret_from_intercept);
EXPORT_SYMBOL(cur_cpu_spec);
#if defined(CONFIG_ALL_PPC)
extern unsigned long agp_special_page;
......
......@@ -251,16 +251,18 @@ void switch_to(struct task_struct *prev, struct task_struct *new)
void show_regs(struct pt_regs * regs)
{
int i;
int i, trap;
printk("NIP: %08lX XER: %08lX LR: %08lX SP: %08lX REGS: %p TRAP: %04lx %s\n",
regs->nip, regs->xer, regs->link, regs->gpr[1], regs,regs->trap, print_tainted());
printk("NIP: %08lX LR: %08lX SP: %08lX REGS: %p TRAP: %04lx %s\n",
regs->nip, regs->link, regs->gpr[1], regs, regs->trap,
print_tainted());
printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
regs->msr&MSR_IR ? 1 : 0,
regs->msr&MSR_DR ? 1 : 0);
if (regs->trap == 0x300 || regs->trap == 0x600)
trap = TRAP(regs);
if (trap == 0x300 || trap == 0x600)
printk("DAR: %08lX, DSISR: %08lX\n", regs->dar, regs->dsisr);
printk("TASK = %p[%d] '%s' ",
current, current->pid, current->comm);
......@@ -281,24 +283,17 @@ void show_regs(struct pt_regs * regs)
printk(" CPU: %d", smp_processor_id());
#endif /* CONFIG_SMP */
printk("\n");
for (i = 0; i < 32; i++)
{
for (i = 0; i < 32; i++) {
long r;
if ((i % 8) == 0)
{
printk("GPR%02d: ", i);
}
if ( __get_user(r, &(regs->gpr[i])) )
goto out;
printk("\n" KERN_INFO "GPR%02d: ", i);
if (__get_user(r, &regs->gpr[i]))
break;
printk("%08lX ", r);
if ((i % 8) == 7)
{
printk("\n");
}
if (i == 12 && !FULL_REGS(regs))
break;
}
out:
printk("\n");
print_backtrace((unsigned long *)regs->gpr[1]);
}
......@@ -336,6 +331,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
unsigned long sp = (unsigned long)p->thread_info + THREAD_SIZE;
unsigned long childframe;
CHECK_FULL_REGS(regs);
/* Copy registers */
sp -= sizeof(struct pt_regs);
childregs = (struct pt_regs *) sp;
......@@ -441,18 +437,21 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs)
{
CHECK_FULL_REGS(regs);
return do_fork(p1, regs->gpr[1], regs, 0);
}
int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs)
{
CHECK_FULL_REGS(regs);
return do_fork(SIGCHLD, regs->gpr[1], regs, 0);
}
int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs)
{
CHECK_FULL_REGS(regs);
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
}
......
......@@ -218,14 +218,15 @@ int sys_ptrace(long request, long pid, long addr, long data)
ret = -EIO;
/* convert to index and check */
index = (unsigned long) addr >> 2;
if ((addr & 3) || index > PT_FPSCR)
if ((addr & 3) || index > PT_FPSCR
|| child->thread.regs == NULL)
break;
CHECK_FULL_REGS(child->thread.regs);
if (index < PT_FPR0) {
tmp = get_reg(child, (int) index);
} else {
if (child->thread.regs != NULL
&& child->thread.regs->msr & MSR_FP)
if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child);
tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
}
......@@ -243,23 +244,23 @@ int sys_ptrace(long request, long pid, long addr, long data)
break;
/* write the word at location addr in the USER area */
/* XXX this will need fixing for 64-bit */
case PTRACE_POKEUSR: {
unsigned long index;
ret = -EIO;
/* convert to index and check */
index = (unsigned long) addr >> 2;
if ((addr & 3) || index > PT_FPSCR)
if ((addr & 3) || index > PT_FPSCR
|| child->thread.regs == NULL)
break;
CHECK_FULL_REGS(child->thread.regs);
if (index == PT_ORIG_R3)
break;
if (index < PT_FPR0) {
ret = put_reg(child, index, data);
} else {
if (child->thread.regs != NULL
&& child->thread.regs->msr & MSR_FP)
if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child);
((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
ret = 0;
......
......@@ -44,6 +44,8 @@
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
extern void sigreturn_exit(struct pt_regs *);
#define GP_REGS_SIZE MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
/*
......@@ -111,20 +113,14 @@ sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock);
regs->gpr[3] = -EINTR;
regs->result = -EINTR;
regs->ccr |= 0x10000000;
regs->gpr[3] = EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
if (do_signal(&saveset, regs))
/*
* If a signal handler needs to be called,
* do_signal() has set R3 to the signal number (the
* first argument of the signal handler), so don't
* overwrite that with EINTR !
* In the other cases, do_signal() doesn't touch
* R3, so it's still set to -EINTR (see above).
*/
return regs->gpr[3];
sigreturn_exit(regs);
}
}
......@@ -148,20 +144,22 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock);
regs->gpr[3] = -EINTR;
regs->result = -EINTR;
regs->ccr |= 0x10000000;
regs->gpr[3] = EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
if (do_signal(&saveset, regs))
return regs->gpr[3];
sigreturn_exit(regs);
}
}
int
sys_sigaltstack(const stack_t *uss, stack_t *uoss)
sys_sigaltstack(const stack_t *uss, stack_t *uoss, int r5, int r6,
int r7, int r8, struct pt_regs *regs)
{
struct pt_regs *regs = (struct pt_regs *) &uss;
return do_sigaltstack(uss, uoss, regs->gpr[1]);
}
......@@ -236,16 +234,15 @@ struct rt_sigframe
* Each of these things must be a multiple of 16 bytes in size.
*
*/
int sys_rt_sigreturn(struct pt_regs *regs)
int sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
struct pt_regs *regs)
{
struct rt_sigframe *rt_sf;
struct sigcontext_struct sigctx;
struct sigregs *sr;
int ret;
elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */
sigset_t set;
stack_t st;
unsigned long prevsp;
rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
......@@ -260,16 +257,13 @@ int sys_rt_sigreturn(struct pt_regs *regs)
if (regs->msr & MSR_FP)
giveup_fpu(current);
rt_sf++; /* Look at next rt_sigframe */
if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
/* Last stacked signal - restore registers -
/* restore registers -
* sigctx is initialized to point to the
* preamble frame (where registers are stored)
* see handle_signal()
*/
sr = (struct sigregs *) sigctx.regs;
if (copy_from_user(saved_regs, &sr->gp_regs,
sizeof(sr->gp_regs)))
if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs)))
goto badframe;
saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
| (saved_regs[PT_MSR] & MSR_USERCHANGE);
......@@ -279,31 +273,10 @@ int sys_rt_sigreturn(struct pt_regs *regs)
goto badframe;
/* This function sets back the stack flags into
the current task structure. */
sys_sigaltstack(&st, NULL);
ret = regs->result;
} else {
/* More signals to go */
/* Set up registers for next signal handler */
regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
goto badframe;
sr = (struct sigregs *) sigctx.regs;
regs->gpr[3] = ret = sigctx.signal;
/* Get the siginfo */
get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
/* Get the ucontext */
get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
regs->gpr[6] = (unsigned long) rt_sf;
sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs);
regs->link = (unsigned long) &sr->tramp;
regs->nip = sigctx.handler;
if (get_user(prevsp, &sr->gp_regs[PT_R1])
|| put_user(prevsp, (unsigned long *) regs->gpr[1]))
goto badframe;
current->thread.fpscr = 0;
}
return ret;
sigreturn_exit(regs); /* doesn't return here */
return 0;
badframe:
do_exit(SIGSEGV);
......@@ -318,6 +291,7 @@ setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
/* Set up preamble frame */
if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
goto badframe;
CHECK_FULL_REGS(regs);
if (regs->msr & MSR_FP)
giveup_fpu(current);
if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
......@@ -327,7 +301,7 @@ setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
It calls the sc exception at offset 0x9999
for sys_rt_sigreturn().
*/
|| __put_user(0x38006666UL, &frame->tramp[0]) /* li r0,0x6666 */
|| __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0])
|| __put_user(0x44000002UL, &frame->tramp[1])) /* sc */
goto badframe;
flush_icache_range((unsigned long) &frame->tramp[0],
......@@ -362,14 +336,13 @@ setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
/*
* Do a signal return; undo the signal stack.
*/
int sys_sigreturn(struct pt_regs *regs)
int sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
struct pt_regs *regs)
{
struct sigcontext_struct *sc, sigctx;
struct sigregs *sr;
int ret;
elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */
sigset_t set;
unsigned long prevsp;
sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
......@@ -387,12 +360,9 @@ int sys_sigreturn(struct pt_regs *regs)
if (regs->msr & MSR_FP )
giveup_fpu(current);
sc++; /* Look at next sigcontext */
if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
/* Last stacked signal - restore registers */
/* restore registers */
sr = (struct sigregs *) sigctx.regs;
if (copy_from_user(saved_regs, &sr->gp_regs,
sizeof(sr->gp_regs)))
if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs)))
goto badframe;
saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
| (saved_regs[PT_MSR] & MSR_USERCHANGE);
......@@ -402,25 +372,8 @@ int sys_sigreturn(struct pt_regs *regs)
sizeof(sr->fp_regs)))
goto badframe;
ret = regs->result;
} else {
/* More signals to go */
regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
goto badframe;
sr = (struct sigregs *) sigctx.regs;
regs->gpr[3] = ret = sigctx.signal;
regs->gpr[4] = (unsigned long) sc;
regs->link = (unsigned long) &sr->tramp;
regs->nip = sigctx.handler;
if (get_user(prevsp, &sr->gp_regs[PT_R1])
|| put_user(prevsp, (unsigned long *) regs->gpr[1]))
goto badframe;
current->thread.fpscr = 0;
}
return ret;
sigreturn_exit(regs); /* doesn't return here */
return 0;
badframe:
do_exit(SIGSEGV);
......@@ -437,12 +390,13 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame,
if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
goto badframe;
CHECK_FULL_REGS(regs);
if (regs->msr & MSR_FP)
giveup_fpu(current);
if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
|| __copy_to_user(&frame->fp_regs, current->thread.fpr,
ELF_NFPREG * sizeof(double))
|| __put_user(0x38007777UL, &frame->tramp[0]) /* li r0,0x7777 */
|| __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0])
|| __put_user(0x44000002UL, &frame->tramp[1])) /* sc */
goto badframe;
flush_icache_range((unsigned long) &frame->tramp[0],
......@@ -479,11 +433,14 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
struct sigcontext_struct *sc;
struct rt_sigframe *rt_sf;
if (regs->trap == 0x0C00 /* System Call! */
if (TRAP(regs) == 0x0C00 /* System Call! */
&& ((int)regs->result == -ERESTARTNOHAND ||
((int)regs->result == -ERESTARTSYS &&
!(ka->sa.sa_flags & SA_RESTART))))
!(ka->sa.sa_flags & SA_RESTART)))) {
regs->result = -EINTR;
regs->gpr[3] = EINTR;
regs->ccr |= 0x10000000;
}
/* Set up Signal Frame */
if (ka->sa.sa_flags & SA_SIGINFO) {
......@@ -511,7 +468,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
|| __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
goto badframe;
} else {
/* Put another sigcontext on the stack */
/* Put a sigcontext on the stack */
*newspp -= sizeof(*sc);
sc = (struct sigcontext_struct *) *newspp;
if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
......@@ -665,7 +622,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
break;
}
if (regs->trap == 0x0C00 /* System Call! */ &&
if (TRAP(regs) == 0x0C00 /* System Call! */ &&
((int)regs->result == -ERESTARTNOHAND ||
(int)regs->result == -ERESTARTSYS ||
(int)regs->result == -ERESTARTNOINTR)) {
......
......@@ -172,6 +172,7 @@ MachineCheckException(struct pt_regs *regs)
printk(KERN_DEBUG "%s bad port %lx at %p\n",
(*nip & 0x100)? "OUT to": "IN from",
regs->gpr[rb] - _IO_BASE, nip);
regs->msr |= MSR_RI;
regs->nip = fixup;
return;
}
......@@ -223,7 +224,7 @@ SMIException(struct pt_regs *regs)
void
UnknownException(struct pt_regs *regs)
{
printk("Bad trap at PC: %lx, SR: %lx, vector=%lx %s\n",
printk("Bad trap at PC: %lx, MSR: %lx, vector=%lx %s\n",
regs->nip, regs->msr, regs->trap, print_tainted());
_exception(SIGTRAP, regs);
}
......@@ -266,6 +267,7 @@ emulate_instruction(struct pt_regs *regs)
if (!user_mode(regs))
return retval;
CHECK_FULL_REGS(regs);
if (get_user(instword, (uint *)(regs->nip)))
return -EFAULT;
......@@ -366,6 +368,14 @@ StackOverflow(struct pt_regs *regs)
panic("kernel stack overflow");
}
void nonrecoverable_exception(struct pt_regs *regs)
{
printk(KERN_ERR "Non-recoverable exception at PC=%lx MSR=%lx\n",
regs->nip, regs->msr);
debugger(regs);
die("nonrecoverable exception", regs, SIGKILL);
}
void
trace_syscall(struct pt_regs *regs)
{
......@@ -382,6 +392,8 @@ SoftwareEmulation(struct pt_regs *regs)
extern int Soft_emulate_8xx(struct pt_regs *);
int errcode;
CHECK_FULL_REGS(regs);
if (!user_mode(regs)) {
debugger(regs);
die("Kernel Mode Software FPU Emulation", regs, SIGFPE);
......@@ -423,7 +435,7 @@ void DebugException(struct pt_regs *regs)
} else if (debug_status & DBSR_IC) { /* instruction completion */
mtspr(SPRN_DBSR, DBSR_IC);
regs->dbcr0 &= ~DBCR0_IC;
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC);
if (!user_mode(regs) && debugger_sstep(regs))
return;
......@@ -436,7 +448,7 @@ void DebugException(struct pt_regs *regs)
void
TAUException(struct pt_regs *regs)
{
printk("TAU trap at PC: %lx, SR: %lx, vector=%lx %s\n",
printk("TAU trap at PC: %lx, MSR: %lx, vector=%lx %s\n",
regs->nip, regs->msr, regs->trap, print_tainted());
}
#endif /* CONFIG_INT_TAU */
......
......@@ -37,6 +37,7 @@
#include <asm/mmu_context.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/tlbflush.h>
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
extern void (*debugger)(struct pt_regs *);
......@@ -81,14 +82,14 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
* bits we are interested in. But there are some bits which
* indicate errors in DSISR but can validly be set in SRR1.
*/
if (regs->trap == 0x400)
if (TRAP(regs) == 0x400)
error_code &= 0x48200000;
else
is_write = error_code & 0x02000000;
#endif /* CONFIG_4xx */
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
if (debugger_fault_handler && regs->trap == 0x300) {
if (debugger_fault_handler && TRAP(regs) == 0x300) {
debugger_fault_handler(regs);
return;
}
......@@ -140,7 +141,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
goto bad_area;
#if defined(CONFIG_4xx)
/* an exec - 4xx allows for per-page execute permission */
} else if (regs->trap == 0x400) {
} else if (TRAP(regs) == 0x400) {
pte_t *ptep;
#if 0
......@@ -159,8 +160,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
struct page *page = pte_page(*ptep);
if (! test_bit(PG_arch_1, &page->flags)) {
__flush_dcache_icache((unsigned long)kmap(page));
kunmap(page);
unsigned long phys = page_to_pfn(page) << PAGE_SHIFT;
__flush_dcache_icache_phys(phys);
set_bit(PG_arch_1, &page->flags);
}
pte_update(ptep, 0, _PAGE_HWEXEC);
......
......@@ -43,13 +43,13 @@
* Load a PTE into the hash table, if possible.
* The address is in r4, and r3 contains an access flag:
* _PAGE_RW (0x400) if a write.
* r23 contains the SRR1 value, from which we use the MSR_PR bit.
* r9 contains the SRR1 value, from which we use the MSR_PR bit.
* SPRG3 contains the physical address of the current task's thread.
*
* Returns to the caller if the access is illegal or there is no
* mapping for the address. Otherwise it places an appropriate PTE
* in the hash table and returns from the exception.
* Uses r0, r2 - r7, ctr, lr.
* Uses r0, r3 - r8, ctr, lr.
*/
.text
.globl hash_page
......@@ -62,34 +62,34 @@ hash_page:
#endif
tophys(r7,0) /* gets -KERNELBASE into r7 */
#ifdef CONFIG_SMP
addis r2,r7,mmu_hash_lock@h
ori r2,r2,mmu_hash_lock@l
addis r8,r7,mmu_hash_lock@h
ori r8,r8,mmu_hash_lock@l
lis r0,0x0fff
b 10f
11: lwz r6,0(r2)
11: lwz r6,0(r8)
cmpwi 0,r6,0
bne 11b
10: lwarx r6,0,r2
10: lwarx r6,0,r8
cmpwi 0,r6,0
bne- 11b
stwcx. r0,0,r2
stwcx. r0,0,r8
bne- 10b
isync
#endif
/* Get PTE (linux-style) and check access */
lis r0,KERNELBASE@h /* check if kernel address */
cmplw 0,r4,r0
mfspr r2,SPRG3 /* current task's THREAD (phys) */
mfspr r8,SPRG3 /* current task's THREAD (phys) */
ori r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
lwz r5,PGDIR(r2) /* virt page-table root */
lwz r5,PGDIR(r8) /* virt page-table root */
blt+ 112f /* assume user more likely */
lis r5,swapper_pg_dir@ha /* if kernel address, use */
addi r5,r5,swapper_pg_dir@l /* kernel page table */
rlwimi r3,r23,32-12,29,29 /* MSR_PR -> _PAGE_USER */
rlwimi r3,r9,32-12,29,29 /* MSR_PR -> _PAGE_USER */
112: add r5,r5,r7 /* convert to phys addr */
rlwimi r5,r4,12,20,29 /* insert top 10 bits of address */
lwz r2,0(r5) /* get pmd entry */
rlwinm. r2,r2,0,0,19 /* extract address of pte page */
lwz r8,0(r5) /* get pmd entry */
rlwinm. r8,r8,0,0,19 /* extract address of pte page */
#ifdef CONFIG_SMP
beq- hash_page_out /* return if no mapping */
#else
......@@ -99,7 +99,7 @@ hash_page:
to the address following the rfi. */
beqlr-
#endif
rlwimi r2,r4,22,20,29 /* insert next 10 bits of address */
rlwimi r8,r4,22,20,29 /* insert next 10 bits of address */
rlwinm r0,r3,32-3,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */
ori r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE
......@@ -110,7 +110,7 @@ hash_page:
* to update the PTE to set _PAGE_HASHPTE. -- paulus.
*/
retry:
lwarx r6,0,r2 /* get linux-style pte */
lwarx r6,0,r8 /* get linux-style pte */
andc. r5,r3,r6 /* check access & ~permission */
#ifdef CONFIG_SMP
bne- hash_page_out /* return if access not permitted */
......@@ -118,13 +118,13 @@ retry:
bnelr-
#endif
or r5,r0,r6 /* set accessed/dirty bits */
stwcx. r5,0,r2 /* attempt to update PTE */
stwcx. r5,0,r8 /* attempt to update PTE */
bne- retry /* retry if someone got there first */
mfsrin r3,r4 /* get segment reg for segment */
mr r2,r8 /* we have saved r2 but not r8 */
mfctr r0
stw r0,_CTR(r11)
bl create_hpte /* add the hash table entry */
mr r8,r2
/*
* htab_reloads counts the number of times we have to fault an
......@@ -134,48 +134,34 @@ retry:
* update_mmu_cache gets called to put the HPTE into the hash table
* and those are counted as preloads rather than reloads.
*/
addis r2,r7,htab_reloads@ha
lwz r3,htab_reloads@l(r2)
addis r8,r7,htab_reloads@ha
lwz r3,htab_reloads@l(r8)
addi r3,r3,1
stw r3,htab_reloads@l(r2)
stw r3,htab_reloads@l(r8)
#ifdef CONFIG_SMP
eieio
addis r2,r7,mmu_hash_lock@ha
addis r8,r7,mmu_hash_lock@ha
li r0,0
stw r0,mmu_hash_lock@l(r2)
stw r0,mmu_hash_lock@l(r8)
#endif
/* Return from the exception */
lwz r3,_CCR(r21)
lwz r4,_LINK(r21)
lwz r5,_CTR(r21)
mtcrf 0xff,r3
lwz r4,_LINK(r11)
lwz r5,_CTR(r11)
mtlr r4
mtctr r5
lwz r0,GPR0(r21)
lwz r1,GPR1(r21)
lwz r2,GPR2(r21)
lwz r3,GPR3(r21)
lwz r4,GPR4(r21)
lwz r5,GPR5(r21)
lwz r6,GPR6(r21)
lwz r7,GPR7(r21)
/* we haven't used xer */
mtspr SRR1,r23
mtspr SRR0,r22
lwz r20,GPR20(r21)
lwz r22,GPR22(r21)
lwz r23,GPR23(r21)
lwz r21,GPR21(r21)
RFI
lwz r0,GPR0(r11)
lwz r7,GPR7(r11)
lwz r8,GPR8(r11)
b fast_exception_return
#ifdef CONFIG_SMP
hash_page_out:
eieio
addis r2,r7,mmu_hash_lock@ha
addis r8,r7,mmu_hash_lock@ha
li r0,0
stw r0,mmu_hash_lock@l(r2)
stw r0,mmu_hash_lock@l(r8)
blr
#endif /* CONFIG_SMP */
......
......@@ -15,6 +15,7 @@
#include <asm/prom.h>
#include <asm/bitops.h>
#include <asm/bootx.h>
#include <asm/machdep.h>
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
......@@ -105,6 +106,7 @@ static void cpu_cmd(void);
#endif /* CONFIG_SMP */
static int pretty_print_addr(unsigned long addr);
static void csum(void);
static void bootcmds(void);
extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
extern void printf(const char *fmt, ...);
......@@ -482,10 +484,26 @@ cmds(struct pt_regs *excp)
cpu_cmd();
break;
#endif /* CONFIG_SMP */
case 'z':
bootcmds();
break;
}
}
}
static void bootcmds(void)
{
int cmd;
cmd = inchar();
if (cmd == 'r')
ppc_md.restart(NULL);
else if (cmd == 'h')
ppc_md.halt();
else if (cmd == 'p')
ppc_md.power_off();
}
#ifdef CONFIG_SMP
static void cpu_cmd(void)
{
......@@ -670,7 +688,7 @@ bpt_cmds(void)
printf("r");
if (dabr.address & 2)
printf("w");
if (dabr.address & 4)
if (!(dabr.address & 4))
printf("p");
printf("]\n");
}
......@@ -707,8 +725,7 @@ backtrace(struct pt_regs *excp)
unsigned sp;
unsigned stack[2];
struct pt_regs regs;
extern char ret_from_intercept, ret_from_syscall_1, ret_from_syscall_2;
extern char ret_from_except;
extern char ret_from_except, ret_from_except_full, ret_from_syscall;
printf("backtrace:\n");
......@@ -723,10 +740,9 @@ backtrace(struct pt_regs *excp)
break;
pretty_print_addr(stack[1]);
printf(" ");
if (stack[1] == (unsigned) &ret_from_intercept
|| stack[1] == (unsigned) &ret_from_except
|| stack[1] == (unsigned) &ret_from_syscall_1
|| stack[1] == (unsigned) &ret_from_syscall_2) {
if (stack[1] == (unsigned) &ret_from_except
|| stack[1] == (unsigned) &ret_from_except_full
|| stack[1] == (unsigned) &ret_from_syscall) {
if (mread(sp+16, &regs, sizeof(regs)) != sizeof(regs))
break;
printf("\nexception:%x [%x] %x ", regs.trap, sp+16,
......@@ -751,6 +767,8 @@ getsp()
void
excprint(struct pt_regs *fp)
{
int trap;
#ifdef CONFIG_SMP
printf("cpu %d: ", smp_processor_id());
#endif /* CONFIG_SMP */
......@@ -759,7 +777,8 @@ excprint(struct pt_regs *fp)
printf(", lr = ");
pretty_print_addr(fp->link);
printf("\nmsr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp);
if (fp->trap == 0x300 || fp->trap == 0x600)
trap = TRAP(fp);
if (trap == 0x300 || trap == 0x600)
printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
if (current)
printf("current = %x, pid = %d, comm = %s\n",
......@@ -774,9 +793,14 @@ prregs(struct pt_regs *fp)
if (scanhex(&base))
fp = (struct pt_regs *) base;
for (n = 0; n < 32; ++n)
for (n = 0; n < 32; ++n) {
printf("R%.2d = %.8x%s", n, fp->gpr[n],
(n & 3) == 3? "\n": " ");
if (n == 12 && !FULL_REGS(fp)) {
printf("\n");
break;
}
}
printf("pc = %.8x msr = %.8x lr = %.8x cr = %.8x\n",
fp->nip, fp->msr, fp->link, fp->ccr);
printf("ctr = %.8x xer = %.8x trap = %4x\n",
......@@ -1160,7 +1184,7 @@ static char *fault_chars[] = { "--", "**", "##" };
static void
handle_fault(struct pt_regs *regs)
{
fault_type = regs->trap == 0x200? 0: regs->trap == 0x300? 1: 2;
fault_type = TRAP(regs) == 0x200? 0: TRAP(regs) == 0x300? 1: 2;
longjmp(bus_error_jmp, 1);
}
......
......@@ -8,7 +8,6 @@
#include <linux/config.h>
#include <asm/smp.h>
/* entry.S is sensitive to the offsets of these fields */
/* The __last_jiffy_stamp field is needed to ensure that no decrementer
* interrupt is lost on SMP machines. Since on most CPUs it is in the same
* cache line as local_irq_count, it is cheap to access and is also used on UP
......@@ -40,8 +39,8 @@ typedef struct {
#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0)
#define hardirq_endlock(cpu) do { } while (0)
#define hardirq_enter(cpu) (local_irq_count(cpu)++)
#define hardirq_exit(cpu) (local_irq_count(cpu)--)
#define hardirq_enter(cpu) do { preempt_disable(); local_irq_count(cpu)++; } while (0)
#define hardirq_exit(cpu) do { local_irq_count(cpu)--; preempt_enable(); } while (0)
#define synchronize_irq() do { } while (0)
#define release_irqlock(cpu) do { } while (0)
......@@ -76,6 +75,7 @@ static inline void hardirq_enter(int cpu)
{
unsigned int loops = 10000000;
preempt_disable();
++local_irq_count(cpu);
while (test_bit(0,&global_irq_lock)) {
if (cpu == global_irq_holder) {
......@@ -97,6 +97,7 @@ static inline void hardirq_enter(int cpu)
static inline void hardirq_exit(int cpu)
{
--local_irq_count(cpu);
preempt_enable();
}
static inline int hardirq_trylock(int cpu)
......
......@@ -31,6 +31,11 @@
#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 SAVE_NVGPRS(base) SAVE_GPR(13, base); SAVE_8GPRS(14, base); \
SAVE_10GPRS(22, base)
#define REST_NVGPRS(base) REST_GPR(13, base); REST_8GPRS(14, base); \
REST_10GPRS(22, 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_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
......
......@@ -49,12 +49,12 @@
#define MSR_LE (1<<0) /* Little Endian */
#ifdef CONFIG_APUS_FAST_EXCEPT
#define MSR_ MSR_ME|MSR_IP|MSR_RI
#define MSR_ (MSR_ME|MSR_IP|MSR_RI)
#else
#define MSR_ MSR_ME|MSR_RI
#define MSR_ (MSR_ME|MSR_RI)
#endif
#define MSR_KERNEL MSR_|MSR_IR|MSR_DR
#define MSR_USER MSR_KERNEL|MSR_PR|MSR_EE
#define MSR_KERNEL (MSR_|MSR_IR|MSR_DR)
#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE)
/* Floating Point Status and Control Register (FPSCR) Fields */
......
......@@ -33,14 +33,16 @@ struct pt_regs {
unsigned long mq; /* 601 only (not used at present) */
/* Used on APUS to hold IPL value. */
unsigned long trap; /* Reason for being here */
/* N.B. for critical exceptions on 4xx, the dar and dsisr
fields are overloaded to hold srr0 and srr1. */
unsigned long dar; /* Fault registers */
unsigned long dsisr;
unsigned long result; /* Result of a system call */
};
#endif
/* iSeries uses mq field for soft enable flag */
#define softEnable mq
#endif /* __ASSEMBLY__ */
#ifdef __KERNEL__
#define STACK_FRAME_OVERHEAD 16 /* size of minimum stack frame */
......@@ -48,9 +50,28 @@ struct pt_regs {
/* Size of stack frame allocated when calling signal handler. */
#define __SIGNAL_FRAMESIZE 64
#ifndef __ASSEMBLY__
#define instruction_pointer(regs) ((regs)->nip)
#define user_mode(regs) (((regs)->msr & MSR_PR) != 0)
/*
* 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.
* On 4xx we use the next bit to indicate whether the exception
* is a critical exception (1 means it is).
*/
#define FULL_REGS(regs) (((regs)->trap & 1) == 0)
#define IS_CRITICAL_EXC(regs) (((regs)->trap & 2) == 0)
#define TRAP(regs) ((regs)->trap & ~0xF)
#define CHECK_FULL_REGS(regs) \
do { \
if ((regs)->trap & 1) \
printk(KERN_CRIT "%s: partial register set\n", __FUNCTION__); \
} while (0)
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
/*
......
/*
* BK Id: SCCS/s.smplock.h 1.10 10/23/01 08:09:35 trini
* BK Id: %F% %I% %G% %U% %#%
*/
/*
* <asm/smplock.h>
......@@ -15,17 +15,19 @@
extern spinlock_t kernel_flag;
#ifdef CONFIG_SMP
#define kernel_locked() spin_is_locked(&kernel_flag)
#elif defined(CONFIG_PREEMPT)
#define kernel_locked() preempt_get_count()
#endif
/*
* Release global kernel lock and global interrupt lock
*/
#define release_kernel_lock(task, cpu) \
do { \
if (task->lock_depth >= 0) \
if (unlikely(task->lock_depth >= 0)) \
spin_unlock(&kernel_flag); \
release_irqlock(cpu); \
__sti(); \
} while (0)
/*
......@@ -33,7 +35,7 @@ do { \
*/
#define reacquire_kernel_lock(task) \
do { \
if (task->lock_depth >= 0) \
if (unlikely(task->lock_depth >= 0)) \
spin_lock(&kernel_flag); \
} while (0)
......@@ -47,8 +49,14 @@ do { \
*/
static __inline__ void lock_kernel(void)
{
#ifdef CONFIG_PREEMPT
if (current->lock_depth == -1)
spin_lock(&kernel_flag);
++current->lock_depth;
#else
if (!++current->lock_depth)
spin_lock(&kernel_flag);
#endif /* CONFIG_PREEMPT */
}
static __inline__ void unlock_kernel(void)
......
/*
* BK Id: SCCS/s.softirq.h 1.13 07/12/01 20:02:34 paulus
* BK Id: %F% %I% %G% %U% %#%
*/
#ifdef __KERNEL__
#ifndef __ASM_SOFTIRQ_H
......@@ -10,6 +10,7 @@
#define local_bh_disable() \
do { \
preempt_disable(); \
local_bh_count(smp_processor_id())++; \
barrier(); \
} while (0)
......@@ -18,14 +19,17 @@ do { \
do { \
barrier(); \
local_bh_count(smp_processor_id())--; \
preempt_enable(); \
} while (0)
#define local_bh_enable() \
do { \
barrier(); \
if (!--local_bh_count(smp_processor_id()) \
&& softirq_pending(smp_processor_id())) { \
do_softirq(); \
} \
preempt_enable(); \
} while (0)
#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
......
......@@ -23,6 +23,8 @@ struct thread_info {
unsigned long flags; /* low level flags */
int cpu; /* cpu we're on */
int preempt_count; /* not used at present */
int softirq_count;
int hardirq_count;
};
/*
......@@ -67,6 +69,9 @@ static inline struct thread_info *current_thread_info(void)
#define TI_EXECDOMAIN 4
#define TI_FLAGS 8
#define TI_CPU 12
#define TI_PREEMPT 16
#define TI_SOFTIRQ 20
#define TI_HARDIRQ 24
#define PREEMPT_ACTIVE 0x4000000
......
......@@ -234,7 +234,6 @@
#define __NR(n) #n
#define __syscall_return(type) \
return (__sc_err & 0x10000000 ? errno = __sc_ret, __sc_ret = -1 : 0), \
(type) __sc_ret
......@@ -403,8 +402,9 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
__syscall_return (type); \
}
#ifdef __KERNEL__
#ifdef __KERNEL_SYSCALLS__
#define __NR__exit __NR_exit
/*
* Forking from kernel space will result in the child getting a new,
......@@ -414,29 +414,24 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
* the child.
*/
#ifdef __KERNEL_SYSCALLS__
/*
* System call prototypes.
*/
#define __NR__exit __NR_exit
static inline _syscall0(int,pause)
static inline _syscall0(int,sync)
static inline _syscall0(pid_t,setsid)
static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
static inline _syscall1(int,dup,int,fd)
static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
static inline _syscall1(int,close,int,fd)
static inline _syscall1(int,_exit,int,exitcode)
static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
static inline _syscall1(int,delete_module,const char *,name)
extern pid_t setsid(void);
extern int write(int fd, const char *buf, off_t count);
extern int read(int fd, char *buf, off_t count);
extern off_t lseek(int fd, off_t offset, int count);
extern int dup(int fd);
extern int execve(const char *file, char **argv, char **envp);
extern int open(const char *file, int flag, int mode);
extern int close(int fd);
extern pid_t waitpid(pid_t pid, int *wait_stat, int options);
static inline pid_t wait(int * wait_stat)
{
return waitpid(-1, wait_stat, 0);
}
#endif /* __KERNEL_SYSCALLS__ */
/*
......@@ -447,4 +442,6 @@ static inline pid_t wait(int * wait_stat)
*/
#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
#endif /* __KERNEL__ */
#endif /* _ASM_PPC_UNISTD_H_ */
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