diff --git a/sys/arch/mips/mips/trap.c b/sys/arch/mips/mips/trap.c index b86ccecbf586..b1022196fcc6 100644 --- a/sys/arch/mips/mips/trap.c +++ b/sys/arch/mips/mips/trap.c @@ -1,4 +1,4 @@ -/* $NetBSD: trap.c,v 1.56 1997/06/15 01:08:19 jonathan Exp $ */ +/* $NetBSD: trap.c,v 1.57 1997/06/15 17:49:53 mhitch Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -41,9 +41,10 @@ * * @(#)trap.c 8.5 (Berkeley) 1/11/94 */ +#define MINIDEBUG 1 #if !defined(MIPS1) && !defined(MIPS3) -#error Neither "MIPS1" (r2000 family), "MIP3" (r4000 family) was configured. +#error Neither "MIPS1" (r2000 family), "MIPS3" (r4000 family) was configured. #endif #include @@ -58,9 +59,6 @@ #ifdef KTRACE #include #endif -#include - -#include #include #include @@ -93,44 +91,43 @@ #include /* pppintr() prototype */ #endif - -struct proc *machFPCurProcPtr; /* pointer to last proc to use FP */ - /* * Port-specific hardware interrupt handler */ -int (*mips_hardware_intr) __P((u_int mask, u_int pc, u_int status, - u_int cause)) = - ( int (*) __P((u_int, u_int, u_int, u_int)) ) 0; +int (*mips_hardware_intr) __P((unsigned mask, unsigned pc, unsigned status, + unsigned cause)) = + ( int (*) __P((unsigned, unsigned, unsigned, unsigned)) ) 0; /* - * Exception-handling functions, called via machExceptionTable from locore + * Exception-handling functions, called via ExceptionTable from locore */ -extern void MachTLBModException __P((void)); -extern void MachTLBMissException __P((void)); - extern void mips1_KernGenException __P((void)); extern void mips1_UserGenException __P((void)); +extern void mips1_TLBMissException __P((void)); +extern void mips1_SystemCall __P((void)); extern void mips1_KernIntr __P((void)); extern void mips1_UserIntr __P((void)); -extern void mips1_TLBModException __P((void)); - -extern void mips1_TLBMissException __P((void)); /* marks end of vector code */ extern void mips1_UTLBMiss __P((void)); extern void mips1_exceptionentry_end __P((void)); +#ifdef MIPS3 extern void mips3_KernGenException __P((void)); extern void mips3_UserGenException __P((void)); +extern void mips3_SystemCall __P((void)); extern void mips3_KernIntr __P((void)); extern void mips3_UserIntr __P((void)); extern void mips3_TLBModException __P((void)); extern void mips3_TLBMissException __P((void)); +extern void mips3_TLBInvalidException __P((void)); +extern void mips3_VCED __P((void)); +extern void mips3_VCEI __P((void)); /* marks end of vector code */ extern void mips3_TLBMiss __P((void)); extern void mips3_exceptionentry_end __P((void)); +#endif void (*mips1_ExceptionTable[]) __P((void)) = { @@ -180,7 +177,7 @@ void (*mips1_ExceptionTable[]) __P((void)) = { mips1_UserGenException, /* 5 */ mips1_UserGenException, /* 6 */ mips1_UserGenException, /* 7 */ - mips1_UserGenException, /* 8 */ + mips1_SystemCall, /* 8 */ mips1_UserGenException, /* 9 */ mips1_UserGenException, /* 10 */ mips1_UserGenException, /* 11 */ @@ -214,8 +211,8 @@ void (*mips3_ExceptionTable[]) __P((void)) = { */ mips3_KernIntr, /* 0 external interrupt */ mips3_KernGenException, /* 1 TLB modification */ - mips3_TLBMissException, /* 2 TLB miss (load or instr. fetch) */ - mips3_TLBMissException, /* 3 TLB miss (store) */ + mips3_TLBInvalidException, /* 2 TLB miss (load or instr. fetch) */ + mips3_TLBInvalidException, /* 3 TLB miss (store) */ mips3_KernGenException, /* 4 address error (load or I-fetch) */ mips3_KernGenException, /* 5 address error (store) */ mips3_KernGenException, /* 6 bus error (I-fetch) */ @@ -226,7 +223,7 @@ void (*mips3_ExceptionTable[]) __P((void)) = { mips3_KernGenException, /* 11 coprocessor unusable */ mips3_KernGenException, /* 12 arithmetic overflow */ mips3_KernGenException, /* 13 r4k trap excpt, r3k reserved */ - mips3_KernGenException, /* 14 r4k virt coherence, r3k reserved */ + mips3_VCEI, /* 14 r4k virt coherence, r3k reserved */ mips3_KernGenException, /* 15 r4k FP exception, r3k reserved */ mips3_KernGenException, /* 16 reserved */ mips3_KernGenException, /* 17 reserved */ @@ -243,7 +240,7 @@ void (*mips3_ExceptionTable[]) __P((void)) = { mips3_KernGenException, /* 28 reserved */ mips3_KernGenException, /* 29 reserved */ mips3_KernGenException, /* 30 reserved */ - mips3_KernGenException, /* 31 virt. coherence exception data */ + mips3_VCED, /* 31 virt. coherence exception data */ /* * The user exception handlers. */ @@ -255,13 +252,13 @@ void (*mips3_ExceptionTable[]) __P((void)) = { mips3_UserGenException, /* 5 */ mips3_UserGenException, /* 6 */ mips3_UserGenException, /* 7 */ - mips3_UserGenException, /* 8 */ + mips3_SystemCall, /* 8 */ mips3_UserGenException, /* 9 */ mips3_UserGenException, /* 10 */ mips3_UserGenException, /* 11 */ mips3_UserGenException, /* 12 */ mips3_UserGenException, /* 13 */ - mips3_UserGenException, /* 14 */ + mips3_VCEI, /* 14 */ mips3_UserGenException, /* 15 */ mips3_UserGenException, /* 16 */ mips3_UserGenException, /* 17 */ @@ -278,7 +275,7 @@ void (*mips3_ExceptionTable[]) __P((void)) = { mips3_UserGenException, /* 28 */ mips3_UserGenException, /* 29 */ mips3_UserGenException, /* 20 */ - mips3_UserGenException, /* 31 */ + mips3_VCED, /* 31 virt. coherence exception data */ }; #endif /* MIPS3 */ @@ -317,6 +314,7 @@ char *trap_type[] = { "reserved 30", "r4000 virtual coherency data", }; +extern unsigned intrcnt[]; #ifdef DEBUG #define TRAPSIZE 10 @@ -331,34 +329,44 @@ struct trapdebug { /* trap history buffer for debugging */ } trapdebug[TRAPSIZE], *trp = trapdebug; void trapDump __P((char * msg)); -void cpu_getregs __P((int *regs)); #endif /* DEBUG */ + +#ifdef MINIDEBUG +void mips_dump_tlb __P((int, int)); +void mdbpanic __P((void)); +#endif + /* * Other forward declarations. */ -u_int MachEmulateBranch __P((unsigned *regsPtr, +unsigned MachEmulateBranch __P((unsigned *regsPtr, unsigned instPC, unsigned fpcCSR, int allowNonBranch)); +struct proc *fpcurproc; + /* extern functions used but not declared elsewhere */ -extern void MachFPInterrupt __P((u_int status, u_int cause, u_int pc)); extern void clearsoftclock __P((void)); extern void clearsoftnet __P((void)); -extern int splx __P((int)); -extern int splhigh __P((void)); -extern void MachSwitchFPState __P((struct proc *from, struct user *to)); +extern void MachFPInterrupt __P((unsigned, unsigned, unsigned, int *)); +extern void switchfpregs __P((struct proc *, struct proc *)); /* only called by locore */ -extern u_int trap __P((u_int status, u_int cause, u_int vaddr, u_int pc, - int args)); -extern void interrupt __P((u_int status, u_int cause, u_int pc)); -extern void softintr __P((unsigned statusReg, unsigned pc)); - +extern void trap __P((u_int status, u_int cause, u_int vaddr, u_int opc, + struct frame frame)); +static void userret __P((struct proc *p, unsigned pc, u_quad_t sticks)); +extern void syscall __P((unsigned status, unsigned cause, unsigned opc, + struct frame *frame)); +extern void child_return __P((struct proc *p)); +extern void interrupt __P((unsigned status, unsigned cause, unsigned pc, + struct frame *frame)); +extern void ast __P((unsigned pc)); #ifdef DEBUG /* stack trace code, also useful to DDB one day */ int kdbpeek __P((vm_offset_t addr)); +extern void cpu_getregs __P((int *)); extern void stacktrace __P((void)); /*XXX*/ extern void logstacktrace __P((void)); /*XXX*/ @@ -369,212 +377,436 @@ extern void MachUTLBMiss __P((void)); extern void setsoftclock __P((void)); extern int main __P((void*)); extern void am7990_meminit __P((void*)); /* XXX */ +extern void savectx __P((struct user *)); #endif /* DEBUG */ -extern volatile struct chiptime *Mach_clock_addr; -extern u_long kernelfaults; -u_long kernelfaults = 0; -extern u_long intrcnt[]; +#ifdef MINIDEBUG +extern long mdbpeek __P((caddr_t addr)); +extern void mdbpoke __P((caddr_t addr, long value)); +extern int cngetc __P((void)); +extern void cnputc __P((int)); +extern int gethex __P((unsigned *val, unsigned dotval)); +extern void dump __P((unsigned *addr, unsigned size)); +extern void print_regs __P((struct frame *frame)); +extern void set_break __P((u_int va)); +extern void del_break __P((u_int va)); +extern void break_insert __P((void)); +extern void break_restore __P((void)); +extern int break_find __P((u_int va)); +extern void prt_break __P((void)); +extern void mdbsetsstep __P((struct frame *frame)); +extern int mdbclrsstep __P((struct frame *frame)); +extern int mdbprintins __P((int ins, int mdbdot)); +extern int mdb __P((int type, struct frame *frame)); +#endif /* * Index into intrcnt[], which is defined in locore */ typedef enum { - SOFTCLOCK_INTR =0, - SOFTNET_INTR =1, - SERIAL0_INTR=2, - SERIAL1_INTR = 3, - SERIAL2_INTR = 4, - LANCE_INTR =5, - SCSI_INTR = 6, - ERROR_INTR=7, - HARDCLOCK = 8, - FPU_INTR =9, - SLOT0_INTR =10, - SLOT1_INTR =11, - SLOT2_INTR =12, - DTOP_INTR = 13, /* XXX */ - ISDN_INTR = 14, /* XXX */ - FLOPPY_INTR = 15, - STRAY_INTR = 16 + SOFTCLOCK_INTR = 0, + SOFTNET_INTR, + SERIAL0_INTR, + SERIAL1_INTR, + SERIAL2_INTR, + LANCE_INTR, + SCSI_INTR, + ERROR_INTR, + HARDCLOCK, + FPU_INTR, + SLOT0_INTR, + SLOT1_INTR, + SLOT2_INTR, + DTOP_INTR, + ISDN_INTR, + FLOPPY_INTR, + STRAY_INTR } decstation_intr_t; - -/* - * Handle an exception. - * Called from MachKernGenException() or MachUserGenException() - * when a processor trap occurs. - * In the case of a kernel trap, we return the pc where to resume if - * ((struct pcb *)UADDR)->pcb_onfault is set, otherwise, return old pc. - */ -u_int -trap(statusReg, causeReg, vadr, pc, args) - unsigned statusReg; /* status register at time of the exception */ - unsigned causeReg; /* cause register at time of exception */ - unsigned vadr; /* address (if any) the fault occured on */ - unsigned pc; /* program counter where to continue */ -{ - register int type, i; - unsigned ucode = 0; - register struct proc *p = curproc; +static void +userret(p, pc, sticks) + struct proc *p; + unsigned pc; u_quad_t sticks; - vm_prot_t ftype; - extern unsigned onfault_table[]; +{ + int sig; + + /* take pending signals */ + while ((sig = CURSIG(p)) != 0) + postsig(sig); + p->p_priority = p->p_usrpri; + if (want_resched) { + int s; + /* + * Since we are curproc, a clock interrupt could + * change our priority without changing run queues + * (the running process is not kept on a run queue). + * If this happened after we setrunqueue ourselves but + * before we switch()'ed, we might not be on the queue + * indicated by our priority. + */ + s = splstatclock(); + setrunqueue(p); + p->p_stats->p_ru.ru_nivcsw++; + mi_switch(); + splx(s); + while ((sig = CURSIG(p)) != 0) + postsig(sig); + } + /* + * If profiling, charge system time to the trapped pc. + */ + if (p->p_flag & P_PROFIL) { + extern int psratio; + + addupc_task(p, pc, (int)(p->p_sticks - sticks) * psratio); + } + curpriority = p->p_priority; +} + +#define DELAYBRANCH(x) ((x)<0) +/* + * Process a system call. + * + * System calls are strange beasts. They are passed the syscall number + * in v0, and the arguments in the registers (as normal). They return + * an error flag in a3 (if a3 != 0 on return, the syscall had an error), + * and the return value (if any) in v0 and possibly v1. + */ +void +syscall(status, cause, opc, frame) + unsigned status, cause, opc; + struct frame *frame; +{ + struct proc *p = curproc; + u_quad_t sticks; + int args[8], rval[2], error; + size_t code, numsys, nsaved, argsiz; + struct sysent *callp; #ifdef DEBUG - trp->status = statusReg; - trp->cause = causeReg; - trp->vadr = vadr; - trp->pc = pc; - trp->ra = !USERMODE(statusReg) ? ((int *)&args)[19] : - p->p_md.md_regs[RA]; - trp->sp = (int)&args; + trp->status = status; + trp->cause = cause; + trp->vadr = 0; + trp->pc = opc; + trp->ra = frame->f_regs[RA]; + trp->sp = frame->f_regs[SP]; trp->code = 0; if (++trp == &trapdebug[TRAPSIZE]) trp = trapdebug; #endif + cnt.v_syscall++; + +#ifdef MIPS3 + if (status & MIPS_SR_INT_IE) +#else + if (status & MIPS_3K_SR_INT_ENA_PREV) +#endif + splx(MIPS_SR_INT_IE | (status & MACH_HARD_INT_MASK)); + + sticks = p->p_sticks; + if (DELAYBRANCH(cause)) + frame->f_regs[PC] = MachEmulateBranch(frame->f_regs, opc, 0, 0); + else + frame->f_regs[PC] = opc + sizeof(int); + callp = p->p_emul->e_sysent; + numsys = p->p_emul->e_nsysent; + code = frame->f_regs[V0]; + switch (code) { + case SYS_syscall: + /* + * Code is first argument, followed by actual args. + */ + code = frame->f_regs[A0]; + args[0] = frame->f_regs[A1]; + args[1] = frame->f_regs[A2]; + args[2] = frame->f_regs[A3]; + nsaved = 3; + break; + case SYS___syscall: + /* + * Like syscall, but code is a quad, so as to maintain + * quad alignment for the rest of the arguments. + */ + code = frame->f_regs[A0 + _QUAD_LOWWORD]; + args[0] = frame->f_regs[A2]; + args[1] = frame->f_regs[A3]; + nsaved = 2; + break; + default: + args[0] = frame->f_regs[A0]; + args[1] = frame->f_regs[A1]; + args[2] = frame->f_regs[A2]; + args[3] = frame->f_regs[A3]; + nsaved = 4; + break; + } + if (code >= p->p_emul->e_nsysent) + callp += p->p_emul->e_nosys; + else + callp += code; + argsiz = callp->sy_argsize / sizeof(int); + if (argsiz > nsaved) { + error = copyin( + (caddr_t)((int *)frame->f_regs[SP] + 4), + (caddr_t)(args + nsaved), + (argsiz - nsaved) * sizeof(int)); + if (error) + goto bad; + } +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_argsize, args); +#endif + rval[0] = 0; + rval[1] = frame->f_regs[V1]; +#ifdef DEBUG +/* XXX save code */ +#endif + error = (*callp->sy_call)(p, args, rval); + +#ifdef DEBUG +/* XXX save syscall result in trapdebug */ +#endif + switch (error) { + case 0: + frame->f_regs[V0] = rval[0]; + frame->f_regs[V1] = rval[1]; + frame->f_regs[A3] = 0; + break; + case ERESTART: + frame->f_regs[PC] = opc; + break; + case EJUSTRETURN: + break; /* nothing to do */ + default: + bad: + frame->f_regs[V0] = error; + frame->f_regs[A3] = 1; + break; + } +#ifdef SYSCALL_DEBUG + scdebug_ret(p, code, error, rval); +#endif + userret(p, opc, sticks); +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, code, error, rval[0]); +#endif +} + +/* + * fork syscall returns directly to user process via proc_trampoline, + * which will be called the very first time when child gets running. + * no more FORK_BRAINDAMAGED. + */ +void +child_return(p) + struct proc *p; +{ + struct frame *frame = (struct frame *)p->p_md.md_regs; + + frame->f_regs[V0] = 0; + frame->f_regs[V1] = 1; + frame->f_regs[A3] = 0; + userret(p, frame->f_regs[PC] - sizeof(int), 0); /* XXX */ +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, SYS_fork, 0, 0); +#endif +} + +#ifdef MIPS3 +#define TRAPTYPE(x) (((x) & MIPS_4K_CR_EXC_CODE) >> MACH_CR_EXC_CODE_SHIFT) +#else +#define TRAPTYPE(x) (((x) & MIPS_3K_CR_EXC_CODE) >> MACH_CR_EXC_CODE_SHIFT) +#endif +#define KERNLAND(x) ((int)(x) < 0) + +/* + * Trap is called from locore to handle most types of processor traps. + * System calls are broken out for efficiency. MIPS can handle software + * interrupts as a part of real interrupt processing. + */ +void +trap(status, cause, vaddr, opc, frame) + u_int status; + u_int cause; + u_int vaddr; + u_int opc; + struct frame frame; +{ + int type, sig; + int ucode = 0; + u_quad_t sticks = 0; + struct proc *p = curproc; + vm_prot_t ftype; + extern void fswintrberr __P((void)); + +#ifdef DEBUG + trp->status = status; + trp->cause = cause; + trp->vadr = vaddr; + trp->pc = opc; + trp->ra = !USERMODE(status) ? frame.f_regs[RA] : p->p_md.md_regs[RA]; + trp->sp = (int)&frame; + trp->code = 0; + if (++trp == &trapdebug[TRAPSIZE]) + trp = trapdebug; +#endif cnt.v_trap++; - type = (causeReg & MIPS_3K_CR_EXC_CODE) >> MACH_CR_EXC_CODE_SHIFT; - if (USERMODE(statusReg)) { + type = TRAPTYPE(cause); + if (USERMODE(status)) { type |= T_USER; sticks = p->p_sticks; } - /* - * Enable hardware interrupts if they were on before. - * We only respond to software interrupts when returning to user mode. - */ - if (statusReg & MIPS_3K_SR_INT_ENA_PREV) - splx((statusReg & MACH_HARD_INT_MASK) | MIPS_SR_INT_IE); +#ifdef MIPS3 + if (status & MIPS_SR_INT_IE) +#else + if (status & MIPS_3K_SR_INT_ENA_PREV) +#endif + splx((status & MACH_HARD_INT_MASK) | MIPS_SR_INT_IE); switch (type) { - case T_TLB_MOD: - /* check for kernel address */ - if ((int)vadr < 0) { - register pt_entry_t *pte; - register unsigned entry; - register vm_offset_t pa; - - pte = kvtopte(vadr); - entry = pte->pt_entry; -#ifdef DIAGNOSTIC - if (!(entry & PG_V) || (entry & PG_M)) - panic("trap: ktlbmod: invalid pte"); + default: + dopanic: + type &= ~T_USER; + if (type >= 0 && type < 32) + printf("trap: %s", trap_type[type]); + else + printf("trap: unknown %d", type); + printf(" in %s mode\n", USERMODE(status) ? "user" : "kernel"); + printf("status=0x%x, cause=0x%x, pc=0x%x, v=0x%x\n", + status, cause, opc, vaddr); + printf("usp=0x%x ksp=%p\n", p->p_md.md_regs[SP], (int*)&frame); + if (curproc != NULL) + printf("pid=%d cmd=%s\n", p->p_pid, p->p_comm); + else + printf("curproc == NULL\n"); +#ifdef MINIDEBUG + frame.f_regs[CAUSE] = cause; + frame.f_regs[BADVADDR] = vaddr; + mdb(type, (struct frame *)&frame.f_regs); +#else +#ifdef DEBUG + stacktrace(); + trapDump("trap"); #endif - if (PAGE_IS_RDONLY(entry, vadr)) { +#endif + panic("trap"); + /*NOTREACHED*/ + case T_TLB_MOD: + if (KERNLAND(vaddr)) { + pt_entry_t *pte; + unsigned entry; + vm_offset_t pa; + + pte = kvtopte(vaddr); + entry = pte->pt_entry; + if (!(entry & PG_V) || (entry & PG_M)) { + mdb(type, (struct frame *)&frame.f_regs); + panic("ktlbmod: invalid pte"); + } +/*XXX MIPS3? */ if (entry & PG_RO) { /* write to read only page in the kernel */ ftype = VM_PROT_WRITE; - goto kernel_fault; + goto kernelfault; } entry |= PG_M; pte->pt_entry = entry; - vadr &= ~PGOFSET; - MachTLBUpdate(vadr, entry); - pa = PTE_TO_PADDR(entry); + vaddr &= ~PGOFSET; + MachTLBUpdate(vaddr, entry); + pa = pfn_to_vad(entry); #ifdef ATTR pmap_attributes[atop(pa)] |= PMAP_ATTR_MOD; #else if (!IS_VM_PHYSADDR(pa)) - panic("trap: ktlbmod: unmanaged page"); + panic("ktlbmod: unmanaged page"); PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN; #endif - return (pc); + return; /* KERN */ } - /* FALLTHROUGH */ - + /*FALLTHROUGH*/ case T_TLB_MOD+T_USER: { - register pt_entry_t *pte; - register unsigned entry; - register vm_offset_t pa; - pmap_t pmap = p->p_vmspace->vm_map.pmap; + pt_entry_t *pte; + unsigned entry; + vm_offset_t pa; + pmap_t pmap; - if (!(pte = pmap_segmap(pmap, vadr))) - panic("trap: utlbmod: invalid segmap"); - pte += (vadr >> PGSHIFT) & (NPTEPG - 1); + pmap = p->p_vmspace->vm_map.pmap; + if (!(pte = pmap_segmap(pmap, vaddr))) + panic("utlbmod: invalid segmap"); + pte += (vaddr >> PGSHIFT) & (NPTEPG - 1); entry = pte->pt_entry; -#ifdef DIAGNOSTIC - if (!(entry & PG_V) || (entry & PG_M)) { - panic("trap: utlbmod: invalid pte"); - } -#endif - if (PAGE_IS_RDONLY(entry, vadr)) { + if (!(entry & PG_V) || (entry & PG_M)) + panic("utlbmod: invalid pte"); + +/*XXX MIPS3? */ if (entry & PG_RO) { /* write to read only page */ ftype = VM_PROT_WRITE; - goto dofault; + goto pagefault; } entry |= PG_M; pte->pt_entry = entry; - vadr = (vadr & ~PGOFSET) | + vaddr = (vaddr & ~PGOFSET) | (pmap->pm_tlbpid << VMMACH_TLB_PID_SHIFT); - MachTLBUpdate(vadr, entry); - pa = PTE_TO_PADDR(entry); + MachTLBUpdate(vaddr, entry); + pa = pfn_to_vad(entry); #ifdef ATTR pmap_attributes[atop(pa)] |= PMAP_ATTR_MOD; #else - if (!IS_VM_PHYSADDR(pa)) { - panic("trap: utlbmod: unmanaged page"); - } + if (!IS_VM_PHYSADDR(pa)) + panic("utlbmod: unmanaged page"); PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN; #endif - if (!USERMODE(statusReg)) - return (pc); - goto out; + if (type & T_USER) + userret(p, opc, sticks); + return; /* GEN */ } - case T_TLB_LD_MISS: case T_TLB_ST_MISS: - ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ; - /* check for kernel address */ - if ((int)vadr < 0) { - register vm_offset_t va; - int rv; - - kernel_fault: - kernelfaults++; - va = trunc_page((vm_offset_t)vadr); - rv = vm_fault(kernel_map, va, ftype, FALSE); - if (rv == KERN_SUCCESS) - return (pc); - if ((i = ((struct pcb *)UADDR)->pcb_onfault) != 0) { - ((struct pcb *)UADDR)->pcb_onfault = 0; - return (onfault_table[i]); - } - goto err; - } + ftype = (type == T_TLB_LD_MISS) ? VM_PROT_READ : VM_PROT_WRITE; + if (KERNLAND(vaddr)) + goto kernelfault; /* * It is an error for the kernel to access user space except * through the copyin/copyout routines. */ - if ((i = ((struct pcb *)UADDR)->pcb_onfault) == 0) - goto err; + if (p->p_addr->u_pcb.pcb_onfault == NULL) + goto dopanic; /* check for fuswintr() or suswintr() getting a page fault */ - if (i == 4) - return (onfault_table[i]); - goto dofault; - + if (p->p_addr->u_pcb.pcb_onfault == (caddr_t)fswintrberr) { + frame.f_regs[PC] = (int)fswintrberr; + return; /* KERN */ + } + goto pagefault; case T_TLB_LD_MISS+T_USER: ftype = VM_PROT_READ; - goto dofault; - + goto pagefault; case T_TLB_ST_MISS+T_USER: ftype = VM_PROT_WRITE; - dofault: + pagefault: ; { - register vm_offset_t va; - register struct vmspace *vm; - register vm_map_t map; + vm_offset_t va; + struct vmspace *vm; + vm_map_t map; int rv; vm = p->p_vmspace; map = &vm->vm_map; - va = trunc_page((vm_offset_t)vadr); + va = trunc_page((vm_offset_t)vaddr); rv = vm_fault(map, va, ftype, FALSE); #ifdef VMFAULT_TRACE - printf("vm_fault(%x (pmap %x), %x (%x), %x, %d) -> %x at pc %x\n", - map, vm->vm_map.pmap, va, vadr, ftype, FALSE, rv, pc); + printf( + "vm_fault(%p (pmap %p), %p (%p), %p, %d) -> %p at pc %p\n", + map, vm->vm_map.pmap, va, vaddr, ftype, FALSE, rv, opc); #endif /* * If this was a stack access we keep track of the maximum @@ -590,428 +822,154 @@ trap(statusReg, causeReg, vadr, pc, args) nss = clrnd(btoc(USRSTACK-(unsigned)va)); if (nss > vm->vm_ssize) vm->vm_ssize = nss; - } else if (rv == KERN_PROTECTION_FAILURE) + } + else if (rv == KERN_PROTECTION_FAILURE) rv = KERN_INVALID_ADDRESS; } if (rv == KERN_SUCCESS) { - if (!USERMODE(statusReg)) - return (pc); - goto out; + if (type & T_USER) + userret(p, opc, sticks); + return; /* GEN */ } - if (!USERMODE(statusReg)) { - if ((i = ((struct pcb *)UADDR)->pcb_onfault) != 0) { - ((struct pcb *)UADDR)->pcb_onfault = 0; - return (onfault_table[i]); - } - goto err; + if ((type & T_USER) == 0) + goto copyfault; + sig = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; + ucode = vaddr; + break; /* SIGNAL */ } - ucode = vadr; - i = SIGSEGV; - break; + kernelfault: ; + { + vm_offset_t va; + int rv; + + va = trunc_page((vm_offset_t)vaddr); + rv = vm_fault(kernel_map, va, ftype, FALSE); + if (rv == KERN_SUCCESS) + return; /* KERN */ + /*FALLTHROUGH*/ } + case T_ADDR_ERR_LD: /* misaligned access */ + case T_ADDR_ERR_ST: /* misaligned access */ + case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */ + copyfault: + if (p->p_addr->u_pcb.pcb_onfault == NULL) + goto dopanic; + frame.f_regs[PC] = (int)p->p_addr->u_pcb.pcb_onfault; + return; /* KERN */ case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */ case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */ - i = SIGBUS; - break; - - case T_SYSCALL+T_USER: - { - register int *locr0 = p->p_md.md_regs; - register struct sysent *callp; - unsigned int code; - int numsys; - struct args { - int i[8]; - } args; - int rval[2]; - - cnt.v_syscall++; - /* compute next PC after syscall instruction */ - if ((int)causeReg < 0) - locr0[PC] = MachEmulateBranch(locr0, pc, 0, 0); - else - locr0[PC] += 4; - callp = p->p_emul->e_sysent; - numsys = p->p_emul->e_nsysent; - code = locr0[V0]; - switch (code) { - case SYS_syscall: - /* - * Code is first argument, followed by actual args. - */ - code = locr0[A0]; - if (code >= numsys) - callp += p->p_emul->e_nosys; /* (illegal) */ - else - callp += code; - i = callp->sy_argsize / sizeof(int); - args.i[0] = locr0[A1]; - args.i[1] = locr0[A2]; - args.i[2] = locr0[A3]; - if (i > 3) { - i = copyin((caddr_t)(locr0[SP] + - 4 * sizeof(int)), - (caddr_t)&args.i[3], - (u_int)(i - 3) * sizeof(int)); - if (i) { - locr0[V0] = i; - locr0[A3] = 1; -#ifdef SYSCALL_DEBUG - scdebug_call(p, code, args.i); -#endif -#ifdef KTRACE - if (KTRPOINT(p, KTR_SYSCALL)) - ktrsyscall(p->p_tracep, code, - callp->sy_argsize, - args.i); -#endif - goto done; - } - } - break; - - case SYS___syscall: - /* - * Like syscall, but code is a quad, so as to maintain - * quad alignment for the rest of the arguments. - */ - code = locr0[A0 + _QUAD_LOWWORD]; - if (code >= numsys) - callp += p->p_emul->e_nosys; /* (illegal) */ - else - callp += code; - i = callp->sy_argsize / sizeof(int); - args.i[0] = locr0[A2]; - args.i[1] = locr0[A3]; - if (i > 2) { - i = copyin((caddr_t)(locr0[SP] + - 4 * sizeof(int)), - (caddr_t)&args.i[2], - (u_int)(i - 2) * sizeof(int)); - if (i) { - locr0[V0] = i; - locr0[A3] = 1; -#ifdef SYSCALL_DEBUG - scdebug_call(p, code, args.i); -#endif -#ifdef KTRACE - if (KTRPOINT(p, KTR_SYSCALL)) - ktrsyscall(p->p_tracep, code, - callp->sy_argsize, - args.i); -#endif - goto done; - } - } - break; - - default: - if (code >= numsys) - callp += p->p_emul->e_nosys; /* (illegal) */ - else - callp += code; - i = callp->sy_narg; - args.i[0] = locr0[A0]; - args.i[1] = locr0[A1]; - args.i[2] = locr0[A2]; - args.i[3] = locr0[A3]; - if (i > 4) { - i = copyin((caddr_t)(locr0[SP] + - 4 * sizeof(int)), - (caddr_t)&args.i[4], - (u_int)(i - 4) * sizeof(int)); - if (i) { - locr0[V0] = i; - locr0[A3] = 1; -#ifdef SYSCALL_DEBUG - scdebug_call(p, code, args.i); -#endif -#ifdef KTRACE - if (KTRPOINT(p, KTR_SYSCALL)) - ktrsyscall(p->p_tracep, code, - callp->sy_argsize, - args.i); -#endif - goto done; - } - } - } -#ifdef SYSCALL_DEBUG - scdebug_call(p, code, args.i); -#endif -#ifdef KTRACE - if (KTRPOINT(p, KTR_SYSCALL)) - ktrsyscall(p->p_tracep, code, callp->sy_argsize, args.i); -#endif - rval[0] = 0; - rval[1] = locr0[V1]; -#ifdef DEBUG - if (trp == trapdebug) - trapdebug[TRAPSIZE - 1].code = code; - else - trp[-1].code = code; -#endif - i = (*callp->sy_call)(p, &args, rval); - /* - * Reinitialize proc pointer `p' as it may be different - * if this is a child returning from fork syscall. - */ - p = curproc; - locr0 = p->p_md.md_regs; -#ifdef DEBUG - { int s; - s = splhigh(); - trp->status = statusReg; - trp->cause = causeReg; - trp->vadr = locr0[SP]; - trp->pc = locr0[PC]; - trp->ra = locr0[RA]; - /*trp->sp = (int)&args;*/ - trp->code = -code; - if (++trp == &trapdebug[TRAPSIZE]) - trp = trapdebug; - splx(s); - } -#endif - switch (i) { - case 0: - locr0[V0] = rval[0]; - locr0[V1] = rval[1]; - locr0[A3] = 0; - break; - - case ERESTART: - locr0[PC] = pc; - break; - - case EJUSTRETURN: - break; /* nothing to do */ - - default: - locr0[V0] = i; - locr0[A3] = 1; - } - - /* - * If we modified code or data, flush caches. - * XXX code unyderling ptrace() and/or proc fs should do this? - */ - if (code == SYS_ptrace) - MachFlushCache(); - done: -#ifdef SYSCALL_DEBUG - scdebug_ret(p, code, i, rval); -#endif -#ifdef KTRACE - if (KTRPOINT(p, KTR_SYSRET)) - ktrsysret(p->p_tracep, code, i, rval[0]); /*XXX*/ -#endif - goto out; - } - + sig = SIGSEGV; + ucode = vaddr; + break; /* SIGNAL */ case T_BREAK+T_USER: { - register unsigned va, instr; + unsigned va, instr; + int rv; /* compute address of break instruction */ - va = pc; - if ((int)causeReg < 0) - va += 4; + va = (DELAYBRANCH(cause)) ? opc + sizeof(int) : opc; /* read break instruction */ instr = fuiword((caddr_t)va); -#if 0 - printf("trap: %s (%d) breakpoint %x at %x: (adr %x ins %x)\n", - p->p_comm, p->p_pid, instr, pc, - p->p_md.md_ss_addr, p->p_md.md_ss_instr); /* XXX */ -#endif -#ifdef KADB - if (instr == MACH_BREAK_BRKPT || instr == MACH_BREAK_SSTEP) - goto err; -#endif + if (p->p_md.md_ss_addr != va || instr != MACH_BREAK_SSTEP) { - i = SIGTRAP; + sig = SIGTRAP; break; } - - /* restore original instruction and clear BP */ - i = suiword((caddr_t)va, p->p_md.md_ss_instr); - if (i < 0) { + /* + * Restore original instruction and clear BP + */ +#ifndef NO_PROCFS_SUBR + rv = suiword((caddr_t)va, p->p_md.md_ss_instr); + if (rv < 0) { vm_offset_t sa, ea; - int rv; - sa = trunc_page((vm_offset_t)va); - ea = round_page((vm_offset_t)va+sizeof(int)-1); - rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, - VM_PROT_DEFAULT, FALSE); + ea = round_page((vm_offset_t)va + sizeof(int) - 1); + rv = vm_map_protect(&p->p_vmspace->vm_map, + sa, ea, VM_PROT_DEFAULT, FALSE); if (rv == KERN_SUCCESS) { - i = suiword((caddr_t)va, p->p_md.md_ss_instr); - (void) vm_map_protect(&p->p_vmspace->vm_map, - sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, - FALSE); + rv = suiword((caddr_t)va, MACH_BREAK_SSTEP); + (void)vm_map_protect(&p->p_vmspace->vm_map, + sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE); + } } +#else + { + struct uio uio; + struct iovec iov; + iov.iov_base = (caddr_t)&p->p_md.md_ss_instr; + iov.iov_len = sizeof(int); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = (off_t)va; + uio.uio_resid = sizeof(int); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_WRITE; + uio.uio_procp = curproc; + rv = procfs_domem(p, p, NULL, &uio); + MachFlushCache(); } - if (i < 0) - printf("Warning: can't restore instruction at %x: %x\n", +#endif + if (rv < 0) + printf("Warning: can't restore instruction at 0x%x: 0x%x\n", p->p_md.md_ss_addr, p->p_md.md_ss_instr); p->p_md.md_ss_addr = 0; - i = SIGTRAP; - break; - } - + sig = SIGTRAP; + break; /* SIGNAL */ + } case T_RES_INST+T_USER: - i = SIGILL; - break; - + sig = SIGILL; + break; /* SIGNAL */ case T_COP_UNUSABLE+T_USER: - if ((causeReg & MACH_CR_COP_ERR) != 0x10000000) { - i = SIGILL; /* only FPU instructions allowed */ - break; - } - MachSwitchFPState(machFPCurProcPtr, - (struct user*)p->p_md.md_regs); - machFPCurProcPtr = p; + if ((cause & MACH_CR_COP_ERR) != 0x10000000) { + sig = SIGILL; /* only FPU instructions allowed */ + break; /* SIGNAL */ + } + switchfpregs(fpcurproc, p); + fpcurproc = p; p->p_md.md_regs[PS] |= MACH_SR_COP_1_BIT; p->p_md.md_flags |= MDP_FPUSED; - goto out; - - case T_FPE: -#ifdef DEBUG - trapDump("fpintr"); -#else - printf("FPU Trap: PC %x CR %x SR %x\n", - pc, causeReg, statusReg); - goto err; -#endif - + userret(p, opc, sticks); + return; /* GEN */ case T_FPE+T_USER: - MachFPTrap(statusReg, causeReg, pc); - goto out; - + MachFPInterrupt(status, cause, opc, p->p_md.md_regs); + userret(p, opc, sticks); + return; /* GEN */ case T_OVFLOW+T_USER: - i = SIGFPE; - break; - - case T_ADDR_ERR_LD: /* misaligned access */ - case T_ADDR_ERR_ST: /* misaligned access */ - case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */ - if ((i = ((struct pcb *)UADDR)->pcb_onfault) != 0) { - ((struct pcb *)UADDR)->pcb_onfault = 0; - return (onfault_table[i]); + sig = SIGFPE; + break; /* SIGNAL */ } - /* FALLTHROUGH */ - - default: - err: -#ifdef KADB - { - extern struct pcb kdbpcb; - - if (USERMODE(statusReg)) - kdbpcb = p->p_addr->u_pcb; - else { - kdbpcb.pcb_regs[ZERO] = 0; - kdbpcb.pcb_regs[AST] = ((int *)&args)[2]; - kdbpcb.pcb_regs[V0] = ((int *)&args)[3]; - kdbpcb.pcb_regs[V1] = ((int *)&args)[4]; - kdbpcb.pcb_regs[A0] = ((int *)&args)[5]; - kdbpcb.pcb_regs[A1] = ((int *)&args)[6]; - kdbpcb.pcb_regs[A2] = ((int *)&args)[7]; - kdbpcb.pcb_regs[A3] = ((int *)&args)[8]; - kdbpcb.pcb_regs[T0] = ((int *)&args)[9]; - kdbpcb.pcb_regs[T1] = ((int *)&args)[10]; - kdbpcb.pcb_regs[T2] = ((int *)&args)[11]; - kdbpcb.pcb_regs[T3] = ((int *)&args)[12]; - kdbpcb.pcb_regs[T4] = ((int *)&args)[13]; - kdbpcb.pcb_regs[T5] = ((int *)&args)[14]; - kdbpcb.pcb_regs[T6] = ((int *)&args)[15]; - kdbpcb.pcb_regs[T7] = ((int *)&args)[16]; - kdbpcb.pcb_regs[T8] = ((int *)&args)[17]; - kdbpcb.pcb_regs[T9] = ((int *)&args)[18]; - kdbpcb.pcb_regs[RA] = ((int *)&args)[19]; - kdbpcb.pcb_regs[MULLO] = ((int *)&args)[21]; - kdbpcb.pcb_regs[MULHI] = ((int *)&args)[22]; - kdbpcb.pcb_regs[PC] = pc; - kdbpcb.pcb_regs[SR] = statusReg; - bzero((caddr_t)&kdbpcb.pcb_regs[F0], 33 * sizeof(int)); - } - if (kdb(causeReg, vadr, p, !USERMODE(statusReg))) - return (kdbpcb.pcb_regs[PC]); - } -#else -#ifdef DEBUG - stacktrace(); - trapDump("trap"); -#endif -#endif - panic("trap"); - } - p->p_md.md_regs [PC] = pc; - p->p_md.md_regs [CAUSE] = causeReg; - p->p_md.md_regs [BADVADDR] = vadr; - trapsignal(p, i, ucode); -out: - /* - * Note: we should only get here if returning to user mode. - */ - /* take pending signals */ - while ((i = CURSIG(p)) != 0) - postsig(i); - p->p_priority = p->p_usrpri; - astpending = 0; - if (want_resched) { - int s; - - /* - * Since we are curproc, clock will normally just change - * our priority without moving us from one queue to another - * (since the running process is not on a queue.) - * If that happened after we put ourselves on the run queue - * but before we switched, we might not be on the queue - * indicated by our priority. - */ - s = splstatclock(); - setrunqueue(p); - p->p_stats->p_ru.ru_nivcsw++; - mi_switch(); - splx(s); - while ((i = CURSIG(p)) != 0) - postsig(i); - } - - /* - * If profiling, charge system time to the trapped pc. - */ - if (p->p_flag & P_PROFIL) { - extern int psratio; - - addupc_task(p, pc, (int)(p->p_sticks - sticks) * psratio); - } - - curpriority = p->p_priority; - return (pc); + p->p_md.md_regs[CAUSE] = cause; + p->p_md.md_regs[BADVADDR] = vaddr; + trapsignal(p, sig, ucode); + if ((type & T_USER) == 0) + panic("trapsignal"); + userret(p, opc, sticks); + return; } +#include +#include "ether.h" +#include "ppp.h" + /* * Handle an interrupt. * Called from MachKernIntr() or MachUserIntr() * Note: curproc might be NULL. */ void -interrupt(statusReg, causeReg, pc /* XXX what, args */ ) - unsigned statusReg; /* status register at time of the exception */ - unsigned causeReg; /* cause register at time of exception */ - unsigned pc; /* program counter where to continue */ +interrupt(status, cause, pc, frame) + unsigned status, cause, pc; + struct frame *frame; { - register unsigned mask; - /*struct clockframe cf;*/ + unsigned mask; #ifdef DEBUG - trp->status = statusReg; - trp->cause = causeReg; + trp->status = status; + trp->cause = cause; trp->vadr = 0; trp->pc = pc; trp->ra = 0; @@ -1022,112 +980,76 @@ interrupt(statusReg, causeReg, pc /* XXX what, args */ ) #endif cnt.v_intr++; - mask = causeReg & statusReg; /* pending interrupts & enable mask */ + mask = cause & status; /* pending interrupts & enable mask */ + + /* Device interrupt */ if (mips_hardware_intr) - splx((*mips_hardware_intr)(mask, pc, statusReg, causeReg)); + splx((*mips_hardware_intr)(mask, pc, status, cause)); if (mask & MACH_INT_MASK_5) { intrcnt[FPU_INTR]++; - if (!USERMODE(statusReg)) { -#ifdef DEBUG - trapDump("fpintr"); -#else + if (USERMODE(status)) + MachFPInterrupt(status, cause, pc, frame->f_regs); + else { printf("FPU interrupt: PC %x CR %x SR %x\n", - pc, causeReg, statusReg); -#endif - } else - MachFPInterrupt(statusReg, causeReg, pc); + pc, cause, status); + } } - /* process network interrupt if we trapped or will very soon */ - /* XXX fixme: operator precedence botch? */ - if ((mask & MACH_SOFT_INT_MASK_1) || - (netisr && (statusReg & MACH_SOFT_INT_MASK_1))) { + /* Network software interrupt */ + if ((mask & MACH_SOFT_INT_MASK_1) + || (netisr && (status & MACH_SOFT_INT_MASK_1))) { + register isr; + isr = netisr; netisr = 0; /* XXX need protect? */ clearsoftnet(); cnt.v_soft++; intrcnt[SOFTNET_INTR]++; #ifdef INET - if (netisr & (1 << NETISR_ARP)) { - netisr &= ~(1 << NETISR_ARP); - arpintr(); - } - if (netisr & (1 << NETISR_IP)) { - netisr &= ~(1 << NETISR_IP); - ipintr(); - } +#if NETHER > 0 + if (isr & (1 << NETISR_ARP)) arpintr(); +#endif + if (isr & (1 << NETISR_IP)) ipintr(); #endif #ifdef NS - if (netisr & (1 << NETISR_NS)) { - netisr &= ~(1 << NETISR_NS); - nsintr(); - } + if (isr & (1 << NETISR_NS)) nsintr(); #endif #ifdef ISO - if (netisr & (1 << NETISR_ISO)) { - netisr &= ~(1 << NETISR_ISO); - clnlintr(); - } + if (isr & (1 << NETISR_ISO)) clnlintr(); #endif #if NPPP > 0 - if (netisr & (1 << NETISR_PPP)) { - netisr &= ~(1 << NETISR_PPP); - pppintr(); - } + if (isr & (1 << NETISR_PPP)) pppintr(); #endif } + /* Software clock interrupt */ if (mask & MACH_SOFT_INT_MASK_0) { clearsoftclock(); - intrcnt[SOFTCLOCK_INTR]++; cnt.v_soft++; + intrcnt[SOFTCLOCK_INTR]++; softclock(); } } - /* - * This is called from MachUserIntr() if astpending is set. - * This is very similar to the tail of trap(). + * Handle asynchronous software traps. + * This is called from MachUserIntr() either to deliver signals or + * to make involuntary context switch (preemption). */ void -softintr(statusReg, pc) - unsigned statusReg; /* status register at time of the exception */ +ast(pc) unsigned pc; /* program counter where to continue */ { - register struct proc *p = curproc; - int sig; + struct proc *p = curproc; cnt.v_soft++; - /* take pending signals */ - while ((sig = CURSIG(p)) != 0) - postsig(sig); - p->p_priority = p->p_usrpri; astpending = 0; if (p->p_flag & P_OWEUPC) { p->p_flag &= ~P_OWEUPC; ADDUPROF(p); } - if (want_resched) { - int s; - - /* - * Since we are curproc, clock will normally just change - * our priority without moving us from one queue to another - * (since the running process is not on a queue.) - * If that happened after we put ourselves on the run queue - * but before we switched, we might not be on the queue - * indicated by our priority. - */ - s = splstatclock(); - setrunqueue(p); - p->p_stats->p_ru.ru_nivcsw++; - mi_switch(); - splx(s); - while ((sig = CURSIG(p)) != 0) - postsig(sig); - } - curpriority = p->p_priority; + userret(p, pc, p->p_sticks); } + #ifdef DEBUG void trapDump(msg) @@ -1323,65 +1245,81 @@ MachEmulateBranch(regsPtr, instPC, fpcCSR, allowNonBranch) */ int mips_singlestep(p) - register struct proc *p; + struct proc *p; { - register unsigned va; - register int *locr0 = p->p_md.md_regs; - int i; +#ifdef NO_PROCFS_SUBR + struct frame *f = (struct frame *)p->p_md.md_regs; + unsigned va = 0; + int rv; -#if notanymore - /* compute next address after current location */ - va = MachEmulateBranch(locr0, locr0[PC], locr0[FSR], 1); - if (p->p_md.md_ss_addr || p->p_md.md_ss_addr == va || - !useracc((caddr_t)va, 4, B_READ)) { + if (p->p_md.md_ss_addr) { printf("SS %s (%d): breakpoint already set at %x (va %x)\n", p->p_comm, p->p_pid, p->p_md.md_ss_addr, va); /* XXX */ - return (EFAULT); + return EFAULT; } + if (fuiword((caddr_t)f->f_regs[PC]) != 0) /* not a NOP instruction */ + va = MachEmulateBranch(f->f_regs, f->f_regs[PC], + p->p_addr->u_pcb.pcb_fpregs.r_regs[32], 1); + else + va = f->f_regs[PC] + sizeof(int); p->p_md.md_ss_addr = va; p->p_md.md_ss_instr = fuiword((caddr_t)va); - i = suiword((caddr_t)va, MACH_BREAK_SSTEP); - if (i < 0) { + rv = suiword((caddr_t)va, MACH_BREAK_SSTEP); + if (rv < 0) { vm_offset_t sa, ea; - int rv; - sa = trunc_page((vm_offset_t)va); - ea = round_page((vm_offset_t)va+sizeof(int)-1); - rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, - VM_PROT_DEFAULT, FALSE); + ea = round_page((vm_offset_t)va + sizeof(int) - 1); + rv = vm_map_protect(&p->p_vmspace->vm_map, + sa, ea, VM_PROT_DEFAULT, FALSE); if (rv == KERN_SUCCESS) { - i = suiword((caddr_t)va, MACH_BREAK_SSTEP); - (void) vm_map_protect(&p->p_vmspace->vm_map, + rv = suiword((caddr_t)va, MACH_BREAK_SSTEP); + (void)vm_map_protect(&p->p_vmspace->vm_map, sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE); } } -#endif - int bpinstr = MACH_BREAK_SSTEP; - int curinstr; +#else + struct frame *f = (struct frame *)p->p_md.md_regs; + unsigned pc = f->f_regs[PC]; + unsigned va = 0; + int rv; + int curinstr, bpinstr = MACH_BREAK_SSTEP; struct uio uio; struct iovec iov; - /* - * Fetch what's at the current location. - */ - iov.iov_base = (caddr_t)&curinstr; - iov.iov_len = sizeof(int); - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_offset = (off_t)locr0[PC]; - uio.uio_resid = sizeof(int); - uio.uio_segflg = UIO_SYSSPACE; - uio.uio_rw = UIO_READ; - uio.uio_procp = curproc; - procfs_domem(curproc, p, NULL, &uio); +#define FETCH_INSTRUCTION(i, va) \ + iov.iov_base = (caddr_t)&(i);\ + iov.iov_len = sizeof(int); \ + uio.uio_iov = &iov;\ + uio.uio_iovcnt = 1;\ + uio.uio_offset = (off_t)(va);\ + uio.uio_resid = sizeof(int);\ + uio.uio_segflg = UIO_SYSSPACE;\ + uio.uio_rw = UIO_READ;\ + uio.uio_procp = curproc;\ + rv = procfs_domem(curproc, p, NULL, &uio) + +#define STORE_INSTRUCTION(i, va) \ + iov.iov_base = (caddr_t)&(i);\ + iov.iov_len = sizeof(int);\ + uio.uio_iov = &iov;\ + uio.uio_iovcnt = 1;\ + uio.uio_offset = (off_t)(va);\ + uio.uio_resid = sizeof(int);\ + uio.uio_segflg = UIO_SYSSPACE;\ + uio.uio_rw = UIO_WRITE;\ + uio.uio_procp = curproc;\ + rv = procfs_domem(curproc, p, NULL, &uio) + + /* Fetch what's at the current location. */ + FETCH_INSTRUCTION(curinstr, va); /* compute next address after current location */ - if(curinstr != 0) { - va = MachEmulateBranch(locr0, locr0[PC], locr0[FSR], curinstr); - } - else { - va = locr0[PC] + 4; - } + if (curinstr != 0) + va = MachEmulateBranch(f->f_regs, pc, + p->p_addr->u_pcb.pcb_fpregs.r_regs[32], 1); + else + va = pc + sizeof(int); + if (p->p_md.md_ss_addr) { printf("SS %s (%d): breakpoint already set at %x (va %x)\n", p->p_comm, p->p_pid, p->p_md.md_ss_addr, va); /* XXX */ @@ -1389,43 +1327,22 @@ mips_singlestep(p) } p->p_md.md_ss_addr = va; - /* - * Fetch what's at the current location. - */ - iov.iov_base = (caddr_t)&p->p_md.md_ss_instr; - iov.iov_len = sizeof(int); - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_offset = (off_t)va; - uio.uio_resid = sizeof(int); - uio.uio_segflg = UIO_SYSSPACE; - uio.uio_rw = UIO_READ; - uio.uio_procp = curproc; - procfs_domem(curproc, p, NULL, &uio); + /* Fetch what's at the current location. */ + FETCH_INSTRUCTION(p->p_md.md_ss_instr, va); - /* - * Store breakpoint instruction at the "next" location now. - */ - iov.iov_base = (caddr_t)&bpinstr; - iov.iov_len = sizeof(int); - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_offset = (off_t)va; - uio.uio_resid = sizeof(int); - uio.uio_segflg = UIO_SYSSPACE; - uio.uio_rw = UIO_WRITE; - uio.uio_procp = curproc; - i = procfs_domem(curproc, p, NULL, &uio); + /* Store breakpoint instruction at the "next" location now. */ + STORE_INSTRUCTION(bpinstr, va); MachFlushCache(); /* XXX memory barrier followed by flush icache? */ - - if (i < 0) +#endif + if (rv < 0) return (EFAULT); #if 0 printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n", + printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n", p->p_comm, p->p_pid, p->p_md.md_ss_addr, - p->p_md.md_ss_instr, locr0[PC], fuword((caddr_t)va)); /* XXX */ + p->p_md.md_ss_instr, pc, fuword((caddr_t)va)); /* XXX */ #endif - return (0); + return 0; } #ifdef DEBUG @@ -1439,9 +1356,7 @@ kdbpeek(addr) } return (*(int *)addr); } -#endif -#ifdef DEBUG #define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ /* forward */ @@ -1511,14 +1426,14 @@ specialframe: /* NOTE: the offsets depend on the code in locore.s */ (*printfn)("r3000 KernIntr+%x: (%x, %x ,%x) -------\n", pc-(unsigned)mips1_KernIntr, a0, a1, a2); - a0 = kdbpeek(sp + 36); - a1 = kdbpeek(sp + 40); - a2 = kdbpeek(sp + 44); - a3 = kdbpeek(sp + 48); + a0 = kdbpeek(sp + 40); + a1 = kdbpeek(sp + 44); + a2 = kdbpeek(sp + 48); + a3 = kdbpeek(sp + 52); pc = kdbpeek(sp + 20); /* exc_pc - pc at time of exception */ - ra = kdbpeek(sp + 92); /* ra at time of exception */ - sp = sp + 108; + ra = kdbpeek(sp + 148); /* ra at time of exception */ + sp = sp + 176; goto specialframe; } #endif /* MIPS1 */ @@ -1528,14 +1443,14 @@ specialframe: /* NOTE: the offsets depend on the code in locore.s */ (*printfn)("R4000 KernIntr+%x: (%x, %x ,%x) -------\n", pc-(unsigned)mips3_KernIntr, a0, a1, a2); - a0 = kdbpeek(sp + 36); - a1 = kdbpeek(sp + 40); - a2 = kdbpeek(sp + 44); - a3 = kdbpeek(sp + 48); + a0 = kdbpeek(sp + 40); + a1 = kdbpeek(sp + 44); + a2 = kdbpeek(sp + 48); + a3 = kdbpeek(sp + 52); pc = kdbpeek(sp + 20); /* exc_pc - pc at time of exception */ - ra = kdbpeek(sp + 92); /* ra at time of exception */ - sp = sp + 108; + ra = kdbpeek(sp + 148); /* ra at time of exception */ + sp = sp + 176; goto specialframe; } #endif /* MIPS3 */ @@ -1554,13 +1469,12 @@ specialframe: #ifdef MIPS1 /* r2000 family (mips-I cpu) */ if (pcBetween(mips1_KernGenException, mips1_UserGenException)) subr = (unsigned) mips1_KernGenException; - else if (pcBetween(mips1_UserGenException,mips1_KernIntr)) + else if (pcBetween(mips1_UserGenException,mips1_SystemCall)) + subr = (unsigned) mips1_UserGenException; + else if (pcBetween(mips1_SystemCall,mips1_KernIntr)) subr = (unsigned) mips1_UserGenException; else if (pcBetween(mips1_KernIntr, mips1_UserIntr)) subr = (unsigned) mips1_KernIntr; - else if (pcBetween(mips1_UserIntr, mips1_TLBMissException)) - subr = (unsigned) mips1_UserIntr; - else if (pcBetween(mips1_UserIntr, mips1_TLBMissException)) subr = (unsigned) mips1_UserIntr; else if (pcBetween(mips1_UTLBMiss, mips1_exceptionentry_end)) { @@ -1575,13 +1489,14 @@ specialframe: /* R4000 exception handlers */ if (pcBetween(mips3_KernGenException, mips3_UserGenException)) subr = (unsigned) mips3_KernGenException; - else if (pcBetween(mips3_UserGenException,mips3_KernIntr)) + else if (pcBetween(mips3_UserGenException,mips3_SystemCall)) subr = (unsigned) mips3_UserGenException; + else if (pcBetween(mips3_SystemCall,mips3_KernIntr)) + subr = (unsigned) mips3_SystemCall; else if (pcBetween(mips3_KernIntr, mips3_UserIntr)) subr = (unsigned) mips3_KernIntr; - - else if (pcBetween(mips3_UserIntr, mips3_TLBMissException)) + else if (pcBetween(mips3_UserIntr, mips3_TLBInvalidException)) subr = (unsigned) mips3_UserIntr; else if (pcBetween(mips3_TLBMiss, mips3_exceptionentry_end)) { (*printfn)("<>"); @@ -1590,9 +1505,9 @@ specialframe: #endif /* MIPS3 */ - if (pcBetween(splx, wbflush)) + if (pcBetween(splx, switchfpregs)) subr = (unsigned) splx; - else if (pcBetween(cpu_switch, fuword)) + else if (pcBetween(cpu_switch, savectx)) subr = (unsigned) cpu_switch; else if (pcBetween(idle, cpu_switch)) { subr = (unsigned) idle; @@ -1767,6 +1682,7 @@ static struct { void *addr; char *name;} names[] = { #ifdef MIPS1 /* r2000 family (mips-I cpu) */ Name(mips1_KernGenException), Name(mips1_UserGenException), + Name(mips1_SystemCall), Name(mips1_KernIntr), Name(mips1_UserIntr), #endif /* MIPS1 */ @@ -1774,6 +1690,7 @@ static struct { void *addr; char *name;} names[] = { #ifdef MIPS3 /* r4000 family (mips-III cpu) */ Name(mips3_KernGenException), Name(mips3_UserGenException), + Name(mips3_SystemCall), Name(mips3_KernIntr), Name(mips3_UserIntr), #endif /* MIPS3 */ @@ -1801,3 +1718,953 @@ fn_name(unsigned addr) } #endif /* DEBUG */ + +#ifdef MINIDEBUG + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* XXX -- need onfault processing */ +long mdbpeek(caddr_t addr) { return (*(long *)addr); } +void mdbpoke(caddr_t addr, long value) { *(long *)addr = value; } + +static char *op_name[64] = { +/* 0 */ "spec", "bcond","j", "jal", "beq", "bne", "blez", "bgtz", +/* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui", +/*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl", +/*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37", +/*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", +/*40 */ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache", +/*48 */ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld", +/*56 */ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd" +}; + +static char *spec_name[64] = { +/* 0 */ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav", +/* 8 */ "jr", "jalr", "spec12","spec13","syscall","break","spec16","sync", +/*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav", +/*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu", +/*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", +/*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu", +/*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67", +/*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32" +}; + +static char *bcond_name[32] = { +/* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?", +/* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?", +/*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?", +/*24 */ "?", "?", "?", "?", "?", "?", "?", "?", +}; + +static char *cop1_name[64] = { +/* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", +/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", +/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", +/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", +/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", +/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", +/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", + "fcmp.ole","fcmp.ule", +/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", + "fcmp.le","fcmp.ngt" +}; + +static char *fmt_name[16] = { + "s", "d", "e", "fmt3", + "w", "fmt5", "fmt6", "fmt7", + "fmt8", "fmt9", "fmta", "fmtb", + "fmtc", "fmtd", "fmte", "fmtf" +}; + +static char *reg_name[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static char *c0_opname[64] = { + "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", + "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", + "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", + "eret","c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", + "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", + "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", + "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", + "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", +}; + +static char *c0_reg[32] = { + "index","random","tlblo0","tlblo1","context","tlbmask","wired","c0r7", + "badvaddr","count","tlbhi","c0r11","sr","cause","epc", "prid", + "config","lladr","watchlo","watchhi","xcontext","c0r21","c0r22","c0r23", + "c0r24","c0r25","ecc","cacheerr","taglo","taghi","errepc","c0r31" +}; + +extern char *trap_type[]; + +#define MAXBRK 10 +struct brk { + int inst; + int addr; +} brk_tab[MAXBRK]; + +/* + * Mini debugger for kernel. + */ +int +gethex(val, dotval) + unsigned *val, dotval; +{ + unsigned c; + + *val = 0; + while ((c = cngetc()) != '\e' && c != '\n' && c != '\r') { + if (c >= '0' && c <= '9') { + *val = (*val << 4) + c - '0'; + cnputc(c); + } + else if (c >= 'a' && c <= 'f') { + *val = (*val << 4) + c - 'a' + 10; + cnputc(c); + } + else if (c == '\b' || c == 0x7f) { + *val = *val >> 4; + printf("\b \b"); + } + else if (c == ',') { + cnputc(c); + return(c); + } + else if (c == '.') { + *val = dotval;; + cnputc(c); + } + else + cnputc('\a'); + } + if (c == '\r') + c = '\n'; + return(c); +} + +void dump(addr, size) +unsigned *addr, size; +{ + int cnt; + + cnt = 0; + size = (size + 3) / 4; + while (size--) { + if ((cnt++ & 3) == 0) + printf("\n%08x: ",(int)addr); + printf("%08x ",*addr++); + } +} + +void print_regs(frame) +struct frame *frame; +{ + printf("\n"); + printf("T0-7 %08x %08x %08x %08x %08x %08x %08x %08x\n", + frame->f_regs[T0], frame->f_regs[T1], + frame->f_regs[T2], frame->f_regs[T3], + frame->f_regs[T4], frame->f_regs[T5], + frame->f_regs[T6], frame->f_regs[T7]); + printf("T8-9 %08x %08x A0-4 %08x %08x %08x %08x\n", + frame->f_regs[T8], frame->f_regs[T9], + frame->f_regs[A0], frame->f_regs[A1], + frame->f_regs[A2], frame->f_regs[A3]); + printf("S0-7 %08x %08x %08x %08x %08x %08x %08x %08x\n", + frame->f_regs[S0], frame->f_regs[S1], + frame->f_regs[S2], frame->f_regs[S3], + frame->f_regs[S4], frame->f_regs[S5], + frame->f_regs[S6], frame->f_regs[S7]); + printf(" S8 %08x V0-1 %08x %08x GP %08x SP %08x\n", + frame->f_regs[S8], frame->f_regs[V0], + frame->f_regs[V1], frame->f_regs[GP], + frame->f_regs[SP]); + printf(" AT %08x PC %08x RA %08x SR %08x", + frame->f_regs[AST], frame->f_regs[PC], + frame->f_regs[RA], frame->f_regs[SR]); +} + +void +set_break(va) + u_int va; +{ + int i; + + va = va & ~3; + for (i = 0; i < MAXBRK; i++) { + if (brk_tab[i].addr == 0) { + brk_tab[i].addr = va; + brk_tab[i].inst = *(unsigned *)va; + return; + } + + } + printf(" Break table full!!"); +} + +void +del_break(va) + u_int va; +{ + int i; + + va = va & ~3; + for (i = 0; i < MAXBRK; i++) { + if (brk_tab[i].addr == va) { + brk_tab[i].addr = 0; + return; + } + } + printf(" Break to remove not found!!"); +} + +void +break_insert() +{ + int i; + + for (i = 0; i < MAXBRK; i++) { + if (brk_tab[i].addr != 0) { + brk_tab[i].inst = *(unsigned *)brk_tab[i].addr; + *(unsigned *)brk_tab[i].addr = MACH_BREAK_BRKPT; + MachFlushDCache(brk_tab[i].addr,4); + MachFlushICache(brk_tab[i].addr,4); + } + } +} + +void +break_restore() +{ + int i; + + + + for (i = 0; i < MAXBRK; i++) { + if (brk_tab[i].addr != 0) { + *(unsigned *)brk_tab[i].addr = brk_tab[i].inst; + MachFlushDCache(brk_tab[i].addr,4); + MachFlushICache(brk_tab[i].addr,4); + } + } +} + +int +break_find(va) + u_int va; +{ + int i; + + for (i = 0; i < MAXBRK; i++) { + if (brk_tab[i].addr == va) { + return(i); + } + } + return(-1); +} + +void +prt_break() +{ + int i; + + + for (i = 0; i < MAXBRK; i++) { + if (brk_tab[i].addr != 0) { + printf("\n %08x\t", brk_tab[i].addr); + mdbprintins(brk_tab[i].inst, brk_tab[i].addr); + } + } +} + +unsigned mdb_ss_addr; +unsigned mdb_ss_instr; + +void +mdbsetsstep(frame) + struct frame *frame; +{ + register unsigned va; + int pc, allowbranch; + + pc = frame->f_regs[PC]; + + /* compute next address after current location */ + if ((allowbranch = mdbpeek((caddr_t)pc)) != 0) + va = MachEmulateBranch(frame->f_regs, pc, 0, allowbranch); + else + va = pc + 4; + if (mdb_ss_addr) { + printf("mdbsetsstep: breakpoint already set at %x (va %x)\n", + mdb_ss_addr, va); + return; + } + mdb_ss_addr = va; + + if ((int)va < 0) { + /* kernel address */ + mdb_ss_instr = mdbpeek((caddr_t)va); + mdbpoke((caddr_t)va, MACH_BREAK_SSTEP); + MachFlushDCache(va, 4); + MachFlushICache(va, 4); + } + return; +} + +int +mdbclrsstep(frame) + struct frame *frame; +{ + register unsigned pc, va; + + /* fix pc if break instruction is in the delay slot */ + pc = frame->f_regs[PC]; + if (frame->f_regs[CAUSE] < 0) + pc += 4; + + + /* check to be sure its the one we are expecting */ + va = mdb_ss_addr; + if (!va || va != pc) + return(FALSE); + + /* read break instruction */ + if (mdbpeek((caddr_t)va) != MACH_BREAK_SSTEP) + return(FALSE); + + if ((int)va < 0) { + /* kernel address */ + mdbpoke((caddr_t)va, mdb_ss_instr); + MachFlushDCache(va, 4); + MachFlushICache(va, 4); + mdb_ss_addr = 0; + return(TRUE); + } + + printf("can't clear break at %x\n", va); + mdb_ss_addr = 0; + return(FALSE); +} + +int +mdbprintins(ins, mdbdot) + int ins, mdbdot; +{ + InstFmt i; + int delay = 0; + + i.word = ins; + + switch (i.JType.op) { + case OP_SPECIAL: + if (i.word == 0) { + printf("nop"); + break; + } + if (i.RType.func == OP_ADDU && i.RType.rt == 0) { + printf("move\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs]); + break; + } + printf("%s", spec_name[i.RType.func]); + switch (i.RType.func) { + case OP_SLL: + case OP_SRL: + case OP_SRA: + case OP_DSLL: + + case OP_DSRL: + case OP_DSRA: + case OP_DSLL32: + case OP_DSRL32: + case OP_DSRA32: + printf("\t%s,%s,%d", + reg_name[i.RType.rd], + reg_name[i.RType.rt], + i.RType.shamt); + break; + + case OP_SLLV: + case OP_SRLV: + case OP_SRAV: + case OP_DSLLV: + case OP_DSRLV: + case OP_DSRAV: + printf("\t%s,%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt], + reg_name[i.RType.rs]); + break; + + case OP_MFHI: + case OP_MFLO: + printf("\t%s", reg_name[i.RType.rd]); + break; + + case OP_JR: + case OP_JALR: + delay = 1; + /* FALLTHROUGH */ + case OP_MTLO: + case OP_MTHI: + printf("\t%s", reg_name[i.RType.rs]); + break; + + case OP_MULT: + case OP_MULTU: + case OP_DMULT: + case OP_DMULTU: + case OP_DIV: + case OP_DIVU: + case OP_DDIV: + case OP_DDIVU: + printf("\t%s,%s", + reg_name[i.RType.rs], + reg_name[i.RType.rt]); + break; + + + case OP_SYSCALL: + case OP_SYNC: + break; + + case OP_BREAK: + printf("\t%d", (i.RType.rs << 5) | i.RType.rt); + break; + + default: + printf("\t%s,%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs], + reg_name[i.RType.rt]); + }; + break; + + case OP_BCOND: + printf("%s\t%s,", bcond_name[i.IType.rt], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BLEZ: + case OP_BLEZL: + case OP_BGTZ: + case OP_BGTZL: + printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BEQ: + case OP_BEQL: + if (i.IType.rs == 0 && i.IType.rt == 0) { + printf("b\t"); + goto pr_displ; + } + /* FALLTHROUGH */ + case OP_BNE: + case OP_BNEL: + printf("%s\t%s,%s,", op_name[i.IType.op], + reg_name[i.IType.rs], + reg_name[i.IType.rt]); + pr_displ: + delay = 1; + printf("0x%08x", mdbdot + 4 + ((short)i.IType.imm << 2)); + break; + + case OP_COP0: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + + printf("bc0%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + printf("mtc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_DMT: + printf("dmtc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_MF: + printf("mfc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_DMF: + printf("dmfc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + default: + printf("%s", c0_opname[i.FRType.func]); + }; + break; + + case OP_COP1: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + printf("bc1%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + printf("mtc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_MF: + printf("mfc1\t%s,f%d", + + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_CT: + printf("ctc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_CF: + printf("cfc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + default: + printf("%s.%s\tf%d,f%d,f%d", + cop1_name[i.FRType.func], + fmt_name[i.FRType.fmt], + i.FRType.fd, i.FRType.fs, i.FRType.ft); + }; + break; + + case OP_J: + case OP_JAL: + printf("%s\t", op_name[i.JType.op]); + printf("0x%8x",(mdbdot & 0xF0000000) | (i.JType.target << 2)); + delay = 1; + break; + + case OP_LWC1: + case OP_SWC1: + printf("%s\tf%d,", op_name[i.IType.op], + i.IType.rt); + goto loadstore; + + case OP_LB: + case OP_LH: + case OP_LW: + case OP_LD: + case OP_LBU: + case OP_LHU: + case OP_LWU: + case OP_SB: + case OP_SH: + case OP_SW: + case OP_SD: + printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rt]); + loadstore: + printf("%d(%s)", (short)i.IType.imm, + reg_name[i.IType.rs]); + break; + + case OP_ORI: + case OP_XORI: + if (i.IType.rs == 0) { + printf("li\t%s,0x%x", + reg_name[i.IType.rt], + i.IType.imm); + break; + } + /* FALLTHROUGH */ + case OP_ANDI: + printf("%s\t%s,%s,0x%x", op_name[i.IType.op], + reg_name[i.IType.rt], + reg_name[i.IType.rs], + i.IType.imm); + break; + + case OP_LUI: + printf("%s\t%s,0x%x", op_name[i.IType.op], + reg_name[i.IType.rt], + i.IType.imm); + break; + + case OP_ADDI: + case OP_DADDI: + case OP_ADDIU: + case OP_DADDIU: + if (i.IType.rs == 0) { + printf("li\t%s,%d", + reg_name[i.IType.rt], + (short)i.IType.imm); + break; + } + /* FALLTHROUGH */ + default: + printf("%s\t%s,%s,%d", op_name[i.IType.op], + reg_name[i.IType.rt], + reg_name[i.IType.rs], + (short)i.IType.imm); + } + return(delay); +} + +#ifdef MIPS3 +/* + * Dump TLB contents. + */ +void +mips_dump_tlb(first, last) + int first; + int last; +{ + int tlbno; + struct tlb tlb; + extern void mips3_TLBRead(int, struct tlb *); + + tlbno = first; + + while(tlbno <= last) { + mips3_TLBRead(tlbno, &tlb); + if(tlb.tlb_lo0 & PG_V || tlb.tlb_lo1 & PG_V) { + printf("TLB %2d vad 0x%08x ", tlbno, tlb.tlb_hi); + } + else { + printf("TLB*%2d vad 0x%08x ", tlbno, tlb.tlb_hi); + } + printf("0=0x%08x ", pfn_to_vad(tlb.tlb_lo0)); + printf("%c", tlb.tlb_lo0 & PG_M ? 'M' : ' '); + printf("%c", tlb.tlb_lo0 & PG_G ? 'G' : ' '); + printf(" atr %x ", (tlb.tlb_lo0 >> 3) & 7); + printf("1=0x%08x ", pfn_to_vad(tlb.tlb_lo1)); + printf("%c", tlb.tlb_lo1 & PG_M ? 'M' : ' '); + printf("%c", tlb.tlb_lo1 & PG_G ? 'G' : ' '); + printf(" atr %x ", (tlb.tlb_lo1 >> 3) & 7); + printf(" sz=%x\n", tlb.tlb_mask); + + tlbno++; + } +} +#else /* MIPS3 */ +/* + * Dump TLB contents. + */ +void +mips_dump_tlb(first, last) + int first; + int last; +{ + int tlbno; + extern u_int tlbhi, tlblo; + extern void mips1_TLBRead(int); + + tlbno = first; + + while(tlbno <= last) { + mips1_TLBRead(tlbno); + if(tlblo & PG_V) { + printf("TLB %2d vad 0x%08x ", tlbno, tlbhi); + } + else { + printf("TLB*%2d vad 0x%08x ", tlbno, tlbhi); + } + printf("0x%08x ", tlblo & PG_FRAME); + printf("%c", tlblo & PG_M ? 'M' : ' '); + printf("%c", tlblo & PG_G ? 'G' : ' '); + printf("%c\n", tlblo & PG_N ? 'N' : ' '); + + tlbno++; + } +} +#endif /* MIPS3 */ + +int +mdb(type, frame) + int type; + struct frame *frame; +{ + int c; + int newaddr; + int size; +static int ssandrun; /* Single step and run flag (when cont at brk) */ + + splhigh(); + newaddr = frame->f_regs[PC]; + switch (type) { + case T_BREAK: + if (*(int *)newaddr == MACH_BREAK_SOVER) { + break_restore(); + frame->f_regs[PC] += 4; + printf("\nStop break (panic)\n# "); + printf(" %08x\t", newaddr); + (void)mdbprintins(*(int *)newaddr, newaddr); + printf("\n# "); + break; + } + if (*(int *)newaddr == MACH_BREAK_BRKPT) { + break_restore(); + printf("\rBRK %08x\t", newaddr); + if (mdbprintins(*(int *)newaddr, newaddr)) { + newaddr += 4; + printf("\n %08x\t", newaddr); + (void)mdbprintins(*(int *)newaddr, newaddr); + } + printf("\n# "); + break; + } + if (mdbclrsstep(frame)) { + if (ssandrun) { /* Step over bp before free run */ + ssandrun = 0; + break_insert(); + return(TRUE); + } + printf("\r %08x\t", newaddr); + if (mdbprintins(*(int *)newaddr, newaddr)) { + newaddr += 4; + printf("\n %08x\t",newaddr); + (void)mdbprintins(*(int *)newaddr, newaddr); + } + printf("\n# "); + } + break; + + default: + printf("\n-- %s --\n# ", trap_type[type]); + } + ssandrun = 0; + break_restore(); + + while (1) { + c = cngetc(); + switch (c) { + case 'T': +#ifdef DEBUG + trapDump("Debugger"); +#else + printf("trapDump not available\n"); +#endif + break; + case 'b': + printf("break-"); + c = cngetc(); + switch (c) { + case 's': + printf("set at "); + c = gethex(&newaddr, newaddr); + if (c != '\e') { + set_break(newaddr); + } + break; + + case 'd': + printf("delete at "); + c = gethex(&newaddr, newaddr); + if (c != '\e') { + del_break(newaddr); + } + break; + + case 'p': + printf("print"); + prt_break(); + break; + } + break; + + case 'r': + print_regs(frame); + break; + + case 'I': + printf("Instruction at "); + c = gethex(&newaddr, newaddr); + while (c != '\e') { + printf("\n %08x\t",newaddr); + mdbprintins(*(int *)newaddr, newaddr); + newaddr += 4; + c = cngetc(); + } + break; + + case 'c': + printf("continue\n"); + if (break_find(frame->f_regs[PC]) >= 0) { + ssandrun = 1; + mdbsetsstep(frame); + } + else { + break_insert(); + } + return TRUE; + + case 'S': +#ifdef DEBUG + printf("Stack traceback:\n"); + stacktrace(); +#else + printf("Stack traceback not available\n"); +#endif + break; + case 's': + set_break(frame->f_regs[PC] + 8); + return TRUE; + case ' ': + mdbsetsstep(frame); + return TRUE; + + case 'd': + printf("dump "); + c = gethex(&newaddr, newaddr); + if (c == ',') { + c = gethex(&size, 256); + } + else { + size = 16; + } + if ((c == '\n' || c == '\r') && newaddr != 0) { + dump((unsigned *)newaddr, size); + newaddr += size; + } + break; + + case 'm': + printf("mod "); + c = gethex(&newaddr, newaddr); + while (c == ',') { + c = gethex(&size, 0); + if (c != '\e') + *((unsigned *)newaddr)++ = size; + } + break; + + case 'i': + printf("in-"); + c = cngetc(); + switch (c) { + case 'b': + printf("byte "); + c = gethex(&newaddr, newaddr); + if (c == '\n') { + printf("= %02x", + *(u_char *)newaddr); + } + break; + case 'h': + printf("halfword "); + c = gethex(&newaddr, newaddr); + if (c == '\n') { + printf("= %04x", + *(u_short *)newaddr); + } + break; + case 'w': + printf("word "); + c = gethex(&newaddr, newaddr); + if (c == '\n') { + printf("= %08x", + *(unsigned *)newaddr); + } + break; + } + break; + + case 'o': + printf("out-"); + c = cngetc(); + switch (c) { + case 'b': + printf("byte "); + c = gethex(&newaddr, newaddr); + if (c == ',') { + c = gethex(&size, 0); + if (c == '\n') { + *(u_char *)newaddr = size; + } + } + break; + case 'h': + printf("halfword "); + c = gethex(&newaddr, newaddr); + if (c == ',') { + c = gethex(&size, 0); + if (c == '\n') { + *(u_short *)newaddr = size; + } + } + break; + case 'w': + printf("word "); + c = gethex(&newaddr, newaddr); + if (c == ',') { + c = gethex(&size, 0); + if (c == '\n') { + *(unsigned *)newaddr = size; + } + + } + break; + } + break; + + case 't': + printf("tlb-dump\n"); +#ifdef MIPS3 + mips_dump_tlb(0, 23); + (void)cngetc(); + mips_dump_tlb(24, 47); +#else + mips_dump_tlb(0, 22); + (void)cngetc(); + mips_dump_tlb(23, 45); + (void)cngetc(); + mips_dump_tlb(46, 63); +#endif + break; + + case 'f': + printf("flush-"); + c = cngetc(); + switch (c) { + case 't': + printf("tlb"); + MachTLBFlush(); + break; + + case 'c': + printf("cache"); + MachFlushCache(); + break; + } + break; + + default: + cnputc('\a'); + break; + } + printf("\n# "); + } + return FALSE; +} +#endif