diff options
| author | Paul Mackerras <paulus@samba.org> | 2003-09-08 06:36:41 +1000 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2003-09-08 06:36:41 +1000 |
| commit | d33a40e5065b984d2179c682b6da8f42456e880b (patch) | |
| tree | 535752e30510d2b53d9a3a50c8cb1131e4e748c9 | |
| parent | 79b8787e3b3ee7d333e9b7eb7f49cfb92a9d0ffd (diff) | |
| parent | 2550d7f1901b601341354b3a03ab076dd9189fe0 (diff) | |
Merge samba.org:/home/paulus/kernel/linux-2.5
into samba.org:/home/paulus/kernel/for-linus-ppc
| -rw-r--r-- | arch/ppc/kernel/align.c | 32 | ||||
| -rw-r--r-- | arch/ppc/kernel/asm-offsets.c | 3 | ||||
| -rw-r--r-- | arch/ppc/kernel/head.S | 2 | ||||
| -rw-r--r-- | arch/ppc/kernel/misc.S | 2 | ||||
| -rw-r--r-- | arch/ppc/kernel/process.c | 1 | ||||
| -rw-r--r-- | arch/ppc/kernel/signal.c | 607 | ||||
| -rw-r--r-- | arch/ppc/kernel/traps.c | 188 | ||||
| -rw-r--r-- | include/asm-ppc/bitops.h | 8 | ||||
| -rw-r--r-- | include/asm-ppc/highmem.h | 5 | ||||
| -rw-r--r-- | include/asm-ppc/processor.h | 1 | ||||
| -rw-r--r-- | include/asm-ppc/ucontext.h | 26 |
11 files changed, 531 insertions, 344 deletions
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index ed5a13ca643f..d942c318675d 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -21,11 +21,11 @@ struct aligninfo { unsigned char flags; }; -#if defined(CONFIG_4xx) +#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) #define OPCD(inst) (((inst) & 0xFC000000) >> 26) #define RS(inst) (((inst) & 0x03E00000) >> 21) #define RA(inst) (((inst) & 0x001F0000) >> 16) -#define IS_DFORM(code) ((code) >= 32 && (code) <= 55) +#define IS_XFORM(code) ((code) == 31) #endif #define INVALID { 0, 0 } @@ -61,9 +61,9 @@ static struct aligninfo aligninfo[128] = { { 4, ST+F+S }, /* 00 0 1010: stfs */ { 8, ST+F }, /* 00 0 1011: stfd */ INVALID, /* 00 0 1100 */ - INVALID, /* 00 0 1101 */ + INVALID, /* 00 0 1101: ld/ldu/lwa */ INVALID, /* 00 0 1110 */ - INVALID, /* 00 0 1111 */ + INVALID, /* 00 0 1111: std/stdu */ { 4, LD+U }, /* 00 1 0000: lwzu */ INVALID, /* 00 1 0001 */ { 4, ST+U }, /* 00 1 0010: stwu */ @@ -80,12 +80,12 @@ static struct aligninfo aligninfo[128] = { INVALID, /* 00 1 1101 */ INVALID, /* 00 1 1110 */ INVALID, /* 00 1 1111 */ - INVALID, /* 01 0 0000 */ + INVALID, /* 01 0 0000: ldx */ INVALID, /* 01 0 0001 */ - INVALID, /* 01 0 0010 */ + INVALID, /* 01 0 0010: stdx */ INVALID, /* 01 0 0011 */ INVALID, /* 01 0 0100 */ - INVALID, /* 01 0 0101: lwax?? */ + INVALID, /* 01 0 0101: lwax */ INVALID, /* 01 0 0110 */ INVALID, /* 01 0 0111 */ { 0, LD+HARD }, /* 01 0 1000: lswx */ @@ -96,12 +96,12 @@ static struct aligninfo aligninfo[128] = { INVALID, /* 01 0 1101 */ INVALID, /* 01 0 1110 */ INVALID, /* 01 0 1111 */ - INVALID, /* 01 1 0000 */ + INVALID, /* 01 1 0000: ldux */ INVALID, /* 01 1 0001 */ - INVALID, /* 01 1 0010 */ + INVALID, /* 01 1 0010: stdux */ INVALID, /* 01 1 0011 */ INVALID, /* 01 1 0100 */ - INVALID, /* 01 1 0101: lwaux?? */ + INVALID, /* 01 1 0101: lwaux */ INVALID, /* 01 1 0110 */ INVALID, /* 01 1 0111 */ INVALID, /* 01 1 1000 */ @@ -157,9 +157,9 @@ static struct aligninfo aligninfo[128] = { { 4, ST+F+S }, /* 11 0 1010: stfsx */ { 8, ST+F }, /* 11 0 1011: stfdx */ INVALID, /* 11 0 1100 */ - INVALID, /* 11 0 1101 */ + INVALID, /* 11 0 1101: lmd */ INVALID, /* 11 0 1110 */ - INVALID, /* 11 0 1111 */ + INVALID, /* 11 0 1111: stmd */ { 4, LD+U }, /* 11 1 0000: lwzux */ INVALID, /* 11 1 0001 */ { 4, ST+U }, /* 11 1 0010: stwux */ @@ -184,7 +184,7 @@ int fix_alignment(struct pt_regs *regs) { int instr, nb, flags; -#if defined(CONFIG_4xx) +#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) int opcode, f1, f2, f3; #endif int i, t; @@ -199,9 +199,11 @@ fix_alignment(struct pt_regs *regs) CHECK_FULL_REGS(regs); -#if defined(CONFIG_4xx) +#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) /* The 4xx-family processors have no DSISR register, * so we emulate it. + * The POWER4 has a DSISR register but doesn't set it on + * an alignment fault. -- paulus */ instr = *((unsigned int *)regs->nip); @@ -209,7 +211,7 @@ fix_alignment(struct pt_regs *regs) reg = RS(instr); areg = RA(instr); - if (IS_DFORM(opcode)) { + if (!IS_XFORM(opcode)) { f1 = 0; f2 = (instr & 0x04000000) >> 26; f3 = (instr & 0x78000000) >> 27; diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c index 6e6f78e4e3a0..e41af4ff4dc6 100644 --- a/arch/ppc/kernel/asm-offsets.c +++ b/arch/ppc/kernel/asm-offsets.c @@ -52,6 +52,7 @@ main(void) DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave)); DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); + DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); #endif /* CONFIG_ALTIVEC */ /* Interrupt register frame */ DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); @@ -101,7 +102,7 @@ main(void) DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); - /* The PowerPC 400-class processors have neither the DAR nor the DSISR + /* The PowerPC 400-class & Book-E 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 critical interrupts we use them to * hold SRR0 and SRR1. diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 0311ae117dee..af68a4ee38d8 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -915,7 +915,9 @@ load_up_altivec: /* enable use of AltiVec after return */ oris r9,r9,MSR_VEC@h mfspr r5,SPRG3 /* current task's THREAD (phys) */ + li r4,1 li r10,THREAD_VSCR + stw r4,THREAD_USED_VR(r5) lvx vr0,r10,r5 mtvscr vr0 REST_32VR(0,r10,r5) diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index a41d10ee1614..b5f86a6d3267 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -1379,7 +1379,7 @@ _GLOBAL(sys_call_table) .long sys_clock_gettime .long sys_clock_getres .long sys_clock_nanosleep - .long sys_ni_syscall /* reserved for swapcontext */ + .long sys_swapcontext .long sys_tgkill /* 250 */ .long sys_utimes .long sys_statfs64 diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index f0a608eb1a6e..82e09cc776bc 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -415,6 +415,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) memset(current->thread.vr, 0, sizeof(current->thread.vr)); memset(¤t->thread.vscr, 0, sizeof(current->thread.vscr)); current->thread.vrsave = 0; + current->thread.used_vr = 0; #endif /* CONFIG_ALTIVEC */ } diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 41efaef2153a..c737078db5b0 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -41,18 +41,6 @@ extern void sigreturn_exit(struct pt_regs *); #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) -/* - * These are the flags in the MSR that the user is allowed to change - * by modifying the saved value of the MSR on the stack. SE and BE - * should not be in this list since gdb may want to change these. I.e, - * you should be able to step out of a signal handler to see what - * instruction executes next after the signal handler completes. - * Alternately, if you stepped into a signal handler, you should be - * able to continue 'til the next breakpoint from within the signal - * handler, even if the handler returns. - */ -#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1) - int do_signal(sigset_t *oldset, struct pt_regs *regs); /* @@ -72,8 +60,8 @@ sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, spin_unlock_irq(¤t->sighand->siglock); regs->result = -EINTR; - regs->ccr |= 0x10000000; regs->gpr[3] = EINTR; + regs->ccr |= 0x10000000; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); @@ -103,8 +91,8 @@ sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int p4, spin_unlock_irq(¤t->sighand->siglock); regs->result = -EINTR; - regs->ccr |= 0x10000000; regs->gpr[3] = EINTR; + regs->ccr |= 0x10000000; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); @@ -164,305 +152,389 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, * */ struct sigregs { - elf_gregset_t gp_regs; - double fp_regs[ELF_NFPREG]; - unsigned long tramp[2]; + struct mcontext mctx; /* all the register values */ /* Programs using the rs6000/xcoff abi can save up to 19 gp regs and 18 fp regs below sp before decrementing it. */ int abigap[56]; }; -struct rt_sigframe -{ - unsigned long _unused[2]; - struct siginfo *pinfo; - void *puc; - struct siginfo info; - struct ucontext uc; -}; - +/* We use the mc_pad field for the signal return trampoline. */ +#define tramp mc_pad /* * When we have rt signals to deliver, we set up on the * user stack, going down from the original stack pointer: - * a sigregs struct - * one rt_sigframe struct (siginfo + ucontext) - * a gap of __SIGNAL_FRAMESIZE bytes + * one rt_sigframe struct (siginfo + ucontext + ABI gap) + * a gap of __SIGNAL_FRAMESIZE+16 bytes + * (the +16 is to get the siginfo and ucontext in the same + * positions as in older kernels). * * Each of these things must be a multiple of 16 bytes in size. * */ -int sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, - struct pt_regs *regs) +struct rt_sigframe { - struct rt_sigframe __user *rt_sf; - struct sigcontext sigctx; - struct sigregs __user *sr; - elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ - sigset_t set; - stack_t st; + struct siginfo info; + struct ucontext uc; + /* Programs using the rs6000/xcoff abi can save up to 19 gp regs + and 18 fp regs below sp before decrementing it. */ + int abigap[56]; +}; - rt_sf = (struct rt_sigframe __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); - if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)) - || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set)) - || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st))) - goto badframe; - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); +/* + * Save the current user registers on the user stack. + * We only save the altivec registers if the process has used + * altivec instructions at some point. + */ +static int +save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret) +{ + /* save general and floating-point registers */ + CHECK_FULL_REGS(regs); if (regs->msr & MSR_FP) giveup_fpu(current); + if (__copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE) + || __copy_to_user(&frame->mc_fregs, current->thread.fpr, + ELF_NFPREG * sizeof(double))) + return 1; - /* restore registers - - * sigctx is initialized to point to the - * preamble frame (where registers are stored) - * see handle_signal() + current->thread.fpscr = 0; /* turn off all fp exceptions */ + +#ifdef CONFIG_ALTIVEC + /* save altivec registers */ + if (current->thread.used_vr) { + if (regs->msr & MSR_VEC) + giveup_altivec(current); + if (__copy_to_user(&frame->mc_vregs, current->thread.vr, + ELF_NVRREG * sizeof(vector128))) + return 1; + /* set MSR_VEC in the saved MSR value to indicate that + frame->mc_vregs contains valid data */ + if (__put_user(regs->msr | MSR_VEC, &frame->mc_gregs[PT_MSR])) + return 1; + } + /* else assert((regs->msr & MSR_VEC) == 0) */ + + /* We always copy to/from vrsave, it's 0 if we don't have or don't + * use altivec. Since VSCR only contains 32 bits saved in the least + * significant bits of a vector, we "cheat" and stuff VRSAVE in the + * most significant bits of that same vector. --BenH */ - sr = (struct sigregs __user *) sigctx.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); - memcpy(regs, saved_regs, GP_REGS_SIZE); - if (copy_from_user(current->thread.fpr, &sr->fp_regs, - sizeof(sr->fp_regs))) - goto badframe; + if (__put_user(current->thread.vrsave, (u32 *)&frame->mc_vregs[32])) + return 1; +#endif /* CONFIG_ALTIVEC */ + + if (sigret) { + /* Set up the sigreturn trampoline: li r0,sigret; sc */ + if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) + || __put_user(0x44000002UL, &frame->tramp[1])) + return 1; + flush_icache_range((unsigned long) &frame->tramp[0], + (unsigned long) &frame->tramp[2]); + } - sigreturn_exit(regs); /* doesn't return here */ return 0; +} -badframe: - do_exit(SIGSEGV); +/* + * Restore the current user register values from the user stack, + * (except for MSR). + */ +static int +restore_user_regs(struct pt_regs *regs, struct mcontext __user *sr) +{ +#ifdef CONFIG_ALTIVEC + unsigned long msr; +#endif + + /* copy up to but not including MSR */ + if (__copy_from_user(regs, &sr->mc_gregs, PT_MSR * sizeof(elf_greg_t))) + return 1; + /* copy from orig_r3 (the word after the MSR) up to the end */ + if (__copy_from_user(®s->orig_gpr3, &sr->mc_gregs[PT_ORIG_R3], + GP_REGS_SIZE - PT_ORIG_R3 * sizeof(elf_greg_t))) + return 1; + + /* force the process to reload the FP registers from + current->thread when it next does FP instructions */ + regs->msr &= ~MSR_FP; + if (__copy_from_user(current->thread.fpr, &sr->mc_fregs, + sizeof(sr->mc_fregs))) + return 1; + +#ifdef CONFIG_ALTIVEC + /* force the process to reload the altivec registers from + current->thread when it next does altivec instructions */ + regs->msr &= ~MSR_VEC; + if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_VEC) != 0) { + /* restore altivec registers from the stack */ + if (__copy_from_user(current->thread.vr, &sr->mc_vregs, + sizeof(sr->mc_vregs))) + return 1; + } else if (current->thread.used_vr) + memset(¤t->thread.vr, 0, sizeof(current->thread.vr)); + + /* Always get VRSAVE back */ + if (__get_user(current->thread.vrsave, (u32 *)&sr->mc_vregs[32])) + return 1; +#endif /* CONFIG_ALTIVEC */ + + return 0; } +/* + * Restore the user process's signal mask + */ static void -setup_rt_frame(struct pt_regs *regs, struct sigregs __user *frame, - signed long newsp) +restore_sigmask(sigset_t *set) { - struct rt_sigframe __user *rt_sf = (struct rt_sigframe __user *) newsp; + sigdelsetmask(set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = *set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); +} - /* Set up preamble frame */ - if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) +/* + * Set up a signal frame for a "real-time" signal handler + * (one which gets siginfo). + */ +static void +handle_rt_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, + unsigned long newsp) +{ + struct rt_sigframe __user *rt_sf; + struct mcontext __user *frame; + unsigned long origsp = newsp; + + /* Set up Signal Frame */ + /* Put a Real Time Context onto stack */ + newsp -= sizeof(*rt_sf); + rt_sf = (struct rt_sigframe __user *) newsp; + + /* create a stack frame for the caller of the handler */ + newsp -= __SIGNAL_FRAMESIZE + 16; + + if (verify_area(VERIFY_WRITE, (void __user *) newsp, origsp - newsp)) 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)) - /* Set up to return from user space. - It calls the sc exception at offset 0x9999 - for sys_rt_sigreturn(). - */ - || __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0]) - || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ + + /* Put the siginfo & fill in most of the ucontext */ + if (copy_siginfo_to_user(&rt_sf->info, info) + || __put_user(0, &rt_sf->uc.uc_flags) + || __put_user(0, &rt_sf->uc.uc_link) + || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) + || __put_user(sas_ss_flags(regs->gpr[1]), + &rt_sf->uc.uc_stack.ss_flags) + || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) + || __put_user(&rt_sf->uc.uc_mcontext, &rt_sf->uc.uc_regs) + || __copy_to_user(&rt_sf->uc.uc_oldsigmask, oldset, sizeof(*oldset)) + || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))) goto badframe; - flush_icache_range((unsigned long) &frame->tramp[0], - (unsigned long) &frame->tramp[2]); - current->thread.fpscr = 0; /* turn off all fp exceptions */ - /* Retrieve rt_sigframe from stack and - set up registers for signal handler - */ - newsp -= __SIGNAL_FRAMESIZE; - if (put_user(regs->gpr[1], (unsigned long __user *)newsp) - || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler) - || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal) - || get_user(regs->gpr[4], (unsigned long __user *)&rt_sf->pinfo) - || get_user(regs->gpr[5], (unsigned long __user *)&rt_sf->puc)) + /* Save user registers on the stack */ + frame = &rt_sf->uc.uc_mcontext; + if (save_user_regs(regs, frame, __NR_rt_sigreturn)) goto badframe; + if (put_user(regs->gpr[1], (unsigned long __user *)newsp)) + goto badframe; regs->gpr[1] = newsp; + regs->gpr[3] = sig; + regs->gpr[4] = (unsigned long) &rt_sf->info; + regs->gpr[5] = (unsigned long) &rt_sf->uc; regs->gpr[6] = (unsigned long) rt_sf; + regs->nip = (unsigned long) ka->sa.sa_handler; regs->link = (unsigned long) frame->tramp; + regs->trap = 0; return; badframe: #if DEBUG_SIG - printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", + printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - do_exit(SIGSEGV); + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); } -/* - * Do a signal return; undo the signal stack. - */ -int sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, - struct pt_regs *regs) +static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs) { - struct sigcontext __user *sc; - struct sigcontext sigctx; - struct sigregs __user *sr; - elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ sigset_t set; - sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); - if (copy_from_user(&sigctx, sc, sizeof(sigctx))) - goto badframe; + if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(set))) + return -EFAULT; + restore_sigmask(&set); - set.sig[0] = sigctx.oldmask; -#if _NSIG_WORDS > 1 - set.sig[1] = sigctx._unused[3]; -#endif - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - if (regs->msr & MSR_FP ) - giveup_fpu(current); + if (restore_user_regs(regs, &ucp->uc_mcontext)) + return -EFAULT; - /* restore registers */ - sr = (struct sigregs __user *) sigctx.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); - memcpy(regs, saved_regs, GP_REGS_SIZE); + return 0; +} - if (copy_from_user(current->thread.fpr, &sr->fp_regs, - sizeof(sr->fp_regs))) - goto badframe; +int sys_swapcontext(struct ucontext __user *old_ctx, + struct ucontext __user *new_ctx, + int r5, int r6, int r7, int r8, struct pt_regs *regs) +{ + unsigned char tmp; + + if (old_ctx != NULL) { + if (verify_area(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) + || save_user_regs(regs, &old_ctx->uc_mcontext, 0) + || __copy_to_user(&old_ctx->uc_sigmask, + ¤t->blocked, sizeof(sigset_t)) + /* the next 2 things aren't strictly necessary */ + || __copy_to_user(&old_ctx->uc_oldsigmask, + ¤t->blocked, sizeof(sigset_t)) + || __put_user(&old_ctx->uc_mcontext, &old_ctx->uc_regs)) + return -EFAULT; + } + if (new_ctx == NULL) + return 0; + if (verify_area(VERIFY_READ, new_ctx, sizeof(*new_ctx)) + || __get_user(tmp, (u8 *) new_ctx) + || __get_user(tmp, (u8 *) (new_ctx + 1) - 1)) + return -EFAULT; + + /* + * If we get a fault copying the context into the kernel's + * image of the user's registers, we can't just return -EFAULT + * because the user's registers will be corrupted. For instance + * the NIP value may have been updated but not some of the + * other registers. Given that we have done the verify_area + * and successfully read the first and last bytes of the region + * above, this should only happen in an out-of-memory situation + * or if another thread unmaps the region containing the context. + * We kill the task with a SIGSEGV in this situation. + */ + if (do_setcontext(new_ctx, regs)) + do_exit(SIGSEGV); + sigreturn_exit(regs); + /* doesn't actually return back to here */ + return 0; +} + +int sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, + struct pt_regs *regs) +{ + struct rt_sigframe __user *rt_sf; + + rt_sf = (struct rt_sigframe __user *) + (regs->gpr[1] + __SIGNAL_FRAMESIZE + 16); + if (verify_area(VERIFY_READ, rt_sf, sizeof(struct rt_sigframe))) + goto bad; + if (do_setcontext(&rt_sf->uc, regs)) + goto bad; + + /* + * It's not clear whether or why it is desirable to save the + * sigaltstack setting on signal delivery and restore it on + * signal return. But other architectures do this and we have + * always done it up until now so it is probably better not to + * change it. -- paulus + */ + do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); sigreturn_exit(regs); /* doesn't return here */ return 0; -badframe: - do_exit(SIGSEGV); -} + bad: + force_sig(SIGSEGV, current); + return 0; +} /* - * Set up a signal frame. + * OK, we're invoking a handler */ static void -setup_frame(struct pt_regs *regs, struct sigregs __user *frame, - unsigned long newsp) +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, + unsigned long newsp) { - struct sigcontext __user *sc = (struct sigcontext __user *) newsp; + struct sigcontext __user *sc; + struct sigregs __user *frame; + unsigned long origsp = newsp; - if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + /* Set up Signal Frame */ + newsp -= sizeof(struct sigregs); + frame = (struct sigregs __user *) newsp; + + /* Put a sigcontext on the stack */ + newsp -= sizeof(*sc); + sc = (struct sigcontext __user *) newsp; + + /* create a stack frame for the caller of the handler */ + newsp -= __SIGNAL_FRAMESIZE; + + if (verify_area(VERIFY_WRITE, (void *) newsp, origsp - newsp)) 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(0x38000000UL + __NR_sigreturn, &frame->tramp[0]) - || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ + +#if _NSIG != 64 +#error "Please adjust handle_signal()" +#endif + if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) + || __put_user(oldset->sig[0], &sc->oldmask) + || __put_user(oldset->sig[1], &sc->_unused[3]) + || __put_user((struct pt_regs *)frame, &sc->regs) + || __put_user(sig, &sc->signal)) goto badframe; - flush_icache_range((unsigned long) &frame->tramp[0], - (unsigned long) &frame->tramp[2]); - current->thread.fpscr = 0; /* turn off all fp exceptions */ - newsp -= __SIGNAL_FRAMESIZE; - if (put_user(regs->gpr[1], (unsigned long __user *)newsp) - || get_user(regs->nip, &sc->handler) - || get_user(regs->gpr[3], &sc->signal)) + if (save_user_regs(regs, &frame->mctx, __NR_sigreturn)) + goto badframe; + + if (put_user(regs->gpr[1], (unsigned long *)newsp)) goto badframe; regs->gpr[1] = newsp; + regs->gpr[3] = sig; regs->gpr[4] = (unsigned long) sc; - regs->link = (unsigned long) frame->tramp; + regs->nip = (unsigned long) ka->sa.sa_handler; + regs->link = (unsigned long) frame->mctx.tramp; + regs->trap = 0; return; badframe: #if DEBUG_SIG - printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", - regs, frame, newsp); + printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n", + regs, frame, *newspp); #endif - do_exit(SIGSEGV); + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); } /* - * OK, we're invoking a handler + * Do a signal return; undo the signal stack. */ -static void -handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs, unsigned long *newspp, unsigned long frame) +int sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, + struct pt_regs *regs) { struct sigcontext __user *sc; - struct rt_sigframe __user *rt_sf; - struct k_sigaction *ka = ¤t->sighand->action[sig-1]; - - if (TRAP(regs) == 0x0C00 /* System Call! */ - && ((int)regs->result == -ERESTARTNOHAND || - (int)regs->result == -ERESTART_RESTARTBLOCK || - ((int)regs->result == -ERESTARTSYS && - !(ka->sa.sa_flags & SA_RESTART)))) { - if ((int)regs->result == -ERESTART_RESTARTBLOCK) - current_thread_info()->restart_block.fn - = do_no_restart_syscall; - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - } + struct sigcontext sigctx; + struct mcontext __user *sr; + sigset_t set; - /* Set up Signal Frame */ - if (ka->sa.sa_flags & SA_SIGINFO) { - /* Put a Real Time Context onto stack */ - *newspp -= sizeof(*rt_sf); - rt_sf = (struct rt_sigframe __user *) *newspp; - if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf))) - goto badframe; - - if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler) - || __put_user(&rt_sf->info, &rt_sf->pinfo) - || __put_user(&rt_sf->uc, &rt_sf->puc) - /* Put the siginfo */ - || copy_siginfo_to_user(&rt_sf->info, info) - /* Create the ucontext */ - || __put_user(0, &rt_sf->uc.uc_flags) - || __put_user(0, &rt_sf->uc.uc_link) - || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) - || __put_user(sas_ss_flags(regs->gpr[1]), - &rt_sf->uc.uc_stack.ss_flags) - || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) - || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset)) - /* mcontext.regs points to preamble register frame */ - || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs) - || __put_user(sig, &rt_sf->uc.uc_mcontext.signal)) - goto badframe; - } else { - /* Put a sigcontext on the stack */ - *newspp -= sizeof(*sc); - sc = (struct sigcontext __user *) *newspp; - if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) - goto badframe; - - if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) - || __put_user(oldset->sig[0], &sc->oldmask) -#if _NSIG_WORDS > 1 - || __put_user(oldset->sig[1], &sc->_unused[3]) -#endif - || __put_user((struct pt_regs *)frame, &sc->regs) - || __put_user(sig, &sc->signal)) - goto badframe; - } + sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); + if (copy_from_user(&sigctx, sc, sizeof(sigctx))) + goto badframe; - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; + set.sig[0] = sigctx.oldmask; + set.sig[1] = sigctx._unused[3]; + restore_sigmask(&set); - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); - sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } - return; + sr = (struct mcontext *) sigctx.regs; + if (verify_area(VERIFY_READ, sr, sizeof(*sr)) + || restore_user_regs(regs, sr)) + goto badframe; + + sigreturn_exit(regs); /* doesn't return */ + return 0; badframe: -#if DEBUG_SIG - printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n", - regs, frame, *newspp); - printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset); -#endif - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); + return 0; } /* @@ -475,7 +547,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) siginfo_t info; struct k_sigaction *ka; unsigned long frame, newsp; - int signr; + int signr, ret; if (!oldset) oldset = ¤t->blocked; @@ -483,40 +555,65 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) newsp = frame = 0; signr = get_signal_to_deliver(&info, regs, NULL); - if (signr > 0) { - ka = ¤t->sighand->action[signr-1]; - if ( (ka->sa.sa_flags & SA_ONSTACK) - && (! on_sig_stack(regs->gpr[1]))) - newsp = (current->sas_ss_sp + current->sas_ss_size); - else - newsp = regs->gpr[1]; - newsp = frame = newsp - sizeof(struct sigregs); - - /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, oldset, regs, &newsp, frame); - } - if (TRAP(regs) == 0x0C00) { /* System Call! */ - if ((int)regs->result == -ERESTARTNOHAND || - (int)regs->result == -ERESTARTSYS || - (int)regs->result == -ERESTARTNOINTR) { - regs->gpr[3] = regs->orig_gpr3; + ka = (signr == 0)? NULL: ¤t->sighand->action[signr-1]; + + if (TRAP(regs) == 0x0C00 /* System Call! */ + && regs->ccr & 0x10000000 /* error signalled */ + && ((ret = regs->gpr[3]) == ERESTARTSYS + || ret == ERESTARTNOHAND || ret == ERESTARTNOINTR + || ret == ERESTART_RESTARTBLOCK)) { + + if (signr > 0 + && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK + || (ret == ERESTARTSYS + && !(ka->sa.sa_flags & SA_RESTART)))) { + /* make the system call return an EINTR error */ + regs->result = -EINTR; + regs->gpr[3] = EINTR; + /* note that the cr0.SO bit is already set */ + /* clear any restart function that was set */ + if (ret == ERESTART_RESTARTBLOCK) + current_thread_info()->restart_block.fn + = do_no_restart_syscall; + } else { regs->nip -= 4; /* Back up & retry system call */ regs->result = 0; - } else if ((int)regs->result == -ERESTART_RESTARTBLOCK) { - regs->gpr[0] = __NR_restart_syscall; - regs->nip -= 4; - regs->result = 0; + regs->trap = 0; + if (ret == ERESTART_RESTARTBLOCK) + regs->gpr[0] = __NR_restart_syscall; + else + regs->gpr[3] = regs->orig_gpr3; } } - if (newsp == frame) + if (signr == 0) return 0; /* no signals delivered */ + if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size + && !on_sig_stack(regs->gpr[1])) + newsp = current->sas_ss_sp + current->sas_ss_size; + else + newsp = regs->gpr[1]; + newsp &= ~0xfUL; + + /* Whee! Actually deliver the signal. */ if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(regs, (struct sigregs __user *) frame, newsp); + handle_rt_signal(signr, ka, &info, oldset, regs, newsp); else - setup_frame(regs, (struct sigregs __user *) frame, newsp); + handle_signal(signr, ka, &info, oldset, regs, newsp); + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked, signr); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + return 1; } diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index cc57bcdda39f..1f1304c15b64 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -95,14 +95,19 @@ void die(const char * str, struct pt_regs * fp, long err) } void -_exception(int signr, struct pt_regs *regs) +_exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { - if (!user_mode(regs)) - { + siginfo_t info; + + if (!user_mode(regs)) { debugger(regs); die("Exception in kernel mode", regs, signr); } - force_sig(signr, current); + info.si_signo = signr; + info.si_errno = 0; + info.si_code = code; + info.si_addr = (void *) addr; + force_sig_info(signr, &info, current); } /* @@ -154,12 +159,40 @@ static inline int check_io_access(struct pt_regs *regs) return 0; } +#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) +/* On 4xx, the reason for the machine check or program exception + is in the ESR. */ +#define get_reason(regs) ((regs)->dsisr) +#define REASON_FP 0 +#define REASON_ILLEGAL ESR_PIL +#define REASON_PRIVILEGED ESR_PPR +#define REASON_TRAP ESR_PTR + +/* single-step stuff */ +#define single_stepping(regs) (current->thread.dbcr0 & DBCR0_IC) +#define clear_single_step(regs) (current->thread.dbcr0 &= ~DBCR0_IC) + +#else +/* On non-4xx, the reason for the machine check or program + exception is in the MSR. */ +#define get_reason(regs) ((regs)->msr) +#define REASON_FP 0x100000 +#define REASON_ILLEGAL 0x80000 +#define REASON_PRIVILEGED 0x40000 +#define REASON_TRAP 0x20000 + +#define single_stepping(regs) ((regs)->msr & MSR_SE) +#define clear_single_step(regs) ((regs)->msr &= ~MSR_SE) +#endif + void MachineCheckException(struct pt_regs *regs) { + unsigned long reason = get_reason(regs); + if (user_mode(regs)) { regs->msr |= MSR_RI; - _exception(SIGSEGV, regs); + _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); return; } @@ -178,10 +211,18 @@ MachineCheckException(struct pt_regs *regs) if (check_io_access(regs)) return; -#ifndef CONFIG_4xx - printk(KERN_CRIT "Machine check in kernel mode.\n"); - printk(KERN_CRIT "Caused by (from SRR1=%lx): ", regs->msr); - switch (regs->msr & 0x601F0000) { +#ifdef CONFIG_4xx + if (reason & ESR_IMCP) { + printk("Instruction"); + mtspr(SPRN_ESR, reason & ~ESR_IMCP); + } else + printk("Data"); + printk(" machine check in kernel mode.\n"); + +#else /* !CONFIG_4xx */ + printk("Machine check in kernel mode.\n"); + printk("Caused by (from SRR1=%lx): ", reason); + switch (reason & 0x601F0000) { case 0x80000: printk("Machine check signal\n"); break; @@ -208,15 +249,6 @@ MachineCheckException(struct pt_regs *regs) default: printk("Unknown values in msr\n"); } - -#else /* CONFIG_4xx */ - /* Note that the ESR gets stored in regs->dsisr on 4xx. */ - if (regs->dsisr & ESR_MCI) { - printk(KERN_CRIT "Instruction"); - mtspr(SPRN_ESR, regs->dsisr & ~ESR_MCI); - } else - printk(KERN_CRIT "Data"); - printk(" machine check in kernel mode.\n"); #endif /* CONFIG_4xx */ debugger(regs); @@ -238,7 +270,7 @@ UnknownException(struct pt_regs *regs) { printk("Bad trap at PC: %lx, MSR: %lx, vector=%lx %s\n", regs->nip, regs->msr, regs->trap, print_tainted()); - _exception(SIGTRAP, regs); + _exception(SIGTRAP, regs, 0, 0); } void @@ -246,13 +278,13 @@ InstructionBreakpoint(struct pt_regs *regs) { if (debugger_iabr_match(regs)) return; - _exception(SIGTRAP, regs); + _exception(SIGTRAP, regs, TRAP_BRKPT, 0); } void RunModeException(struct pt_regs *regs) { - _exception(SIGTRAP, regs); + _exception(SIGTRAP, regs, 0, 0); } /* Illegal instruction emulation support. Originally written to @@ -271,17 +303,17 @@ RunModeException(struct pt_regs *regs) static int emulate_instruction(struct pt_regs *regs) { - uint instword; - uint rd; - uint retval; + u32 instword; + u32 rd; + int retval; - retval = EINVAL; + retval = -EINVAL; if (!user_mode(regs)) return retval; CHECK_FULL_REGS(regs); - if (get_user(instword, (uint __user *)(regs->nip))) + if (get_user(instword, (u32 __user *)(regs->nip))) return -EFAULT; /* Emulate the mfspr rD, PVR. @@ -290,10 +322,23 @@ emulate_instruction(struct pt_regs *regs) rd = (instword >> 21) & 0x1f; regs->gpr[rd] = mfspr(PVR); retval = 0; - } - if (retval == 0) regs->nip += 4; - return(retval); + } + return retval; +} + +/* + * After we have successfully emulated an instruction, we have to + * check if the instruction was being single-stepped, and if so, + * pretend we got a single-step exception. This was pointed out + * by Kumar Gala. -- paulus + */ +static void emulate_single_step(struct pt_regs *regs) +{ + if (single_stepping(regs)) { + clear_single_step(regs); + _exception(SIGTRAP, regs, TRAP_TRACE, 0); + } } /* @@ -349,29 +394,47 @@ check_bug_trap(struct pt_regs *regs) void ProgramCheckException(struct pt_regs *regs) { - int errcode; - -#if defined(CONFIG_4xx) - unsigned int esr = regs->dsisr; - int isbpt = esr & ESR_PTR; + unsigned int reason = get_reason(regs); extern int do_mathemu(struct pt_regs *regs); #ifdef CONFIG_MATH_EMULATION - if (!isbpt && do_mathemu(regs) == 0) + /* (reason & REASON_ILLEGAL) would be the obvious thing here, + * but there seems to be a hardware bug on the 405GP (RevD) + * that means ESR is sometimes set incorrectly - either to + * ESR_DST (!?) or 0. In the process of chasing this with the + * hardware people - not sure if it can happen on any illegal + * instruction or only on FP instructions, whether there is a + * pattern to occurences etc. -dgibson 31/Mar/2003 */ + if (!(reason & REASON_TRAP) && do_mathemu(regs) == 0) { + emulate_single_step(regs); return; + } #endif /* CONFIG_MATH_EMULATION */ -#else /* ! CONFIG_4xx */ - int isbpt = regs->msr & 0x20000; - - if (regs->msr & 0x100000) { + if (reason & REASON_FP) { /* IEEE FP exception */ - _exception(SIGFPE, regs); + int code = 0; + u32 fpscr; + + if (regs->msr & MSR_FP) + giveup_fpu(current); + fpscr = current->thread.fpscr; + fpscr &= fpscr << 22; /* mask summary bits with enables */ + if (fpscr & FPSCR_VX) + code = FPE_FLTINV; + else if (fpscr & FPSCR_OX) + code = FPE_FLTOVF; + else if (fpscr & FPSCR_UX) + code = FPE_FLTUND; + else if (fpscr & FPSCR_ZX) + code = FPE_FLTDIV; + else if (fpscr & FPSCR_XX) + code = FPE_FLTRES; + _exception(SIGFPE, regs, code, regs->nip); return; } -#endif /* ! CONFIG_4xx */ - if (isbpt) { + if (reason & REASON_TRAP) { /* trap exception */ if (debugger_bpt(regs)) return; @@ -379,17 +442,21 @@ ProgramCheckException(struct pt_regs *regs) regs->nip += 4; return; } - _exception(SIGTRAP, regs); + _exception(SIGTRAP, regs, TRAP_BRKPT, 0); return; } - /* Try to emulate it if we should. */ - if ((errcode = emulate_instruction(regs))) { - if (errcode == -EFAULT) - _exception(SIGBUS, regs); - else - _exception(SIGILL, regs); + if (reason & REASON_PRIVILEGED) { + /* Try to emulate it if we should. */ + if (emulate_instruction(regs) == 0) { + emulate_single_step(regs); + return; + } + _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); + return; } + + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); } void @@ -398,7 +465,7 @@ SingleStepException(struct pt_regs *regs) regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ if (debugger_sstep(regs)) return; - _exception(SIGTRAP, regs); + _exception(SIGTRAP, regs, TRAP_TRACE, 0); } void @@ -414,12 +481,12 @@ AlignmentException(struct pt_regs *regs) if (fixed == -EFAULT) { /* fixed == -EFAULT means the operand address was bad */ if (user_mode(regs)) - force_sig(SIGSEGV, current); + _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar); else bad_page_fault(regs, regs->dar, SIGSEGV); return; } - _exception(SIGBUS, regs); + _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); } void @@ -470,16 +537,17 @@ SoftwareEmulation(struct pt_regs *regs) #endif if (errcode) { if (errcode > 0) - _exception(SIGFPE, regs); + _exception(SIGFPE, regs, 0, 0); else if (errcode == -EFAULT) - _exception(SIGSEGV, regs); + _exception(SIGSEGV, regs, 0, 0); else - _exception(SIGILL, regs); - } + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + } else + emulate_single_step(regs); } #endif /* CONFIG_8xx */ -#if defined(CONFIG_4xx) +#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) void DebugException(struct pt_regs *regs, unsigned long debug_status) { @@ -487,7 +555,7 @@ void DebugException(struct pt_regs *regs, unsigned long debug_status) if (debug_status & DBSR_TIE) { /* trap instruction*/ if (!user_mode(regs) && debugger_bpt(regs)) return; - _exception(SIGTRAP, regs); + _exception(SIGTRAP, regs, 0, 0); } #endif @@ -495,10 +563,10 @@ void DebugException(struct pt_regs *regs, unsigned long debug_status) if (!user_mode(regs) && debugger_sstep(regs)) return; current->thread.dbcr0 &= ~DBCR0_IC; - _exception(SIGTRAP, regs); + _exception(SIGTRAP, regs, TRAP_TRACE, 0); } } -#endif /* CONFIG_4xx */ +#endif /* CONFIG_4xx || CONFIG_BOOKE */ #if !defined(CONFIG_TAU_INT) void diff --git a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h index 68e4a5963fb3..e30f536fd830 100644 --- a/include/asm-ppc/bitops.h +++ b/include/asm-ppc/bitops.h @@ -276,7 +276,7 @@ static __inline__ int fls(unsigned int x) * Find the first bit set in a 140-bit bitmap. * The first 100 bits are unlikely to be set. */ -static inline int sched_find_first_bit(unsigned long *b) +static inline int sched_find_first_bit(const unsigned long *b) { if (unlikely(b[0])) return __ffs(b[0]); @@ -295,7 +295,7 @@ static inline int sched_find_first_bit(unsigned long *b) * @offset: The bitnumber to start searching at * @size: The maximum size to search */ -static __inline__ unsigned long find_next_bit(unsigned long *addr, +static __inline__ unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { unsigned int *p = ((unsigned int *) addr) + (offset >> 5); @@ -352,7 +352,7 @@ found_middle: #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) -static __inline__ unsigned long find_next_zero_bit(unsigned long * addr, +static __inline__ unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { unsigned int * p = ((unsigned int *) addr) + (offset >> 5); @@ -411,7 +411,7 @@ static __inline__ int ext2_test_bit(int nr, __const__ void * addr) #define ext2_find_first_zero_bit(addr, size) \ ext2_find_next_zero_bit((addr), (size), 0) -static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, +static __inline__ unsigned long ext2_find_next_zero_bit(const void *addr, unsigned long size, unsigned long offset) { unsigned int *p = ((unsigned int *) addr) + (offset >> 5); diff --git a/include/asm-ppc/highmem.h b/include/asm-ppc/highmem.h index ff202f99218a..eb7c3fef6417 100644 --- a/include/asm-ppc/highmem.h +++ b/include/asm-ppc/highmem.h @@ -26,6 +26,7 @@ #include <linux/interrupt.h> #include <asm/kmap_types.h> #include <asm/tlbflush.h> +#include <asm/page.h> /* undef for production */ #define HIGHMEM_DEBUG 1 @@ -41,8 +42,8 @@ extern void kmap_init(void) __init; * easily, subsequent pte tables have to be allocated in one physical * chunk of RAM. */ -#define PKMAP_BASE CONFIG_HIGHMEM_START -#define LAST_PKMAP 1024 +#define PKMAP_BASE CONFIG_HIGHMEM_START +#define LAST_PKMAP (1 << PTE_SHIFT) #define LAST_PKMAP_MASK (LAST_PKMAP-1) #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h index e13d0a0b1f45..3a893e9d6b47 100644 --- a/include/asm-ppc/processor.h +++ b/include/asm-ppc/processor.h @@ -848,6 +848,7 @@ struct thread_struct { /* AltiVec status */ vector128 vscr __attribute((aligned(16))); unsigned long vrsave; + int used_vr; /* set if process has used altivec */ #endif /* CONFIG_ALTIVEC */ }; diff --git a/include/asm-ppc/ucontext.h b/include/asm-ppc/ucontext.h index 14f1e78c041d..1d6e70c4306d 100644 --- a/include/asm-ppc/ucontext.h +++ b/include/asm-ppc/ucontext.h @@ -1,14 +1,28 @@ #ifndef _ASMPPC_UCONTEXT_H #define _ASMPPC_UCONTEXT_H -/* Copied from i386. */ +#include <asm/elf.h> +#include <asm/signal.h> + +struct mcontext { + elf_gregset_t mc_gregs; + elf_fpregset_t mc_fregs; + unsigned long mc_pad[2]; + elf_vrregset_t mc_vregs __attribute__((__aligned__(16))); +}; struct ucontext { - unsigned long uc_flags; - struct ucontext *uc_link; - stack_t uc_stack; - struct sigcontext uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + int uc_pad[7]; + struct mcontext *uc_regs; /* backward compat */ + sigset_t uc_oldsigmask; /* backward compat */ + int uc_pad2; + sigset_t uc_sigmask; + /* glibc has 1024-bit signal masks, ours are 64-bit */ + int uc_maskext[30]; + struct mcontext uc_mcontext; }; #endif /* !_ASMPPC_UCONTEXT_H */ |
