1 /* $NetBSD: linux32_syscall.c,v 1.30 2010/12/20 00:25:24 matt Exp $ */ 2 3 #include <sys/cdefs.h> 4 __KERNEL_RCSID(0, "$NetBSD: linux32_syscall.c,v 1.30 2010/12/20 00:25:24 matt Exp $"); 5 6 #include <sys/param.h> 7 #include <sys/systm.h> 8 #include <sys/proc.h> 9 #include <sys/signal.h> 10 #include <sys/syscall.h> 11 #include <sys/syscallvar.h> 12 13 #include <machine/cpu.h> 14 #include <machine/psl.h> 15 #include <machine/userret.h> 16 17 #include <compat/linux32/linux32_syscall.h> 18 #include <compat/linux32/common/linux32_errno.h> 19 20 void linux32_syscall_intern(struct proc *); 21 void linux32_syscall(struct trapframe *); 22 23 void 24 linux32_syscall_intern(struct proc *p) 25 { 26 27 p->p_md.md_syscall = linux32_syscall; 28 } 29 30 void 31 linux32_syscall(struct trapframe *frame) 32 { 33 const struct sysent *callp; 34 struct proc *p; 35 struct lwp *l; 36 int error; 37 size_t narg; 38 register32_t code, args[6]; 39 register_t rval[2]; 40 int i; 41 register_t args64[6]; 42 43 l = curlwp; 44 p = l->l_proc; 45 46 code = frame->tf_rax; 47 48 LWP_CACHE_CREDS(l, p); 49 50 callp = p->p_emul->e_sysent; 51 52 code &= (LINUX32_SYS_NSYSENT - 1); 53 callp += code; 54 55 /* 56 * Linux passes the args in ebx, ecx, edx, esi, edi, ebp, in 57 * increasing order. 58 */ 59 args[0] = frame->tf_rbx & 0xffffffff; 60 args[1] = frame->tf_rcx & 0xffffffff; 61 args[2] = frame->tf_rdx & 0xffffffff; 62 args[3] = frame->tf_rsi & 0xffffffff; 63 args[4] = frame->tf_rdi & 0xffffffff; 64 args[5] = frame->tf_rbp & 0xffffffff; 65 66 if (__predict_false(p->p_trace_enabled)) { 67 narg = callp->sy_narg; 68 if (__predict_false(narg > __arraycount(args))) 69 panic("impossible syscall narg, code %d, narg %zd", 70 code, narg); 71 for (i = 0; i < narg; i++) 72 args64[i] = args[i] & 0xffffffff; 73 if ((error = trace_enter(code, args64, narg)) != 0) 74 goto out; 75 } 76 77 rval[0] = 0; 78 rval[1] = 0; 79 80 error = sy_call(callp, l, args, rval); 81 out: 82 switch (error) { 83 case 0: 84 frame->tf_rax = rval[0]; 85 frame->tf_rflags &= ~PSL_C; /* carry bit */ 86 break; 87 case ERESTART: 88 /* 89 * The offset to adjust the PC by depends on whether we entered 90 * the kernel through the trap or call gate. We pushed the 91 * size of the instruction into tf_err on entry. 92 */ 93 frame->tf_rip -= frame->tf_err; 94 break; 95 case EJUSTRETURN: 96 /* nothing to do */ 97 break; 98 default: 99 error = native_to_linux32_errno[error]; 100 frame->tf_rax = error; 101 frame->tf_rflags |= PSL_C; /* carry bit */ 102 break; 103 } 104 105 if (__predict_false(p->p_trace_enabled)) 106 trace_exit(code, rval, error); 107 userret(l); 108 } 109