1/* $NetBSD: ibcs2_syscall.c,v 1.45 2009/03/14 15:36:07 dsl Exp $ */ 2 3/*- 4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: ibcs2_syscall.c,v 1.45 2009/03/14 15:36:07 dsl Exp $"); 34 35#if defined(_KERNEL_OPT) 36#include "opt_vm86.h" 37#endif 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/proc.h> 42#include <sys/signal.h> 43#include <sys/syscall.h> 44#include <sys/syscallvar.h> 45 46#include <uvm/uvm_extern.h> 47 48#include <machine/cpu.h> 49#include <machine/psl.h> 50#include <machine/userret.h> 51 52#include <compat/ibcs2/ibcs2_errno.h> 53#include <compat/ibcs2/ibcs2_exec.h> 54#include <compat/ibcs2/ibcs2_syscall.h> 55#include <machine/ibcs2_machdep.h> 56 57void ibcs2_syscall_plain(struct trapframe *); 58void ibcs2_syscall_fancy(struct trapframe *); 59extern struct sysent ibcs2_sysent[]; 60 61void 62ibcs2_syscall_intern(struct proc *p) 63{ 64 65 if (trace_is_enabled(p)) 66 p->p_md.md_syscall = ibcs2_syscall_fancy; 67 else 68 p->p_md.md_syscall = ibcs2_syscall_plain; 69} 70 71/* 72 * syscall(frame): 73 * System call request from POSIX system call gate interface to kernel. 74 * Like trap(), argument is call by reference. 75 */ 76void 77ibcs2_syscall_plain(struct trapframe *frame) 78{ 79 char *params; 80 const struct sysent *callp; 81 struct lwp *l; 82 int error; 83 size_t argsize; 84 register_t code, args[8], rval[2]; 85 86 l = curlwp; 87 LWP_CACHE_CREDS(l, l->l_proc); 88 89 code = frame->tf_eax; 90 if (IBCS2_HIGH_SYSCALL(code)) 91 code = IBCS2_CVT_HIGH_SYSCALL(code); 92 callp = ibcs2_sysent; 93 params = (char *)frame->tf_esp + sizeof(int); 94 95 switch (code) { 96 case SYS_syscall: 97 /* 98 * Code is first argument, followed by actual args. 99 */ 100 code = fuword(params); 101 params += sizeof(int); 102 break; 103 default: 104 break; 105 } 106 107 code &= (IBCS2_SYS_NSYSENT - 1); 108 callp += code; 109 argsize = callp->sy_argsize; 110 if (argsize) { 111 error = copyin(params, (void *)args, argsize); 112 if (error) 113 goto bad; 114 } 115 116 rval[0] = 0; 117 rval[1] = 0; 118 119 error = sy_call(callp, l, args, rval); 120 121 switch (error) { 122 case 0: 123 frame->tf_eax = rval[0]; 124 frame->tf_edx = rval[1]; 125 frame->tf_eflags &= ~PSL_C; /* carry bit */ 126 break; 127 case ERESTART: 128 /* 129 * The offset to adjust the PC by depends on whether we entered 130 * the kernel through the trap or call gate. We pushed the 131 * size of the instruction into tf_err on entry. 132 */ 133 frame->tf_eip -= frame->tf_err; 134 break; 135 case EJUSTRETURN: 136 /* nothing to do */ 137 break; 138 default: 139 bad: 140 error = native_to_ibcs2_errno[error]; 141 frame->tf_eax = error; 142 frame->tf_eflags |= PSL_C; /* carry bit */ 143 break; 144 } 145 146 userret(l); 147} 148 149/* 150 * syscall(frame): 151 * System call request from POSIX system call gate interface to kernel. 152 * Like trap(), argument is call by reference. 153 */ 154void 155ibcs2_syscall_fancy(struct trapframe *frame) 156{ 157 char * params; 158 const struct sysent *callp; 159 struct lwp *l; 160 int error; 161 size_t argsize; 162 register_t code, args[8], rval[2]; 163 164 l = curlwp; 165 LWP_CACHE_CREDS(l, l->l_proc); 166 167 code = frame->tf_eax; 168 if (IBCS2_HIGH_SYSCALL(code)) 169 code = IBCS2_CVT_HIGH_SYSCALL(code); 170 callp = ibcs2_sysent; 171 params = (char *)frame->tf_esp + sizeof(int); 172 173 switch (code) { 174 case SYS_syscall: 175 /* 176 * Code is first argument, followed by actual args. 177 */ 178 code = fuword(params); 179 params += sizeof(int); 180 break; 181 default: 182 break; 183 } 184 185 code &= (IBCS2_SYS_NSYSENT - 1); 186 callp += code; 187 argsize = callp->sy_argsize; 188 if (argsize) { 189 error = copyin(params, (void *)args, argsize); 190 if (error) 191 goto bad; 192 } 193 194 if ((error = trace_enter(code, args, callp->sy_narg)) == 0) { 195 rval[0] = 0; 196 rval[1] = 0; 197 error = sy_call(callp, l, args, rval); 198 } 199 200 switch (error) { 201 case 0: 202 frame->tf_eax = rval[0]; 203 frame->tf_edx = rval[1]; 204 frame->tf_eflags &= ~PSL_C; /* carry bit */ 205 break; 206 case ERESTART: 207 /* 208 * The offset to adjust the PC by depends on whether we entered 209 * the kernel through the trap or call gate. We pushed the 210 * size of the instruction into tf_err on entry. 211 */ 212 frame->tf_eip -= frame->tf_err; 213 break; 214 case EJUSTRETURN: 215 /* nothing to do */ 216 break; 217 default: 218 bad: 219 error = native_to_ibcs2_errno[error]; 220 frame->tf_eax = error; 221 frame->tf_eflags |= PSL_C; /* carry bit */ 222 break; 223 } 224 225 trace_exit(code, rval, error); 226 227 userret(l); 228} 229