diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index 22f3b2fe61d6..1c2222048276 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -760,31 +760,6 @@ spinlock_exit(void) } } -int db_trap_glue(struct trapframe *); /* Called from trap_subr.S */ - -int -db_trap_glue(struct trapframe *frame) -{ - if (!(frame->srr1 & PSL_PR) - && (frame->exc == EXC_TRC || frame->exc == EXC_RUNMODETRC - || (frame->exc == EXC_PGM - && (frame->srr1 & 0x20000)) - || frame->exc == EXC_BPT - || frame->exc == EXC_DSI)) { - int type = frame->exc; - - /* Ignore DTrace traps. */ - if (*(uint32_t *)frame->srr0 == EXC_DTRACE) - return (0); - if (type == EXC_PGM && (frame->srr1 & 0x20000)) { - type = T_BREAKPOINT; - } - return (kdb_trap(type, 0, frame)); - } - - return (0); -} - #ifndef __powerpc64__ uint64_t diff --git a/sys/powerpc/booke/trap.c b/sys/powerpc/booke/trap.c deleted file mode 100644 index d1899efd8e7c..000000000000 --- a/sys/powerpc/booke/trap.c +++ /dev/null @@ -1,519 +0,0 @@ -/*- - * Copyright (C) 1995, 1996 Wolfgang Solfrank. - * Copyright (C) 1995, 1996 TooLs GmbH. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by TooLs GmbH. - * 4. The name of TooLs GmbH may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $ - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "opt_fpu_emu.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define FAULTBUF_LR 0 -#define FAULTBUF_R1 1 -#define FAULTBUF_R2 2 -#define FAULTBUF_CR 3 -#define FAULTBUF_CTR 4 -#define FAULTBUF_XER 5 -#define FAULTBUF_R13 6 - -static void trap_fatal(struct trapframe *frame); -static void printtrap(u_int vector, struct trapframe *frame, int isfatal, - int user); -static int trap_pfault(struct trapframe *frame, int user); -static int fix_unaligned(struct thread *td, struct trapframe *frame); -static int handle_onfault(struct trapframe *frame); -static void syscall(struct trapframe *frame); - -struct powerpc_exception { - u_int vector; - char *name; -}; - -static struct powerpc_exception powerpc_exceptions[] = { - { EXC_CRIT, "critical input" }, - { EXC_MCHK, "machine check" }, - { EXC_DSI, "data storage interrupt" }, - { EXC_ISI, "instruction storage interrupt" }, - { EXC_EXI, "external interrupt" }, - { EXC_ALI, "alignment" }, - { EXC_PGM, "program" }, - { EXC_SC, "system call" }, - { EXC_APU, "auxiliary proc unavailable" }, - { EXC_DECR, "decrementer" }, - { EXC_FIT, "fixed-interval timer" }, - { EXC_WDOG, "watchdog timer" }, - { EXC_DTMISS, "data tlb miss" }, - { EXC_ITMISS, "instruction tlb miss" }, - { EXC_DEBUG, "debug" }, - { EXC_PERF, "performance monitoring" }, - { EXC_LAST, NULL } -}; - -static const char * -trapname(u_int vector) -{ - struct powerpc_exception *pe; - - for (pe = powerpc_exceptions; pe->vector != EXC_LAST; pe++) { - if (pe->vector == vector) - return (pe->name); - } - - return ("unknown"); -} - -void -trap(struct trapframe *frame) -{ - struct thread *td; - struct proc *p; - int sig, type, user; - ksiginfo_t ksi; - -#ifdef KDB - if (kdb_active) { - kdb_reenter(); - return; - } -#endif - - PCPU_INC(cnt.v_trap); - - td = curthread; - p = td->td_proc; - - type = frame->exc; - sig = 0; - user = (frame->srr1 & PSL_PR) ? 1 : 0; - - CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm, - trapname(type), user ? "user" : "kernel"); - - if (user) { - td->td_frame = frame; - if (td->td_ucred != p->p_ucred) - cred_update_thread(td); - - /* User Mode Traps */ - switch (type) { - case EXC_DSI: - case EXC_ISI: - sig = trap_pfault(frame, 1); - break; - - case EXC_SC: - syscall(frame); - break; - - case EXC_ALI: - if (fix_unaligned(td, frame) != 0) - sig = SIGBUS; - else - frame->srr0 += 4; - break; - - case EXC_DEBUG: /* Single stepping */ - mtspr(SPR_DBSR, mfspr(SPR_DBSR)); - frame->srr1 &= ~PSL_DE; - frame->cpu.booke.dbcr0 &= ~(DBCR0_IDM || DBCR0_IC); - sig = SIGTRAP; - break; - - case EXC_PGM: /* Program exception */ - sig = ppc_instr_emulate(frame, td->td_pcb); - break; - - default: - trap_fatal(frame); - } - } else { - /* Kernel Mode Traps */ - KASSERT(cold || td->td_ucred != NULL, - ("kernel trap doesn't have ucred")); - - switch (type) { - case EXC_DEBUG: - mtspr(SPR_DBSR, mfspr(SPR_DBSR)); - kdb_trap(frame->exc, 0, frame); - return; - - case EXC_DSI: - if (trap_pfault(frame, 0) == 0) - return; - break; - - case EXC_MCHK: - if (handle_onfault(frame)) - return; - break; -#ifdef KDB - case EXC_PGM: - if (frame->cpu.booke.esr & ESR_PTR) - kdb_trap(EXC_PGM, 0, frame); - return; -#endif - default: - break; - } - trap_fatal(frame); - } - - if (sig != 0) { - if (p->p_sysent->sv_transtrap != NULL) - sig = (p->p_sysent->sv_transtrap)(sig, type); - ksiginfo_init_trap(&ksi); - ksi.ksi_signo = sig; - ksi.ksi_code = type; /* XXX, not POSIX */ - /* ksi.ksi_addr = ? */ - ksi.ksi_trapno = type; - trapsignal(td, &ksi); - } - - userret(td, frame); -} - -static void -trap_fatal(struct trapframe *frame) -{ - - printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); -#ifdef KDB - if ((debugger_on_panic || kdb_active) && - kdb_trap(frame->exc, 0, frame)) - return; -#endif - panic("%s trap", trapname(frame->exc)); -} - -static void -printtrap(u_int vector, struct trapframe *frame, int isfatal, int user) -{ - register_t va = 0; - - printf("\n"); - printf("%s %s trap:\n", isfatal ? "fatal" : "handled", - user ? "user" : "kernel"); - printf("\n"); - printf(" exception = 0x%x (%s)\n", vector, trapname(vector)); - - switch (vector) { - case EXC_DTMISS: - case EXC_DSI: - va = frame->dar; - break; - - case EXC_ITMISS: - case EXC_ISI: - va = frame->srr0; - break; - } - - printf(" virtual address = 0x%08x\n", va); - printf(" srr0 = 0x%08x\n", frame->srr0); - printf(" srr1 = 0x%08x\n", frame->srr1); - printf(" curthread = %p\n", curthread); - if (curthread != NULL) - printf(" pid = %d, comm = %s\n", - curthread->td_proc->p_pid, curthread->td_proc->p_comm); - printf("\n"); -} - -/* - * Handles a fatal fault when we have onfault state to recover. Returns - * non-zero if there was onfault recovery state available. - */ -static int -handle_onfault(struct trapframe *frame) -{ - struct thread *td; - faultbuf *fb; - - td = curthread; - fb = td->td_pcb->pcb_onfault; - if (fb != NULL) { - frame->srr0 = (*fb)[FAULTBUF_LR]; - frame->fixreg[1] = (*fb)[FAULTBUF_R1]; - frame->fixreg[2] = (*fb)[FAULTBUF_R2]; - frame->fixreg[3] = 1; - frame->cr = (*fb)[FAULTBUF_CR]; - frame->ctr = (*fb)[FAULTBUF_CTR]; - frame->xer = (*fb)[FAULTBUF_XER]; - bcopy(&(*fb)[FAULTBUF_R13], &frame->fixreg[13], - 19 * sizeof(register_t)); - return (1); - } - return (0); -} - -int -cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) -{ - struct proc *p; - struct trapframe *frame; - caddr_t params; - int error, n; - - p = td->td_proc; - frame = td->td_frame; - - sa->code = frame->fixreg[0]; - params = (caddr_t)(frame->fixreg + FIRSTARG); - n = NARGREG; - - if (sa->code == SYS_syscall) { - /* - * code is first argument, - * followed by actual args. - */ - sa->code = *(u_int *) params; - params += sizeof(register_t); - n -= 1; - } else if (sa->code == SYS___syscall) { - /* - * Like syscall, but code is a quad, - * so as to maintain quad alignment - * for the rest of the args. - */ - params += sizeof(register_t); - sa->code = *(u_int *) params; - params += sizeof(register_t); - n -= 2; - } - - if (p->p_sysent->sv_mask) - sa->code &= p->p_sysent->sv_mask; - if (sa->code >= p->p_sysent->sv_size) - sa->callp = &p->p_sysent->sv_table[0]; - else - sa->callp = &p->p_sysent->sv_table[sa->code]; - sa->narg = sa->callp->sy_narg; - - bcopy(params, sa->args, n * sizeof(register_t)); - if (sa->narg > n) { - error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n, - (sa->narg - n) * sizeof(register_t)); - } else - error = 0; - - if (error == 0) { - td->td_retval[0] = 0; - td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; - } - return (error); -} - -#include "../../kern/subr_syscall.c" - -void -syscall(struct trapframe *frame) -{ - struct thread *td; - struct syscall_args sa; - int error; - - td = curthread; - td->td_frame = frame; - - error = syscallenter(td, &sa); - syscallret(td, error, &sa); -} - -static int -trap_pfault(struct trapframe *frame, int user) -{ - vm_offset_t eva, va; - struct thread *td; - struct proc *p; - vm_map_t map; - vm_prot_t ftype; - int rv; - - td = curthread; - p = td->td_proc; - - if (frame->exc == EXC_ISI) { - eva = frame->srr0; - ftype = VM_PROT_READ | VM_PROT_EXECUTE; - - } else { - eva = frame->dar; - if (frame->cpu.booke.esr & ESR_ST) - ftype = VM_PROT_WRITE; - else - ftype = VM_PROT_READ; - } - - if (user) { - KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace NULL")); - map = &p->p_vmspace->vm_map; - } else { - if (eva < VM_MAXUSER_ADDRESS) { - - if (p->p_vmspace == NULL) - return (SIGSEGV); - - map = &p->p_vmspace->vm_map; - - } else { - map = kernel_map; - } - } - va = trunc_page(eva); - - if (map != kernel_map) { - /* - * Keep swapout from messing with us during this - * critical time. - */ - PROC_LOCK(p); - ++p->p_lock; - PROC_UNLOCK(p); - - /* Fault in the user page: */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - - PROC_LOCK(p); - --p->p_lock; - PROC_UNLOCK(p); - } else { - /* - * Don't have to worry about process locking or stacks in the - * kernel. - */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - } - - if (rv == KERN_SUCCESS) - return (0); - - if (!user && handle_onfault(frame)) - return (0); - - return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); -} - -/* - * For now, this only deals with the particular unaligned access case - * that gcc tends to generate. Eventually it should handle all of the - * possibilities that can happen on a 32-bit PowerPC in big-endian mode. - */ - -static int -fix_unaligned(struct thread *td, struct trapframe *frame) -{ -#if 0 - struct thread *fputhread; - int indicator, reg; - double *fpr; - - indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); - - switch (indicator) { - case EXC_ALI_LFD: - case EXC_ALI_STFD: - reg = EXC_ALI_RST(frame->dsisr); - fpr = &td->td_pcb->pcb_fpu.fpr[reg]; - fputhread = PCPU_GET(fputhread); - /* Juggle the FPU to ensure that we've initialized - * the FPRs, and that their current state is in - * the PCB. - */ - if (fputhread != td) { - if (fputhread) - save_fpu(fputhread); - enable_fpu(td); - } - save_fpu(td); - - if (indicator == EXC_ALI_LFD) { - if (copyin((void *)frame->dar, fpr, - sizeof(double)) != 0) - return -1; - enable_fpu(td); - } else { - if (copyout(fpr, (void *)frame->dar, - sizeof(double)) != 0) - return -1; - } - return 0; - break; - } - -#endif - return (-1); -} - -#ifdef KDB -int db_trap_glue(struct trapframe *); -int -db_trap_glue(struct trapframe *tf) -{ - if (!(tf->srr1 & PSL_PR)) - return (kdb_trap(tf->exc, 0, tf)); - return (0); -} -#endif diff --git a/sys/powerpc/aim/trap.c b/sys/powerpc/powerpc/trap.c similarity index 86% rename from sys/powerpc/aim/trap.c rename to sys/powerpc/powerpc/trap.c index e0e2fe630159..7991a7059d10 100644 --- a/sys/powerpc/aim/trap.c +++ b/sys/powerpc/powerpc/trap.c @@ -74,6 +74,12 @@ __FBSDID("$FreeBSD$"); #include #include +#define FAULTBUF_LR 0 +#define FAULTBUF_R1 1 +#define FAULTBUF_R2 2 +#define FAULTBUF_CR 3 +#define FAULTBUF_R13 6 + static void trap_fatal(struct trapframe *frame); static void printtrap(u_int vector, struct trapframe *frame, int isfatal, int user); @@ -100,32 +106,37 @@ int (*dtrace_invop_jump_addr)(struct trapframe *); #endif static struct powerpc_exception powerpc_exceptions[] = { - { 0x0100, "system reset" }, - { 0x0200, "machine check" }, - { 0x0300, "data storage interrupt" }, - { 0x0380, "data segment exception" }, - { 0x0400, "instruction storage interrupt" }, - { 0x0480, "instruction segment exception" }, - { 0x0500, "external interrupt" }, - { 0x0600, "alignment" }, - { 0x0700, "program" }, - { 0x0800, "floating-point unavailable" }, - { 0x0900, "decrementer" }, - { 0x0c00, "system call" }, - { 0x0d00, "trace" }, - { 0x0e00, "floating-point assist" }, - { 0x0f00, "performance monitoring" }, - { 0x0f20, "altivec unavailable" }, - { 0x0f40, "vsx unavailable" }, - { 0x1000, "instruction tlb miss" }, - { 0x1100, "data load tlb miss" }, - { 0x1200, "data store tlb miss" }, - { 0x1300, "instruction breakpoint" }, - { 0x1400, "system management" }, - { 0x1600, "altivec assist" }, - { 0x1700, "thermal management" }, - { 0x2000, "run mode/trace" }, - { 0x3000, NULL } + { EXC_CRIT, "critical input" }, + { EXC_RST, "system reset" }, + { EXC_MCHK, "machine check" }, + { EXC_DSI, "data storage interrupt" }, + { EXC_DSE, "data segment exception" }, + { EXC_ISI, "instruction storage interrupt" }, + { EXC_ISE, "instruction segment exception" }, + { EXC_EXI, "external interrupt" }, + { EXC_ALI, "alignment" }, + { EXC_PGM, "program" }, + { EXC_FPU, "floating-point unavailable" }, + { EXC_APU, "auxiliary proc unavailable" }, + { EXC_DECR, "decrementer" }, + { EXC_FIT, "fixed-interval timer" }, + { EXC_WDOG, "watchdog timer" }, + { EXC_SC, "system call" }, + { EXC_TRC, "trace" }, + { EXC_FPA, "floating-point assist" }, + { EXC_DEBUG, "debug" }, + { EXC_PERF, "performance monitoring" }, + { EXC_VEC, "altivec unavailable" }, + { EXC_VSX, "vsx unavailable" }, + { EXC_ITMISS, "instruction tlb miss" }, + { EXC_DLMISS, "data load tlb miss" }, + { EXC_DSMISS, "data store tlb miss" }, + { EXC_BPT, "instruction breakpoint" }, + { EXC_SMI, "system management" }, + { EXC_VECAST_G4, "altivec assist" }, + { EXC_THRM, "thermal management" }, + { EXC_RUNMODETRC, "run mode/trace" }, + { EXC_LAST, NULL } }; static const char * @@ -133,7 +144,7 @@ trapname(u_int vector) { struct powerpc_exception *pe; - for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) { + for (pe = powerpc_exceptions; pe->vector != EXC_LAST; pe++) { if (pe->vector == vector) return (pe->name); } @@ -265,9 +276,21 @@ trap(struct trapframe *frame) frame->srr0 += 4; break; + case EXC_DEBUG: /* Single stepping */ + mtspr(SPR_DBSR, mfspr(SPR_DBSR)); + frame->srr1 &= ~PSL_DE; + frame->cpu.booke.dbcr0 &= ~(DBCR0_IDM || DBCR0_IC); + sig = SIGTRAP; + ucode = TRAP_TRACE; + break; + case EXC_PGM: /* Identify the trap reason */ +#ifdef AIM if (frame->srr1 & EXC_PGM_TRAP) { +#else + if (frame->cpu.booke.esr & ESR_PTR) { +#endif #ifdef KDTRACE_HOOKS inst = fuword32((const void *)frame->srr0); if (inst == 0x0FFFDDDD && @@ -384,12 +407,14 @@ printtrap(u_int vector, struct trapframe *frame, int isfatal, int user) printf("\n"); printf(" exception = 0x%x (%s)\n", vector, trapname(vector)); switch (vector) { + case EXC_DTMISS: case EXC_DSE: case EXC_DSI: printf(" virtual address = 0x%" PRIxPTR "\n", frame->dar); printf(" dsisr = 0x%" PRIxPTR "\n", frame->cpu.aim.dsisr); break; + case EXC_ITMISS: case EXC_ISE: case EXC_ISI: printf(" virtual address = 0x%" PRIxPTR "\n", frame->srr0); @@ -418,12 +443,12 @@ handle_onfault(struct trapframe *frame) td = curthread; fb = td->td_pcb->pcb_onfault; if (fb != NULL) { - frame->srr0 = (*fb)[0]; - frame->fixreg[1] = (*fb)[1]; - frame->fixreg[2] = (*fb)[2]; + frame->srr0 = (*fb)[FAULTBUF_LR]; + frame->fixreg[1] = (*fb)[FAULTBUF_R1]; + frame->fixreg[2] = (*fb)[FAULTBUF_R2]; frame->fixreg[3] = 1; - frame->cr = (*fb)[3]; - bcopy(&(*fb)[4], &frame->fixreg[13], + frame->cr = (*fb)[FAULTBUF_CR]; + bcopy(&(*fb)[FAULTBUF_R13], &frame->fixreg[13], 19 * sizeof(register_t)); return (1); } @@ -630,7 +655,9 @@ trap_pfault(struct trapframe *frame, int user) vm_map_t map; vm_prot_t ftype; int rv; +#ifdef AIM register_t user_sr; +#endif td = curthread; p = td->td_proc; @@ -641,24 +668,35 @@ trap_pfault(struct trapframe *frame, int user) ftype |= VM_PROT_READ; } else { eva = frame->dar; +#ifdef BOOKE + if (frame->cpu.booke.esr & ESR_ST) +#else if (frame->cpu.aim.dsisr & DSISR_STORE) +#endif ftype = VM_PROT_WRITE; else ftype = VM_PROT_READ; } if (user) { + KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace NULL")); map = &p->p_vmspace->vm_map; } else { +#ifdef BOOKE + if (eva < VM_MAXUSER_ADDRESS) { +#else if ((eva >> ADDR_SR_SHFT) == (USER_ADDR >> ADDR_SR_SHFT)) { +#endif if (p->p_vmspace == NULL) return (SIGSEGV); map = &p->p_vmspace->vm_map; +#ifdef AIM user_sr = td->td_pcb->pcb_cpu.aim.usr_segm; eva &= ADDR_PIDX | ADDR_POFF; eva |= user_sr << ADDR_SR_SHFT; +#endif } else { map = kernel_map; } @@ -736,17 +774,43 @@ fix_unaligned(struct thread *td, struct trapframe *frame) if (indicator == EXC_ALI_LFD) { if (copyin((void *)frame->dar, fpr, sizeof(double)) != 0) - return -1; + return (-1); enable_fpu(td); } else { if (copyout(fpr, (void *)frame->dar, sizeof(double)) != 0) - return -1; + return (-1); } - return 0; + return (0); break; } - return -1; + return (-1); } +#ifdef KDB +int db_trap_glue(struct trapframe *); /* Called from trap_subr.S */ + +int +db_trap_glue(struct trapframe *frame) +{ + if (!(frame->srr1 & PSL_PR) + && (frame->exc == EXC_TRC || frame->exc == EXC_RUNMODETRC + || (frame->exc == EXC_PGM + && (frame->srr1 & 0x20000)) + || frame->exc == EXC_BPT + || frame->exc == EXC_DSI)) { + int type = frame->exc; + + /* Ignore DTrace traps. */ + if (*(uint32_t *)frame->srr0 == EXC_DTRACE) + return (0); + if (type == EXC_PGM && (frame->srr1 & 0x20000)) { + type = T_BREAKPOINT; + } + return (kdb_trap(type, 0, frame)); + } + + return (0); +} +#endif