#include "use_isa.h"
#include "opt_ddb.h"
#include "opt_ktrace.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/pioctl.h>
#include <sys/kernel.h>
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
#include <sys/signal2.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
#include <sys/vmmeter.h>
#include <sys/malloc.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
#include <sys/ktr.h>
#include <sys/vkernel.h>
#include <sys/sysmsg.h>
#include <sys/vmspace.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <sys/lock.h>
#include <vm/pmap.h>
#include <vm/vm_kern.h>
#include <vm/vm_map.h>
#include <vm/vm_page.h>
#include <vm/vm_extern.h>
#include <machine/cpu.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
#include <machine/smp.h>
#include <machine/tss.h>
#include <machine/globaldata.h>
#include <ddb/ddb.h>
#include <sys/msgport2.h>
#include <sys/thread2.h>
#include <sys/mplock2.h>
int (*pmath_emulate) (struct trapframe *);
static int trap_pfault (struct trapframe *, int, vm_offset_t);
static void trap_fatal (struct trapframe *, int, vm_offset_t);
void dblfault_handler (void);
static struct krate segfltrate = { 1 };
#if 0
extern inthand_t IDTVEC(syscall);
#endif
#define MAX_TRAP_MSG 30
static char *trap_msg[] = {
"",
"privileged instruction fault",
"",
"breakpoint instruction fault",
"",
"",
"arithmetic trap",
"system forced exception",
"",
"general protection fault",
"trace trap",
"",
"page fault",
"",
"alignment fault",
"",
"",
"",
"integer divide fault",
"non-maskable interrupt trap",
"overflow trap",
"FPU bounds check fault",
"FPU device not available",
"double fault",
"FPU operand fetch fault",
"invalid TSS fault",
"segment not present fault",
"stack fault",
"machine check trap",
"SIMD floating-point exception",
"reserved (unknown) fault",
};
#ifdef DDB
static int ddb_on_nmi = 1;
SYSCTL_INT(_machdep, OID_AUTO, ddb_on_nmi, CTLFLAG_RW,
&ddb_on_nmi, 0, "Go to DDB on NMI");
#endif
static int panic_on_nmi = 1;
SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RW,
&panic_on_nmi, 0, "Panic on NMI");
static __inline void
userenter(struct thread *curtd, struct proc *curp)
{
struct ucred *ocred;
struct ucred *ncred;
curtd->td_release = lwkt_passive_release;
if (curtd->td_ucred != curp->p_ucred) {
ncred = crhold(curp->p_ucred);
ocred = curtd->td_ucred;
curtd->td_ucred = ncred;
if (ocred)
crfree(ocred);
}
}
static void
userret(struct lwp *lp, struct trapframe *frame, int sticks)
{
struct proc *p = lp->lwp_proc;
int sig;
int ptok;
if (p->p_flags & P_PROFIL) {
addupc_task(p, frame->tf_rip,
(u_int)((int)lp->lwp_thread->td_sticks - sticks));
}
recheck:
if (lp->lwp_mpflags & LWP_MP_URETMASK)
lwpuserret(lp);
if (STOPLWP(p, lp)) {
lwkt_gettoken(&p->p_token);
tstop();
lwkt_reltoken(&p->p_token);
goto recheck;
}
if (p->p_flags & (P_SIGVTALRM | P_SIGPROF)) {
lwkt_gettoken(&p->p_token);
if (p->p_flags & P_SIGVTALRM) {
p->p_flags &= ~P_SIGVTALRM;
ksignal(p, SIGVTALRM);
}
if (p->p_flags & P_SIGPROF) {
p->p_flags &= ~P_SIGPROF;
ksignal(p, SIGPROF);
}
lwkt_reltoken(&p->p_token);
goto recheck;
}
if ((sig = CURSIG_LCK_TRACE(lp, &ptok)) != 0) {
postsig(sig, ptok);
goto recheck;
}
if (lp->lwp_flags & LWP_OLDMASK) {
lp->lwp_flags &= ~LWP_OLDMASK;
lp->lwp_sigmask = lp->lwp_oldsigmask;
goto recheck;
}
}
static __inline void
userexit(struct lwp *lp)
{
struct thread *td = lp->lwp_thread;
while (STOPLWP(lp->lwp_proc, lp)) {
lwkt_gettoken(&lp->lwp_proc->p_token);
tstop();
lwkt_reltoken(&lp->lwp_proc->p_token);
}
lwkt_passive_recover(td);
lp->lwp_proc->p_usched->acquire_curproc(lp);
}
#if !defined(KTR_KERNENTRY)
#define KTR_KERNENTRY KTR_ALL
#endif
KTR_INFO_MASTER(kernentry);
KTR_INFO(KTR_KERNENTRY, kernentry, trap, 0,
"TRAP(pid %hd, tid %hd, trapno %ld, eva %lu)",
pid_t pid, lwpid_t tid, register_t trapno, vm_offset_t eva);
KTR_INFO(KTR_KERNENTRY, kernentry, trap_ret, 0, "TRAP_RET(pid %hd, tid %hd)",
pid_t pid, lwpid_t tid);
KTR_INFO(KTR_KERNENTRY, kernentry, syscall, 0, "SYSC(pid %hd, tid %hd, nr %ld)",
pid_t pid, lwpid_t tid, register_t trapno);
KTR_INFO(KTR_KERNENTRY, kernentry, syscall_ret, 0, "SYSRET(pid %hd, tid %hd, err %d)",
pid_t pid, lwpid_t tid, int err);
KTR_INFO(KTR_KERNENTRY, kernentry, fork_ret, 0, "FORKRET(pid %hd, tid %hd)",
pid_t pid, lwpid_t tid);
void
user_trap(struct trapframe *frame)
{
struct globaldata *gd = mycpu;
struct thread *td = gd->gd_curthread;
struct lwp *lp = td->td_lwp;
struct proc *p;
int sticks = 0;
int i = 0, ucode = 0, type, code;
#ifdef INVARIANTS
int crit_count = td->td_critcount;
lwkt_tokref_t curstop = td->td_toks_stop;
#endif
vm_offset_t eva;
p = td->td_proc;
if (frame->tf_trapno == T_PAGEFLT)
eva = frame->tf_addr;
else
eva = 0;
if (frame->tf_trapno == T_FAST_SYSCALL) {
syscall2(frame);
return;
}
KTR_LOG(kernentry_trap, lp->lwp_proc->p_pid, lp->lwp_tid,
frame->tf_trapno, eva);
#ifdef DDB
if (db_active) {
eva = (frame->tf_trapno == T_PAGEFLT ? rcr2() : 0);
++gd->gd_trap_nesting_level;
trap_fatal(frame, TRUE, eva);
--gd->gd_trap_nesting_level;
goto out2;
}
#endif
type = frame->tf_trapno;
code = frame->tf_err;
userenter(td, p);
sticks = (int)td->td_sticks;
lp->lwp_md.md_regs = frame;
switch (type) {
case T_PRIVINFLT:
i = SIGILL;
ucode = ILL_PRVOPC;
break;
case T_BPTFLT:
case T_TRCTRAP:
frame->tf_rflags &= ~PSL_T;
i = SIGTRAP;
ucode = (type == T_TRCTRAP ? TRAP_TRACE : TRAP_BRKPT);
break;
case T_ARITHTRAP:
ucode = code;
i = SIGFPE;
break;
case T_ASTFLT:
mycpu->gd_cnt.v_soft++;
if (mycpu->gd_reqflags & RQF_AST_OWEUPC) {
atomic_clear_int(&mycpu->gd_reqflags, RQF_AST_OWEUPC);
addupc_task(p, p->p_prof.pr_addr, p->p_prof.pr_ticks);
}
goto out;
case T_PROTFLT:
case T_STKFLT:
#if 0
if (frame->tf_eflags & PSL_VM) {
i = vm86_emulate((struct vm86frame *)frame);
if (i == 0)
goto out;
break;
}
#endif
case T_SEGNPFLT:
case T_TSSFLT:
case T_DOUBLEFLT:
default:
i = SIGBUS;
ucode = code + BUS_SEGM_FAULT ;
break;
case T_PAGEFLT:
i = trap_pfault(frame, TRUE, eva);
if (i == -1 || i == 0)
goto out;
if (i == SIGSEGV)
ucode = SEGV_MAPERR;
else {
i = SIGSEGV;
ucode = SEGV_ACCERR;
}
break;
case T_DIVIDE:
ucode = FPE_INTDIV;
i = SIGFPE;
break;
#if NISA > 0
case T_NMI:
if (isa_nmi(code) == 0) {
#ifdef DDB
if (ddb_on_nmi) {
kprintf ("NMI ... going to debugger\n");
kdb_trap(type, 0, frame);
}
#endif
goto out2;
} else if (panic_on_nmi)
panic("NMI indicates hardware failure");
break;
#endif
case T_OFLOW:
ucode = FPE_INTOVF;
i = SIGFPE;
break;
case T_BOUND:
ucode = FPE_FLTSUB;
i = SIGFPE;
break;
case T_DNA:
if (lp->lwp_vkernel && lp->lwp_vkernel->ve &&
(td->td_pcb->pcb_flags & FP_VIRTFP)
) {
npxdna(frame);
break;
}
if (npxdna(frame)) {
gd->gd_cnt.v_trap++;
goto out;
}
if (!pmath_emulate) {
i = SIGFPE;
ucode = FPE_FPU_NP_TRAP;
break;
}
i = (*pmath_emulate)(frame);
if (i == 0) {
if (!(frame->tf_rflags & PSL_T))
goto out2;
frame->tf_rflags &= ~PSL_T;
i = SIGTRAP;
}
break;
case T_FPOPFLT:
ucode = T_FPOPFLT;
i = SIGILL;
break;
case T_XMMFLT:
ucode = 0;
i = SIGFPE;
break;
}
if (lp->lwp_vkernel && lp->lwp_vkernel->ve) {
vkernel_trap(lp, frame);
goto out;
}
if (*p->p_sysent->sv_transtrap)
i = (*p->p_sysent->sv_transtrap)(i, type);
trapsignal(lp, i, ucode);
#ifdef DEBUG
if (type <= MAX_TRAP_MSG) {
uprintf("fatal process exception: %s",
trap_msg[type]);
if ((type == T_PAGEFLT) || (type == T_PROTFLT))
uprintf(", fault VA = 0x%lx", (u_long)eva);
uprintf("\n");
}
#endif
out:
userret(lp, frame, sticks);
userexit(lp);
out2: ;
KTR_LOG(kernentry_trap_ret, lp->lwp_proc->p_pid, lp->lwp_tid);
#ifdef INVARIANTS
KASSERT(crit_count == td->td_critcount,
("trap: critical section count mismatch! %d/%d",
crit_count, td->td_pri));
KASSERT(curstop == td->td_toks_stop,
("trap: extra tokens held after trap! %ld/%ld",
curstop - &td->td_toks_base,
td->td_toks_stop - &td->td_toks_base));
#endif
}
void
kern_trap(struct trapframe *frame)
{
struct globaldata *gd = mycpu;
struct thread *td = gd->gd_curthread;
struct lwp *lp;
struct proc *p;
int i = 0, ucode = 0, type, code;
#ifdef INVARIANTS
int crit_count = td->td_critcount;
lwkt_tokref_t curstop = td->td_toks_stop;
#endif
vm_offset_t eva;
lp = td->td_lwp;
p = td->td_proc;
if (frame->tf_trapno == T_PAGEFLT)
eva = frame->tf_addr;
else
eva = 0;
#ifdef DDB
if (db_active) {
++gd->gd_trap_nesting_level;
trap_fatal(frame, FALSE, eva);
--gd->gd_trap_nesting_level;
goto out2;
}
#endif
type = frame->tf_trapno;
code = frame->tf_err;
#if 0
kernel_trap:
#endif
switch (type) {
case T_PAGEFLT:
trap_pfault(frame, FALSE, eva);
goto out2;
case T_DNA:
panic("kernel NPX should not happen");
if (npxdna(frame))
goto out2;
break;
case T_PROTFLT:
case T_SEGNPFLT:
if (mycpu->gd_intr_nesting_level == 0) {
if (td->td_pcb->pcb_onfault) {
frame->tf_rip =
(register_t)td->td_pcb->pcb_onfault;
goto out2;
}
}
break;
case T_TSSFLT:
if (frame->tf_rflags & PSL_NT) {
frame->tf_rflags &= ~PSL_NT;
goto out2;
}
break;
case T_TRCTRAP:
#if 0
if (frame->tf_eip == (int)IDTVEC(syscall)) {
goto out2;
}
if (frame->tf_eip == (int)IDTVEC(syscall) + 1) {
frame->tf_eflags &= ~PSL_T;
goto out2;
}
#endif
#if 0
if (user_dbreg_trap()) {
load_dr6(rdr6() & 0xfffffff0);
goto out2;
}
#endif
case T_BPTFLT:
#ifdef DDB
if (kdb_trap (type, 0, frame))
goto out2;
#endif
break;
case T_DIVIDE:
trap_fatal(frame, FALSE, eva);
goto out2;
case T_NMI:
trap_fatal(frame, FALSE, eva);
goto out2;
case T_SYSCALL80:
case T_FAST_SYSCALL:
goto out2;
}
if (*p->p_sysent->sv_transtrap)
i = (*p->p_sysent->sv_transtrap)(i, type);
gd->gd_cnt.v_trap++;
trapsignal(lp, i, ucode);
#ifdef DEBUG
if (type <= MAX_TRAP_MSG) {
uprintf("fatal process exception: %s",
trap_msg[type]);
if ((type == T_PAGEFLT) || (type == T_PROTFLT))
uprintf(", fault VA = 0x%lx", (u_long)eva);
uprintf("\n");
}
#endif
out2:
;
#ifdef INVARIANTS
KASSERT(crit_count == td->td_critcount,
("trap: critical section count mismatch! %d/%d",
crit_count, td->td_pri));
KASSERT(curstop == td->td_toks_stop,
("trap: extra tokens held after trap! %ld/%ld",
curstop - &td->td_toks_base,
td->td_toks_stop - &td->td_toks_base));
#endif
}
int
trap_pfault(struct trapframe *frame, int usermode, vm_offset_t eva)
{
vm_offset_t va;
struct vmspace *vm = NULL;
vm_map_t map = 0;
int rv = 0;
vm_prot_t ftype;
thread_t td = curthread;
struct lwp *lp = td->td_lwp;
int fault_flags;
va = trunc_page(eva);
if (usermode == FALSE) {
map = kernel_map;
} else {
if (lp != NULL)
vm = lp->lwp_vmspace;
if (vm == NULL)
goto nogo;
map = &vm->vm_map;
}
if (frame->tf_err & PGEX_W)
ftype = VM_PROT_READ | VM_PROT_WRITE;
else if (frame->tf_err & PGEX_I)
ftype = VM_PROT_EXECUTE;
else
ftype = VM_PROT_READ;
if (map != kernel_map) {
PHOLD(lp->lwp_proc);
#if 0
if (!grow_stack (map, va)) {
rv = KERN_FAILURE;
PRELE(lp->lwp_proc);
goto nogo;
}
#endif
fault_flags = 0;
if (usermode)
fault_flags |= VM_FAULT_BURST | VM_FAULT_USERMODE;
if (ftype & VM_PROT_WRITE)
fault_flags |= VM_FAULT_DIRTY;
else
fault_flags |= VM_FAULT_NORMAL;
rv = vm_fault(map, va, ftype, fault_flags);
PRELE(lp->lwp_proc);
} else {
rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
}
if (rv == KERN_SUCCESS)
return (0);
nogo:
if (!usermode) {
if (td->td_gd->gd_intr_nesting_level == 0 &&
td->td_pcb->pcb_onfault) {
frame->tf_rip = (register_t)td->td_pcb->pcb_onfault;
return (0);
}
trap_fatal(frame, usermode, eva);
return (-1);
}
struct proc *p = td->td_proc;
krateprintf(&segfltrate,
"seg-fault accessing address %p "
"rip=%p pid=%d p_comm=%s\n",
(void *)va,
(void *)frame->tf_rip, p->p_pid, p->p_comm);
return((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV);
}
static void
trap_fatal(struct trapframe *frame, int usermode, vm_offset_t eva)
{
int code, type, ss;
long rsp;
code = frame->tf_xflags;
type = frame->tf_trapno;
if (type <= MAX_TRAP_MSG) {
kprintf("\n\nFatal trap %d: %s while in %s mode\n",
type, trap_msg[type],
(usermode ? "user" : "kernel"));
}
kprintf("cpuid = %d\n", mycpu->gd_cpuid);
if (type == T_PAGEFLT) {
kprintf("fault virtual address = %p\n", (void *)eva);
kprintf("fault code = %s %s, %s\n",
usermode ? "user" : "supervisor",
code & PGEX_W ? "write" : "read",
code & PGEX_P ? "protection violation" : "page not present");
}
kprintf("instruction pointer = 0x%lx:0x%lx\n",
frame->tf_cs & 0xffff, frame->tf_rip);
if (usermode) {
ss = frame->tf_ss & 0xffff;
rsp = frame->tf_rsp;
} else {
ss = GSEL(GDATA_SEL, SEL_KPL);
rsp = (long)&frame->tf_rsp;
}
kprintf("stack pointer = 0x%x:0x%lx\n", ss, rsp);
kprintf("frame pointer = 0x%x:0x%lx\n", ss, frame->tf_rbp);
kprintf("processor eflags = ");
if (frame->tf_rflags & PSL_T)
kprintf("trace trap, ");
if (frame->tf_rflags & PSL_I)
kprintf("interrupt enabled, ");
if (frame->tf_rflags & PSL_NT)
kprintf("nested task, ");
if (frame->tf_rflags & PSL_RF)
kprintf("resume, ");
#if 0
if (frame->tf_eflags & PSL_VM)
kprintf("vm86, ");
#endif
kprintf("IOPL = %jd\n", (intmax_t)((frame->tf_rflags & PSL_IOPL) >> 12));
kprintf("current process = ");
if (curproc) {
kprintf("%lu (%s)\n",
(u_long)curproc->p_pid, curproc->p_comm ?
curproc->p_comm : "");
} else {
kprintf("Idle\n");
}
kprintf("current thread = pri %d ", curthread->td_pri);
if (curthread->td_critcount)
kprintf("(CRIT)");
kprintf("\n");
kprintf(" <- SMP: XXX");
kprintf("\n");
#ifdef KDB
if (kdb_trap(&psl))
return;
#endif
#ifdef DDB
if ((debugger_on_panic || db_active) && kdb_trap(type, code, frame))
return;
#endif
kprintf("trap number = %d\n", type);
if (type <= MAX_TRAP_MSG)
panic("%s", trap_msg[type]);
else
panic("unknown/reserved trap");
}
void
dblfault_handler(void)
{
#if 0
struct mdglobaldata *gd = mdcpu;
#endif
kprintf("\nFatal double fault:\n");
#if 0
kprintf("rip = 0x%lx\n", gd->gd_common_tss.tss_rip);
kprintf("rsp = 0x%lx\n", gd->gd_common_tss.tss_rsp);
kprintf("rbp = 0x%lx\n", gd->gd_common_tss.tss_rbp);
#endif
kprintf("cpuid = %d\n", mycpu->gd_cpuid);
panic("double fault");
}
void
syscall2(struct trapframe *frame)
{
struct thread *td = curthread;
struct proc *p = td->td_proc;
struct lwp *lp = td->td_lwp;
struct sysent *callp;
register_t orig_tf_rflags;
int sticks;
int error;
int narg;
#ifdef INVARIANTS
int crit_count = td->td_critcount;
lwkt_tokref_t curstop = td->td_toks_stop;
#endif
struct sysmsg sysmsg;
union sysunion *argp;
u_int code;
const int regcnt = 6;
mycpu->gd_cnt.v_syscall++;
KTR_LOG(kernentry_syscall, lp->lwp_proc->p_pid, lp->lwp_tid,
frame->tf_rax);
userenter(td, p);
sticks = (int)td->td_sticks;
orig_tf_rflags = frame->tf_rflags;
if (__predict_false(lp->lwp_vkernel && lp->lwp_vkernel->ve)) {
vkernel_trap(lp, frame);
error = EJUSTRETURN;
callp = NULL;
code = 0;
goto out;
}
lp->lwp_md.md_regs = frame;
code = frame->tf_rax;
if (code >= p->p_sysent->sv_size)
code = SYS___nosys;
argp = (union sysunion *)&frame->tf_rdi;
callp = &p->p_sysent->sv_table[code];
narg = callp->sy_narg;
if (__predict_false(narg > regcnt)) {
register_t *argsdst;
caddr_t params;
argsdst = (register_t *)&sysmsg.extargs;
bcopy(argp, argsdst, sizeof(register_t) * regcnt);
params = (caddr_t)frame->tf_rsp + sizeof(register_t);
KASSERT(params != NULL, ("copyin args with no params!"));
error = copyin(params, &argsdst[regcnt],
(narg - regcnt) * sizeof(register_t));
argp = (void *)argsdst;
if (error) {
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL)) {
ktrsyscall(lp, code, narg, argp);
}
#endif
goto bad;
}
}
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL)) {
ktrsyscall(lp, code, narg, argp);
}
#endif
sysmsg.sysmsg_fds[0] = 0;
sysmsg.sysmsg_fds[1] = frame->tf_rdx;
sysmsg.sysmsg_frame = frame;
STOPEVENT(p, S_SCE, narg);
error = (*callp->sy_call)(&sysmsg, argp);
#if 0
kprintf("system call %d returned %d\n", code, error);
#endif
out:
switch (error) {
case 0:
p = curproc;
lp = curthread->td_lwp;
frame->tf_rax = sysmsg.sysmsg_fds[0];
frame->tf_rdx = sysmsg.sysmsg_fds[1];
frame->tf_rflags &= ~PSL_C;
break;
case ERESTART:
frame->tf_rip -= frame->tf_err;
frame->tf_r10 = frame->tf_rcx;
break;
case EJUSTRETURN:
break;
case EASYNC:
panic("Unexpected EASYNC return value (for now)");
default:
bad:
if (p->p_sysent->sv_errsize) {
if (error >= p->p_sysent->sv_errsize)
error = -1;
else
error = p->p_sysent->sv_errtbl[error];
}
frame->tf_rax = error;
frame->tf_rflags |= PSL_C;
break;
}
if (orig_tf_rflags & PSL_T) {
frame->tf_rflags &= ~PSL_T;
trapsignal(lp, SIGTRAP, 0);
}
userret(lp, frame, sticks);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET)) {
ktrsysret(lp, code, error, sysmsg.sysmsg_result);
}
#endif
STOPEVENT(p, S_SCX, code);
userexit(lp);
KTR_LOG(kernentry_syscall_ret, lp->lwp_proc->p_pid, lp->lwp_tid, error);
#ifdef INVARIANTS
KASSERT(&td->td_toks_base == td->td_toks_stop,
("syscall: critical section count mismatch! %d/%d",
crit_count, td->td_pri));
KASSERT(curstop == td->td_toks_stop,
("syscall: extra tokens held after trap! %ld",
td->td_toks_stop - &td->td_toks_base));
#endif
}
void xsyscall(struct sysmsg *sysmsg, struct nosys_args *uap);
int
sys_xsyscall(struct sysmsg *sysmsg, const struct nosys_args *uap)
{
struct trapframe *frame;
struct sysent *callp;
union sysunion *argp;
struct thread *td;
const int regcnt = 5;
u_int code;
int error;
int narg;
td = curthread;
frame = sysmsg->sysmsg_frame;
code = (u_int)frame->tf_rdi;
if (code >= td->td_proc->p_sysent->sv_size)
code = SYS___nosys;
argp = (union sysunion *)(&frame->tf_rdi + 1);
callp = &td->td_proc->p_sysent->sv_table[code];
narg = callp->sy_narg;
if (__predict_false(narg > regcnt)) {
register_t *argsdst;
caddr_t params;
argsdst = (register_t *)&sysmsg->extargs;
bcopy(argp, argsdst, sizeof(register_t) * regcnt);
params = (caddr_t)frame->tf_rsp + sizeof(register_t);
error = copyin(params, &argsdst[regcnt],
(narg - regcnt) * sizeof(register_t));
argp = (void *)argsdst;
if (error)
return error;
}
#ifdef KTRACE
if (KTRPOINTP(td->td_proc, td, KTR_SYSCALL)) {
ktrsyscall(td->td_lwp, code, narg, argp);
}
#endif
error = (*callp->sy_call)(sysmsg, argp);
#ifdef KTRACE
if (KTRPOINTP(td->td_proc, td, KTR_SYSRET)) {
ktrsysret(td->td_lwp, code, error, sysmsg->sysmsg_result);
}
#endif
return error;
}
void
fork_return(struct lwp *lp, struct trapframe *frame)
{
frame->tf_rax = 0;
frame->tf_rflags &= ~PSL_C;
frame->tf_rdx = 1;
generic_lwp_return(lp, frame);
KTR_LOG(kernentry_fork_ret, lp->lwp_proc->p_pid, lp->lwp_tid);
}
void
generic_lwp_return(struct lwp *lp, struct trapframe *frame)
{
struct proc *p = lp->lwp_proc;
if (p->p_flags & P_WEXIT) {
lwpsignal(p, lp, SIGKILL);
}
lwkt_setpri_self(TDPRI_USER_NORM);
userenter(lp->lwp_thread, p);
userret(lp, frame, 0);
#ifdef KTRACE
if (KTRPOINT(lp->lwp_thread, KTR_SYSRET))
ktrsysret(lp, SYS_fork, 0, 0);
#endif
lp->lwp_flags |= LWP_PASSIVE_ACQ;
userexit(lp);
lp->lwp_flags &= ~LWP_PASSIVE_ACQ;
}
void
go_user(struct intrframe *frame)
{
struct trapframe *tf = (void *)&frame->if_rdi;
globaldata_t gd;
int r;
void *id;
sigsetmask(0);
for (;;) {
#if 1
crit_enter();
tf->tf_xflags &= ~PGEX_FPFAULT;
if (mdcpu->gd_npxthread != curthread) {
if (mdcpu->gd_npxthread)
npxsave(mdcpu->gd_npxthread->td_savefpu);
npxdna(tf);
}
#else
if (mdcpu->gd_npxthread == curthread) {
tf->tf_xflags &= ~PGEX_FPFAULT;
} else {
tf->tf_xflags |= PGEX_FPFAULT;
}
#endif
id = &curproc->p_vmspace->vm_pmap;
gd = mycpu;
gd->gd_flags |= GDF_VIRTUSER;
r = vmspace_ctl(id, VMSPACE_CTL_RUN, tf,
&curthread->td_savevext);
frame->if_xflags |= PGEX_U;
if (mdcpu->gd_npxthread == curthread) {
npxsave(mdcpu->gd_npxthread->td_savefpu);
}
crit_exit();
gd->gd_flags &= ~GDF_VIRTUSER;
if (r < 0) {
if (errno == EFAULT) {
panic("vmspace_ctl failed with EFAULT");
}
if (errno != EINTR)
panic("vmspace_ctl failed error %d", errno);
} else {
if (tf->tf_trapno) {
user_trap(tf);
}
}
if (mycpu->gd_reqflags & RQF_AST_MASK) {
tf->tf_trapno = T_ASTFLT;
user_trap(tf);
}
tf->tf_trapno = 0;
}
}
void
set_vkernel_fp(struct trapframe *frame)
{
struct thread *td = curthread;
if (frame->tf_xflags & PGEX_FPFAULT) {
td->td_pcb->pcb_flags |= FP_VIRTFP;
if (mdcpu->gd_npxthread == td)
npxexit();
} else {
td->td_pcb->pcb_flags &= ~FP_VIRTFP;
}
}
void
cpu_vkernel_trap(struct trapframe *frame, int error)
{
frame->tf_rax = error;
if (error)
frame->tf_rflags |= PSL_C;
else
frame->tf_rflags &= ~PSL_C;
}