/* Function to handle DTrace traps during probes. See amd64/amd64/trap.c */ int dtrace_trap(struct trapframe *frame, u_int type) { /* * A trap can occur while DTrace executes a probe. Before * executing the probe, DTrace blocks re-scheduling and sets * a flag in its per-cpu flags to indicate that it doesn't * want to fault. On returning from the probe, the no-fault * flag is cleared and finally re-scheduling is enabled. * * Check if DTrace has enabled 'no-fault' mode: */ if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { /* * There are only a couple of trap types that are expected. * All the rest will be handled in the usual way. */ switch (type) { /* Page fault. */ case T_TLB_ST_MISS: case T_ADDR_ERR_ST: case T_TLB_LD_MISS: case T_ADDR_ERR_LD: case T_BUS_ERR_IFETCH: /* Flag a bad address. */ cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; cpu_core[curcpu].cpuc_dtrace_illval = frame->badvaddr; /* * Offset the instruction pointer to the instruction * following the one causing the fault. */ if (DELAYBRANCH(frame->cause)) /* Check BD bit */ { /* XXX: check MipsEmulateBranch on MIPS64 frame->pc = MipsEmulateBranch(frame, frame->pc, 0, 0); */ panic("%s: delay slot at %jx, badvaddr = %jx\n", __func__, (intmax_t)frame->pc, (intmax_t)frame->badvaddr); } else frame->pc += sizeof(int); return (1); default: /* Handle all other traps in the usual way. */ break; } } /* Handle the trap in the usual way. */ return (0); }
void EMULNAME(syscall_fancy)(struct proc *p, u_int status, u_int cause, u_int opc) { struct frame *frame = (struct frame *)p->p_md.md_regs; register_t *args, copyargs[8]; register_t *rval; #if _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN register_t copyrval[2]; #endif mips_reg_t ov0; size_t code, numsys, nsaved, nargs; const struct sysent *callp; int error; uvmexp.syscalls++; if (DELAYBRANCH(cause)) frame->f_regs[PC] = MachEmulateBranch(frame, opc, 0, 0); else frame->f_regs[PC] = opc + sizeof(int); callp = p->p_emul->e_sysent; numsys = p->p_emul->e_nsysent; ov0 = code = frame->f_regs[V0] - SYSCALL_SHIFT; switch (code) { case SYS_syscall: case SYS___syscall: args = copyargs; if (code == SYS_syscall) { /* * Code is first argument, followed by actual args. */ code = frame->f_regs[A0] - SYSCALL_SHIFT; args[0] = frame->f_regs[A1]; args[1] = frame->f_regs[A2]; args[2] = frame->f_regs[A3]; nsaved = 3; } else { /* * 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] - SYSCALL_SHIFT; args[0] = frame->f_regs[A2]; args[1] = frame->f_regs[A3]; nsaved = 2; } if (code >= p->p_emul->e_nsysent) callp += p->p_emul->e_nosys; else callp += code; nargs = callp->sy_argsize / sizeof(register_t); if (nargs > nsaved) { error = copyin( ((register_t *)(vaddr_t)frame->f_regs[SP] + 4), (args + nsaved), (nargs - nsaved) * sizeof(register_t)); if (error) goto bad; } break; default: if (code >= p->p_emul->e_nsysent) callp += p->p_emul->e_nosys; else callp += code; nargs = callp->sy_narg; if (nargs < 5) { #if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 args = (register_t *)&frame->f_regs[A0]; #elif _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN args = copyargs; args[0] = frame->f_regs[A0]; args[1] = frame->f_regs[A1]; args[2] = frame->f_regs[A2]; args[3] = frame->f_regs[A3]; #else # error syscall not implemented for current MIPS ABI #endif } else { args = copyargs; error = copyin( ((register_t *)(vaddr_t)frame->f_regs[SP] + 4), (©args[4]), (nargs - 4) * sizeof(register_t)); if (error) goto bad; args[0] = frame->f_regs[A0]; args[1] = frame->f_regs[A1]; args[2] = frame->f_regs[A2]; args[3] = frame->f_regs[A3]; } break; } #ifdef SYSCALL_DEBUG scdebug_call(p, code, args); #endif #ifdef KTRACE if (KTRPOINT(p, KTR_SYSCALL)) ktrsyscall(p, code, callp->sy_argsize, args); #endif #if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 rval = (register_t *)&frame->f_regs[V0]; rval[0] = 0; /* rval[1] already has V1 */ #elif _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN rval = copyrval; rval[0] = 0; rval[1] = frame->f_regs[V1]; #endif error = (*callp->sy_call)(p, args, rval); switch (error) { case 0: #if _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN frame->f_regs[V0] = rval[0]; frame->f_regs[V1] = rval[1]; #endif frame->f_regs[A3] = 0; break; case ERESTART: frame->f_regs[V0] = ov0; /* restore syscall code */ frame->f_regs[PC] = opc; break; case EJUSTRETURN: break; /* nothing to do */ default: bad: if (p->p_emul->e_errno) error = p->p_emul->e_errno[error]; frame->f_regs[V0] = error; frame->f_regs[A3] = 1; break; } #ifdef SYSCALL_DEBUG scdebug_ret(p, code, error, rval); #endif userret(p); #ifdef KTRACE if (KTRPOINT(p, KTR_SYSRET)) ktrsysret(p, code, error, rval[0]); #endif }
static int cheriabi_fetch_syscall_args(struct thread *td, struct syscall_args *sa) { struct trapframe *locr0 = td->td_frame; /* aka td->td_pcb->pcv_regs */ struct sysentvec *se; #ifdef OLD_ARG_HANDLING register_t intargs[8]; uintptr_t ptrargs[8]; u_int tag; int i, isaved, psaved, curint, curptr, nintargs, nptrargs; #endif int error; error = 0; bzero(sa->args, sizeof(sa->args)); /* compute next PC after syscall instruction */ td->td_pcb->pcb_tpc = sa->trapframe->pc; /* Remember if restart */ if (DELAYBRANCH(sa->trapframe->cause)) /* Check BD bit */ locr0->pc = MipsEmulateBranch(locr0, sa->trapframe->pc, 0, 0); else locr0->pc += sizeof(int); sa->code = locr0->v0; se = td->td_proc->p_sysent; if (se->sv_mask) sa->code &= se->sv_mask; if (sa->code >= se->sv_size) sa->callp = &se->sv_table[0]; else sa->callp = &se->sv_table[sa->code]; sa->narg = sa->callp->sy_narg; #ifndef OLD_ARG_HANDLING error = cheriabi_dispatch_fill_uap(td, sa->code, sa->args); #else intargs[0] = locr0->a0; intargs[1] = locr0->a1; intargs[2] = locr0->a2; intargs[3] = locr0->a3; intargs[4] = locr0->a4; intargs[5] = locr0->a5; intargs[6] = locr0->a6; intargs[7] = locr0->a7; isaved = 8; #if defined(CPU_CHERI_CHERI0) || defined (CPU_CHERI_CHERI8) || defined(CPU_CHERI_CHERI16) #error CHERIABI does not support fewer than 8 argument registers #endif /* * XXXBD: We should ideally use a user capability rather than $kdc * to generate the pointers, but then we have to answer: which one? * * XXXRW: The kernel cannot distinguish between pointers with tags vs. * untagged (possible) integers, which is problematic when a * system-call argument is an intptr_t. We used to just use CToPtr * here, but this caused untagged integer arguments to be lost. Now * we pick one of CToPtr and CToInt based on the tag -- but this is * not really ideal. Instead, we'd prefer that the kernel could * differentiate between the two explicitly using tagged capabilities, * which we're not yet ready to do. */ CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c3, 0); CHERI_CGETTAG(tag, CHERI_CR_CTEMP0); if (tag) CHERI_CTOPTR(ptrargs[0], CHERI_CR_CTEMP0, CHERI_CR_KDC); else CHERI_CTOINT(ptrargs[0], CHERI_CR_CTEMP0); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c4, 0); CHERI_CGETTAG(tag, CHERI_CR_CTEMP0); if (tag) CHERI_CTOPTR(ptrargs[1], CHERI_CR_CTEMP0, CHERI_CR_KDC); else CHERI_CTOINT(ptrargs[1], CHERI_CR_CTEMP0); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c5, 0); CHERI_CGETTAG(tag, CHERI_CR_CTEMP0); if (tag) CHERI_CTOPTR(ptrargs[2], CHERI_CR_CTEMP0, CHERI_CR_KDC); else CHERI_CTOINT(ptrargs[2], CHERI_CR_CTEMP0); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c6, 0); CHERI_CGETTAG(tag, CHERI_CR_CTEMP0); if (tag) CHERI_CTOPTR(ptrargs[3], CHERI_CR_CTEMP0, CHERI_CR_KDC); else CHERI_CTOINT(ptrargs[3], CHERI_CR_CTEMP0); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c7, 0); CHERI_CGETTAG(tag, CHERI_CR_CTEMP0); if (tag) CHERI_CTOPTR(ptrargs[4], CHERI_CR_CTEMP0, CHERI_CR_KDC); else CHERI_CTOINT(ptrargs[4], CHERI_CR_CTEMP0); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c8, 0); CHERI_CGETTAG(tag, CHERI_CR_CTEMP0); if (tag) CHERI_CTOPTR(ptrargs[5], CHERI_CR_CTEMP0, CHERI_CR_KDC); else CHERI_CTOINT(ptrargs[5], CHERI_CR_CTEMP0); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c9, 0); CHERI_CGETTAG(tag, CHERI_CR_CTEMP0); if (tag) CHERI_CTOPTR(ptrargs[6], CHERI_CR_CTEMP0, CHERI_CR_KDC); else CHERI_CTOINT(ptrargs[6], CHERI_CR_CTEMP0); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c10, 0); CHERI_CGETTAG(tag, CHERI_CR_CTEMP0); if (tag) CHERI_CTOPTR(ptrargs[7], CHERI_CR_CTEMP0, CHERI_CR_KDC); else CHERI_CTOINT(ptrargs[7], CHERI_CR_CTEMP0); psaved = 8; #ifdef TRAP_DEBUG if (trap_debug) printf("SYSCALL #%d pid:%u\n", sa->code, td->td_proc->p_pid); #endif nptrargs = bitcount(CHERIABI_SYS_argmap[sa->code].sam_ptrmask); nintargs = sa->narg - nptrargs; KASSERT(nintargs <= isaved, ("SYSCALL #%u pid:%u, nintargs (%u) > isaved (%u).\n", sa->code, td->td_proc->p_pid, nintargs, isaved)); KASSERT(nptrargs <= psaved, ("SYSCALL #%u pid:%u, nptrargs (%u) > psaved (%u).\n", sa->code, td->td_proc->p_pid, nptrargs, psaved)); /* * Check each argument to see if it is a pointer and pop an argument * off the appropriate list. */ curint = curptr = 0; for (i = 0; i < sa->narg; i++) sa->args[i] = (CHERIABI_SYS_argmap[sa->code].sam_ptrmask & 1 << i) ? ptrargs[curptr++] : intargs[curint++]; #endif /* OLD_ARG_HANDLING */ td->td_retval[0] = 0; td->td_retval[1] = locr0->v1; return (error); }
/* * Trap is called from locore to handle most types of processor traps. */ void trap(unsigned int status, unsigned int cause, vaddr_t vaddr, vaddr_t opc, struct trapframe *frame) { int type; struct lwp *l = curlwp; struct proc *p = curproc; vm_prot_t ftype; ksiginfo_t ksi; struct frame *fp; extern void fswintrberr(void); KSI_INIT_TRAP(&ksi); uvmexp.traps++; if ((type = TRAPTYPE(cause)) >= LENGTH(trap_type)) panic("trap: unknown trap type %d", type); if (USERMODE(status)) { type |= T_USER; LWP_CACHE_CREDS(l, p); } /* Enable interrupts just at it was before the trap. */ _splset(status & AVR32_STATUS_IMx); switch (type) { default: dopanic: (void)splhigh(); printf("trap: %s in %s mode\n", trap_type[TRAPTYPE(cause)], USERMODE(status) ? "user" : "kernel"); printf("status=0x%x, cause=0x%x, epc=%#lx, vaddr=%#lx\n", status, cause, opc, vaddr); if (curlwp != NULL) { fp = (struct frame *)l->l_md.md_regs; printf("pid=%d cmd=%s usp=0x%x ", p->p_pid, p->p_comm, (int)fp->f_regs[_R_SP]); } else printf("curlwp == NULL "); printf("ksp=%p\n", &status); #if defined(DDB) kdb_trap(type, (mips_reg_t *) frame); /* XXX force halt XXX */ #elif defined(KGDB) { struct frame *f = (struct frame *)&ddb_regs; extern mips_reg_t kgdb_cause, kgdb_vaddr; kgdb_cause = cause; kgdb_vaddr = vaddr; /* * init global ddb_regs, used in db_interface.c routines * shared between ddb and gdb. Send ddb_regs to gdb so * that db_machdep.h macros will work with it, and * allow gdb to alter the PC. */ db_set_ddb_regs(type, (mips_reg_t *) frame); PC_BREAK_ADVANCE(f); if (kgdb_trap(type, &ddb_regs)) { ((mips_reg_t *)frame)[21] = f->f_regs[_R_PC]; return; } } #else panic("trap: dopanic: notyet"); #endif /*NOTREACHED*/ case T_TLB_MOD: panic("trap: T_TLB_MOD: notyet"); #if notyet if (KERNLAND(vaddr)) { pt_entry_t *pte; unsigned entry; paddr_t pa; pte = kvtopte(vaddr); entry = pte->pt_entry; if (!avr32_pte_v(entry) /*|| (entry & mips_pg_m_bit())*/) { panic("ktlbmod: invalid pte"); } if (entry & avr32_pte_ropage_bit()) { /* write to read only page in the kernel */ ftype = VM_PROT_WRITE; goto kernelfault; } entry |= mips_pg_m_bit(); /* XXXAVR32 Do it on tlbarlo/ tlbarhi? */ pte->pt_entry = entry; vaddr &= ~PGOFSET; MachTLBUpdate(vaddr, entry); pa = avr32_tlbpfn_to_paddr(entry); if (!IS_VM_PHYSADDR(pa)) { printf("ktlbmod: va %#lx pa %#llx\n", vaddr, (long long)pa); panic("ktlbmod: unmanaged page"); } pmap_set_modified(pa); return; /* KERN */ } /*FALLTHROUGH*/ #endif case T_TLB_MOD+T_USER: panic("trap: T_TLB_MOD+T_USER: notyet"); #if notyet { pt_entry_t *pte; unsigned entry; paddr_t pa; pmap_t pmap; 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; if (!avr32_pte_v(entry)) panic("utlbmod: invalid pte"); if (entry & avr32_pte_ropage_bit()) { /* write to read only page */ ftype = VM_PROT_WRITE; goto pagefault; } /* entry |= mips_pg_m_bit(); XXXAVR32 Do it on tlbarlo/ tlbarhi? */ pte->pt_entry = entry; vaddr = (vaddr & ~PGOFSET) | (pmap->pm_asid << AVR32_TLB_PID_SHIFT); MachTLBUpdate(vaddr, entry); pa = avr32_tlbpfn_to_paddr(entry); if (!IS_VM_PHYSADDR(pa)) { printf("utlbmod: va %#lx pa %#llx\n", vaddr, (long long)pa); panic("utlbmod: unmanaged page"); } pmap_set_modified(pa); if (type & T_USER) userret(l); return; /* GEN */ } #endif case T_TLB_LD_MISS: panic("trap: T_TLB_LD_MISS: notyet"); case T_TLB_ST_MISS: ftype = (type == T_TLB_LD_MISS) ? VM_PROT_READ : VM_PROT_WRITE; if (KERNLAND(vaddr)) goto kernelfault; panic("trap: T_TLB_ST_MISS: notyet"); #if notyet /* * It is an error for the kernel to access user space except * through the copyin/copyout routines. */ if (l == NULL || l->l_addr->u_pcb.pcb_onfault == NULL) goto dopanic; /* check for fuswintr() or suswintr() getting a page fault */ if (l->l_addr->u_pcb.pcb_onfault == (void *)fswintrberr) { frame->tf_regs[TF_EPC] = (int)fswintrberr; return; /* KERN */ } goto pagefault; #endif case T_TLB_LD_MISS+T_USER: panic("trap: T_TLB_LD_MISS+T_USER: notyet"); #if notyet ftype = VM_PROT_READ; goto pagefault; #endif case T_TLB_ST_MISS+T_USER: panic("trap: T_TLB_ST_MISS+T_USER: notyet"); #if notyet ftype = VM_PROT_WRITE; #endif pagefault: ; { vaddr_t va; struct vmspace *vm; struct vm_map *map; int rv; vm = p->p_vmspace; map = &vm->vm_map; va = trunc_page(vaddr); if ((l->l_flag & LW_SA) && (~l->l_pflag & LP_SA_NOBLOCK)) { l->l_savp->savp_faultaddr = (vaddr_t)vaddr; l->l_pflag |= LP_SA_PAGEFAULT; } if (p->p_emul->e_fault) rv = (*p->p_emul->e_fault)(p, va, ftype); else rv = uvm_fault(map, va, ftype); #ifdef VMFAULT_TRACE printf( "uvm_fault(%p (pmap %p), %lx (0x%x), %d) -> %d at pc %p\n", map, vm->vm_map.pmap, va, vaddr, ftype, rv, (void*)opc); #endif /* * If this was a stack access we keep track of the maximum * accessed stack size. Also, if vm_fault gets a protection * failure it is due to accessing the stack region outside * the current limit and we need to reflect that as an access * error. */ if ((void *)va >= vm->vm_maxsaddr) { if (rv == 0){ uvm_grow(p, va); } else if (rv == EACCES) rv = EFAULT; } l->l_pflag &= ~LP_SA_PAGEFAULT; if (rv == 0) { if (type & T_USER) { userret(l); } return; /* GEN */ } if ((type & T_USER) == 0) goto copyfault; if (rv == ENOMEM) { printf("UVM: pid %d (%s), uid %d killed: out of swap\n", p->p_pid, p->p_comm, l->l_cred ? kauth_cred_geteuid(l->l_cred) : (uid_t) -1); ksi.ksi_signo = SIGKILL; ksi.ksi_code = 0; } else { if (rv == EACCES) { ksi.ksi_signo = SIGBUS; ksi.ksi_code = BUS_OBJERR; } else { ksi.ksi_signo = SIGSEGV; ksi.ksi_code = SEGV_MAPERR; } } ksi.ksi_trap = type & ~T_USER; ksi.ksi_addr = (void *)vaddr; break; /* SIGNAL */ } kernelfault: ; { vaddr_t va; int rv; va = trunc_page(vaddr); rv = uvm_fault(kernel_map, va, ftype); if (rv == 0) 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: panic("trap: copyfault: notyet"); #if notyet if (l == NULL || l->l_addr->u_pcb.pcb_onfault == NULL) goto dopanic; frame->tf_regs[TF_EPC] = (intptr_t)l->l_addr->u_pcb.pcb_onfault; return; /* KERN */ #endif #if notyet 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 */ ksi.ksi_trap = type & ~T_USER; ksi.ksi_signo = SIGSEGV; /* XXX */ ksi.ksi_addr = (void *)vaddr; ksi.ksi_code = SEGV_MAPERR; /* XXX */ break; /* SIGNAL */ case T_BREAK: panic("trap: T_BREAK: notyet"); #if defined(DDB) kdb_trap(type, (avr32_reg_t *) frame); return; /* KERN */ #elif defined(KGDB) { struct frame *f = (struct frame *)&ddb_regs; extern avr32_reg_t kgdb_cause, kgdb_vaddr; kgdb_cause = cause; kgdb_vaddr = vaddr; /* * init global ddb_regs, used in db_interface.c routines * shared between ddb and gdb. Send ddb_regs to gdb so * that db_machdep.h macros will work with it, and * allow gdb to alter the PC. */ db_set_ddb_regs(type, (avr32_reg_t *) frame); PC_BREAK_ADVANCE(f); if (!kgdb_trap(type, &ddb_regs)) printf("kgdb: ignored %s\n", trap_type[TRAPTYPE(cause)]); else ((avr32_reg_t *)frame)[21] = f->f_regs[_R_PC]; return; } #else goto dopanic; #endif case T_BREAK+T_USER: { vaddr_t va; uint32_t instr; int rv; /* compute address of break instruction */ va = (DELAYBRANCH(cause)) ? opc + sizeof(int) : opc; /* read break instruction */ instr = fuiword((void *)va); if (l->l_md.md_ss_addr != va || instr != MIPS_BREAK_SSTEP) { ksi.ksi_trap = type & ~T_USER; ksi.ksi_signo = SIGTRAP; ksi.ksi_addr = (void *)va; ksi.ksi_code = TRAP_TRACE; break; } /* * Restore original instruction and clear BP */ rv = suiword((void *)va, l->l_md.md_ss_instr); if (rv < 0) { vaddr_t sa, ea; sa = trunc_page(va); ea = round_page(va + sizeof(int) - 1); rv = uvm_map_protect(&p->p_vmspace->vm_map, sa, ea, VM_PROT_ALL, false); if (rv == 0) { rv = suiword((void *)va, l->l_md.md_ss_instr); (void)uvm_map_protect(&p->p_vmspace->vm_map, sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, false); } } mips_icache_sync_all(); /* XXXJRT -- necessary? */ mips_dcache_wbinv_all(); /* XXXJRT -- necessary? */ if (rv < 0) printf("Warning: can't restore instruction at 0x%lx: 0x%x\n", l->l_md.md_ss_addr, l->l_md.md_ss_instr); l->l_md.md_ss_addr = 0; ksi.ksi_trap = type & ~T_USER; ksi.ksi_signo = SIGTRAP; ksi.ksi_addr = (void *)va; ksi.ksi_code = TRAP_BRKPT; break; /* SIGNAL */ } case T_RES_INST+T_USER: case T_COP_UNUSABLE+T_USER: #if !defined(SOFTFLOAT) && !defined(NOFPU) if ((cause & MIPS_CR_COP_ERR) == 0x10000000) { struct frame *f; f = (struct frame *)l->l_md.md_regs; savefpregs(fpcurlwp); /* yield FPA */ loadfpregs(l); /* load FPA */ fpcurlwp = l; l->l_md.md_flags |= MDP_FPUSED; f->f_regs[_R_SR] |= MIPS_SR_COP_1_BIT; } else #endif { MachEmulateInst(status, cause, opc, l->l_md.md_regs); } userret(l); return; /* GEN */ case T_FPE+T_USER: panic ("trap: T_FPE+T_USER: notyet"); #if defined(SOFTFLOAT) MachEmulateInst(status, cause, opc, l->l_md.md_regs); #elif !defined(NOFPU) MachFPTrap(status, cause, opc, l->l_md.md_regs); #endif userret(l); return; /* GEN */ case T_OVFLOW+T_USER: case T_TRAP+T_USER: ksi.ksi_trap = type & ~T_USER; ksi.ksi_signo = SIGFPE; fp = (struct frame *)l->l_md.md_regs; ksi.ksi_addr = (void *)fp->f_regs[_R_PC]; ksi.ksi_code = FPE_FLTOVF; /* XXX */ break; /* SIGNAL */ #endif } panic("trap: post-switch: notyet"); #if notyet fp = (struct frame *)l->l_md.md_regs; fp->f_regs[_R_CAUSE] = cause; fp->f_regs[_R_BADVADDR] = vaddr; (*p->p_emul->e_trapsignal)(l, &ksi); if ((type & T_USER) == 0) panic("trapsignal"); userret(l); #endif return; }
static int cheriabi_fetch_syscall_args(struct thread *td, struct syscall_args *sa) { struct trapframe *locr0 = td->td_frame; /* aka td->td_pcb->pcv_regs */ struct cheri_frame *capreg = &td->td_pcb->pcb_cheriframe; register_t intargs[8]; uintptr_t ptrargs[8]; struct sysentvec *se; int error, i, isaved, psaved, curint, curptr, nintargs, nptrargs; error = 0; bzero(sa->args, sizeof(sa->args)); /* compute next PC after syscall instruction */ td->td_pcb->pcb_tpc = sa->trapframe->pc; /* Remember if restart */ if (DELAYBRANCH(sa->trapframe->cause)) /* Check BD bit */ locr0->pc = MipsEmulateBranch(locr0, sa->trapframe->pc, 0, 0); else locr0->pc += sizeof(int); sa->code = locr0->v0; switch (sa->code) { case CHERIABI_SYS___syscall: case CHERIABI_SYS_syscall: /* * This is an indirect syscall, in which the code is the first * argument. */ sa->code = locr0->a0; intargs[0] = locr0->a1; intargs[1] = locr0->a2; intargs[2] = locr0->a3; intargs[3] = locr0->a4; intargs[4] = locr0->a5; intargs[5] = locr0->a6; intargs[6] = locr0->a7; isaved = 7; break; default: /* * A direct syscall, arguments are just parameters to the syscall. */ intargs[0] = locr0->a0; intargs[1] = locr0->a1; intargs[2] = locr0->a2; intargs[3] = locr0->a3; intargs[4] = locr0->a4; intargs[5] = locr0->a5; intargs[6] = locr0->a6; intargs[7] = locr0->a7; isaved = 8; break; } #if defined(CPU_CHERI_CHERI0) || defined (CPU_CHERI_CHERI8) || defined(CPU_CHERI_CHERI16) #error CHERIABI does not support fewer than 8 argument registers #endif /* * XXXBD: we should idealy use a user capability rather than KDC * to generate the pointers, but then we have to answer: which one? */ CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &capreg->cf_c3, 0); CHERI_CTOPTR(ptrargs[0], CHERI_CR_CTEMP0, CHERI_CR_KDC); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &capreg->cf_c4, 0); CHERI_CTOPTR(ptrargs[1], CHERI_CR_CTEMP0, CHERI_CR_KDC); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &capreg->cf_c5, 0); CHERI_CTOPTR(ptrargs[2], CHERI_CR_CTEMP0, CHERI_CR_KDC); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &capreg->cf_c6, 0); CHERI_CTOPTR(ptrargs[3], CHERI_CR_CTEMP0, CHERI_CR_KDC); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &capreg->cf_c7, 0); CHERI_CTOPTR(ptrargs[4], CHERI_CR_CTEMP0, CHERI_CR_KDC); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &capreg->cf_c8, 0); CHERI_CTOPTR(ptrargs[5], CHERI_CR_CTEMP0, CHERI_CR_KDC); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &capreg->cf_c9, 0); CHERI_CTOPTR(ptrargs[6], CHERI_CR_CTEMP0, CHERI_CR_KDC); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &capreg->cf_c10, 0); CHERI_CTOPTR(ptrargs[7], CHERI_CR_CTEMP0, CHERI_CR_KDC); psaved = 8; #ifdef TRAP_DEBUG if (trap_debug) printf("SYSCALL #%d pid:%u\n", sa->code, td->td_proc->p_pid); #endif se = td->td_proc->p_sysent; /* * XXX * Shouldn't this go before switching on the code? */ if (se->sv_mask) sa->code &= se->sv_mask; if (sa->code >= se->sv_size) sa->callp = &se->sv_table[0]; else sa->callp = &se->sv_table[sa->code]; sa->narg = sa->callp->sy_narg; nptrargs = bitcount(CHERIABI_SYS_argmap[sa->code].sam_ptrmask); nintargs = sa->narg - nintargs; KASSERT(nintargs <= isaved, ("SYSCALL #%u pid:%u, nintargs (%u) > isaved (%u).\n", sa->code, td->td_proc->p_pid, nintargs, isaved)); KASSERT(nptrargs <= psaved, ("SYSCALL #%u pid:%u, nptrargs (%u) > psaved (%u).\n", sa->code, td->td_proc->p_pid, nptrargs, psaved)); /* * Check each argument to see if it is a pointer and pop an argument * off the appropriate list. */ curint = curptr = 0; for (i = 0; i < sa->narg; i++) sa->args[i] = (CHERIABI_SYS_argmap[sa->code].sam_ptrmask & 1 << i) ? ptrargs[curptr++] : intargs[curint++]; td->td_retval[0] = 0; td->td_retval[1] = locr0->v1; return (error); }