1 /* $NetBSD: linux_machdep.c,v 1.90 2003/07/03 21:24:27 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1995, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank van der Linden. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.90 2003/07/03 21:24:27 christos Exp $"); 41 42 #if defined(_KERNEL_OPT) 43 #include "opt_vm86.h" 44 #include "opt_user_ldt.h" 45 #endif 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/signalvar.h> 50 #include <sys/kernel.h> 51 #include <sys/proc.h> 52 #include <sys/user.h> 53 #include <sys/buf.h> 54 #include <sys/reboot.h> 55 #include <sys/conf.h> 56 #include <sys/exec.h> 57 #include <sys/file.h> 58 #include <sys/callout.h> 59 #include <sys/malloc.h> 60 #include <sys/mbuf.h> 61 #include <sys/msgbuf.h> 62 #include <sys/mount.h> 63 #include <sys/vnode.h> 64 #include <sys/device.h> 65 #include <sys/sa.h> 66 #include <sys/syscallargs.h> 67 #include <sys/filedesc.h> 68 #include <sys/exec_elf.h> 69 #include <sys/disklabel.h> 70 #include <sys/ioctl.h> 71 #include <miscfs/specfs/specdev.h> 72 73 #include <compat/linux/common/linux_types.h> 74 #include <compat/linux/common/linux_signal.h> 75 #include <compat/linux/common/linux_util.h> 76 #include <compat/linux/common/linux_ioctl.h> 77 #include <compat/linux/common/linux_hdio.h> 78 #include <compat/linux/common/linux_exec.h> 79 #include <compat/linux/common/linux_machdep.h> 80 81 #include <compat/linux/linux_syscallargs.h> 82 83 #include <machine/cpu.h> 84 #include <machine/cpufunc.h> 85 #include <machine/psl.h> 86 #include <machine/reg.h> 87 #include <machine/segments.h> 88 #include <machine/specialreg.h> 89 #include <machine/sysarch.h> 90 #include <machine/vm86.h> 91 #include <machine/vmparam.h> 92 93 /* 94 * To see whether wscons is configured (for virtual console ioctl calls). 95 */ 96 #if defined(_KERNEL_OPT) 97 #include "wsdisplay.h" 98 #endif 99 #if (NWSDISPLAY > 0) 100 #include <dev/wscons/wsconsio.h> 101 #include <dev/wscons/wsdisplay_usl_io.h> 102 #if defined(_KERNEL_OPT) 103 #include "opt_xserver.h" 104 #endif 105 #endif 106 107 #ifdef USER_LDT 108 #include <machine/cpu.h> 109 int linux_read_ldt __P((struct lwp *, struct linux_sys_modify_ldt_args *, 110 register_t *)); 111 int linux_write_ldt __P((struct lwp *, struct linux_sys_modify_ldt_args *, 112 register_t *)); 113 #endif 114 115 #ifdef DEBUG_LINUX 116 #define DPRINTF(a) uprintf a 117 #else 118 #define DPRINTF(a) 119 #endif 120 121 static struct biosdisk_info *fd2biosinfo __P((struct proc *, struct file *)); 122 extern struct disklist *i386_alldisks; 123 static void linux_save_ucontext __P((struct lwp *, struct trapframe *, 124 sigset_t *, struct sigaltstack *, struct linux_ucontext *)); 125 static void linux_save_sigcontext __P((struct lwp *, struct trapframe *, 126 sigset_t *, struct linux_sigcontext *)); 127 static int linux_restore_sigcontext __P((struct lwp *, 128 struct linux_sigcontext *, register_t *)); 129 static void linux_rt_sendsig __P((int, sigset_t *, u_long)); 130 static void linux_old_sendsig __P((int, sigset_t *, u_long)); 131 132 extern char linux_sigcode[], linux_rt_sigcode[]; 133 /* 134 * Deal with some i386-specific things in the Linux emulation code. 135 */ 136 137 void 138 linux_setregs(l, epp, stack) 139 struct lwp *l; 140 struct exec_package *epp; 141 u_long stack; 142 { 143 struct pcb *pcb = &l->l_addr->u_pcb; 144 struct trapframe *tf; 145 146 #if NNPX > 0 147 /* If we were using the FPU, forget about it. */ 148 if (npxproc == l) 149 npxdrop(); 150 #endif 151 152 #ifdef USER_LDT 153 pmap_ldt_cleanup(l); 154 #endif 155 156 l->l_md.md_flags &= ~MDP_USEDFPU; 157 158 if (i386_use_fxsave) { 159 pcb->pcb_savefpu.sv_xmm.sv_env.en_cw = __Linux_NPXCW__; 160 pcb->pcb_savefpu.sv_xmm.sv_env.en_mxcsr = __INITIAL_MXCSR__; 161 } else 162 pcb->pcb_savefpu.sv_87.sv_env.en_cw = __Linux_NPXCW__; 163 164 tf = l->l_md.md_regs; 165 tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL); 166 tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL); 167 tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); 168 tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); 169 tf->tf_edi = 0; 170 tf->tf_esi = 0; 171 tf->tf_ebp = 0; 172 tf->tf_ebx = (int)l->l_proc->p_psstr; 173 tf->tf_edx = 0; 174 tf->tf_ecx = 0; 175 tf->tf_eax = 0; 176 tf->tf_eip = epp->ep_entry; 177 tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); 178 tf->tf_eflags = PSL_USERSET; 179 tf->tf_esp = stack; 180 tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL); 181 } 182 183 /* 184 * Send an interrupt to process. 185 * 186 * Stack is set up to allow sigcode stored 187 * in u. to call routine, followed by kcall 188 * to sigreturn routine below. After sigreturn 189 * resets the signal mask, the stack, and the 190 * frame pointer, it returns to the user 191 * specified pc, psl. 192 */ 193 194 void 195 linux_sendsig(sig, mask, code) 196 int sig; 197 sigset_t *mask; 198 u_long code; 199 { 200 if (SIGACTION(curproc, sig).sa_flags & SA_SIGINFO) 201 linux_rt_sendsig(sig, mask, code); 202 else 203 linux_old_sendsig(sig, mask, code); 204 } 205 206 207 static void 208 linux_save_ucontext(l, tf, mask, sas, uc) 209 struct lwp *l; 210 struct trapframe *tf; 211 sigset_t *mask; 212 struct sigaltstack *sas; 213 struct linux_ucontext *uc; 214 { 215 uc->uc_flags = 0; 216 uc->uc_link = NULL; 217 native_to_linux_sigaltstack(&uc->uc_stack, sas); 218 linux_save_sigcontext(l, tf, mask, &uc->uc_mcontext); 219 native_to_linux_sigset(&uc->uc_sigmask, mask); 220 (void)memset(&uc->uc_fpregs_mem, 0, sizeof(uc->uc_fpregs_mem)); 221 } 222 223 static void 224 linux_save_sigcontext(l, tf, mask, sc) 225 struct lwp *l; 226 struct trapframe *tf; 227 sigset_t *mask; 228 struct linux_sigcontext *sc; 229 { 230 /* Save register context. */ 231 #ifdef VM86 232 if (tf->tf_eflags & PSL_VM) { 233 sc->sc_gs = tf->tf_vm86_gs; 234 sc->sc_fs = tf->tf_vm86_fs; 235 sc->sc_es = tf->tf_vm86_es; 236 sc->sc_ds = tf->tf_vm86_ds; 237 sc->sc_eflags = get_vflags(l); 238 } else 239 #endif 240 { 241 sc->sc_gs = tf->tf_gs; 242 sc->sc_fs = tf->tf_fs; 243 sc->sc_es = tf->tf_es; 244 sc->sc_ds = tf->tf_ds; 245 sc->sc_eflags = tf->tf_eflags; 246 } 247 sc->sc_edi = tf->tf_edi; 248 sc->sc_esi = tf->tf_esi; 249 sc->sc_esp = tf->tf_esp; 250 sc->sc_ebp = tf->tf_ebp; 251 sc->sc_ebx = tf->tf_ebx; 252 sc->sc_edx = tf->tf_edx; 253 sc->sc_ecx = tf->tf_ecx; 254 sc->sc_eax = tf->tf_eax; 255 sc->sc_eip = tf->tf_eip; 256 sc->sc_cs = tf->tf_cs; 257 sc->sc_esp_at_signal = tf->tf_esp; 258 sc->sc_ss = tf->tf_ss; 259 sc->sc_err = tf->tf_err; 260 sc->sc_trapno = tf->tf_trapno; 261 sc->sc_cr2 = l->l_addr->u_pcb.pcb_cr2; 262 sc->sc_387 = NULL; 263 264 /* Save signal stack. */ 265 /* Linux doesn't save the onstack flag in sigframe */ 266 267 /* Save signal mask. */ 268 native_to_linux_old_sigset(&sc->sc_mask, mask); 269 } 270 271 static void 272 linux_rt_sendsig(sig, mask, code) 273 int sig; 274 sigset_t *mask; 275 u_long code; 276 { 277 struct lwp *l = curlwp; 278 struct proc *p = l->l_proc; 279 struct trapframe *tf; 280 struct linux_rt_sigframe *fp, frame; 281 int onstack; 282 sig_t catcher = SIGACTION(p, sig).sa_handler; 283 struct sigaltstack *sas = &p->p_sigctx.ps_sigstk; 284 285 tf = l->l_md.md_regs; 286 /* Do we need to jump onto the signal stack? */ 287 onstack = (sas->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && 288 (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; 289 290 291 /* Allocate space for the signal handler context. */ 292 if (onstack) 293 fp = (struct linux_rt_sigframe *)((caddr_t)sas->ss_sp + 294 sas->ss_size); 295 else 296 fp = (struct linux_rt_sigframe *)tf->tf_esp; 297 fp--; 298 299 DPRINTF(("rt: onstack = %d, fp = %p sig = %d eip = 0x%x\n", onstack, fp, 300 sig, tf->tf_eip)); 301 302 /* Build stack frame for signal trampoline. */ 303 frame.sf_handler = catcher; 304 frame.sf_sig = native_to_linux_signo[sig]; 305 frame.sf_sip = &fp->sf_si; 306 frame.sf_ucp = &fp->sf_uc; 307 308 (void)memset(&frame.sf_si, 0, sizeof(frame.sf_si)); 309 /* 310 * XXX: We'll fake bit of it here, all of the following 311 * info is a bit bogus, because we don't have the 312 * right info passed to us from the trap. 313 */ 314 switch (frame.sf_si.lsi_signo = frame.sf_sig) { 315 case LINUX_SIGSEGV: 316 frame.sf_si.lsi_code = LINUX_SEGV_MAPERR; 317 break; 318 case LINUX_SIGBUS: 319 frame.sf_si.lsi_code = LINUX_BUS_ADRERR; 320 break; 321 case LINUX_SIGTRAP: 322 frame.sf_si.lsi_code = LINUX_TRAP_BRKPT; 323 break; 324 case LINUX_SIGCHLD: 325 case LINUX_SIGIO: 326 default: 327 frame.sf_si.lsi_signo = 0; 328 break; 329 } 330 331 /* Save register context. */ 332 linux_save_ucontext(l, tf, mask, sas, &frame.sf_uc); 333 334 if (copyout(&frame, fp, sizeof(frame)) != 0) { 335 /* 336 * Process has trashed its stack; give it an illegal 337 * instruction to halt it in its tracks. 338 */ 339 sigexit(l, SIGILL); 340 /* NOTREACHED */ 341 } 342 343 /* 344 * Build context to run handler in. 345 */ 346 tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL); 347 tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL); 348 tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); 349 tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); 350 tf->tf_eip = ((int)p->p_sigctx.ps_sigcode) + 351 (linux_rt_sigcode - linux_sigcode); 352 tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); 353 tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC); 354 tf->tf_esp = (int)fp; 355 tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL); 356 357 /* Remember that we're now on the signal stack. */ 358 if (onstack) 359 sas->ss_flags |= SS_ONSTACK; 360 } 361 362 static void 363 linux_old_sendsig(sig, mask, code) 364 int sig; 365 sigset_t *mask; 366 u_long code; 367 { 368 struct lwp *l = curlwp; 369 struct proc *p = l->l_proc; 370 struct trapframe *tf; 371 struct linux_sigframe *fp, frame; 372 int onstack; 373 sig_t catcher = SIGACTION(p, sig).sa_handler; 374 struct sigaltstack *sas = &p->p_sigctx.ps_sigstk; 375 376 tf = l->l_md.md_regs; 377 378 /* Do we need to jump onto the signal stack? */ 379 onstack = (sas->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && 380 (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; 381 382 /* Allocate space for the signal handler context. */ 383 if (onstack) 384 fp = (struct linux_sigframe *) ((caddr_t)sas->ss_sp + 385 sas->ss_size); 386 else 387 fp = (struct linux_sigframe *)tf->tf_esp; 388 fp--; 389 390 DPRINTF(("old: onstack = %d, fp = %p sig = %d eip = 0x%x\n", 391 onstack, fp, sig, tf->tf_eip)); 392 393 /* Build stack frame for signal trampoline. */ 394 frame.sf_handler = catcher; 395 frame.sf_sig = native_to_linux_signo[sig]; 396 397 linux_save_sigcontext(l, tf, mask, &frame.sf_sc); 398 399 if (copyout(&frame, fp, sizeof(frame)) != 0) { 400 /* 401 * Process has trashed its stack; give it an illegal 402 * instruction to halt it in its tracks. 403 */ 404 sigexit(l, SIGILL); 405 /* NOTREACHED */ 406 } 407 408 /* 409 * Build context to run handler in. 410 */ 411 tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL); 412 tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL); 413 tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); 414 tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); 415 tf->tf_eip = (int)p->p_sigctx.ps_sigcode; 416 tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); 417 tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC); 418 tf->tf_esp = (int)fp; 419 tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL); 420 421 /* Remember that we're now on the signal stack. */ 422 if (onstack) 423 sas->ss_flags |= SS_ONSTACK; 424 } 425 426 /* 427 * System call to cleanup state after a signal 428 * has been taken. Reset signal mask and 429 * stack state from context left by sendsig (above). 430 * Return to previous pc and psl as specified by 431 * context left by sendsig. Check carefully to 432 * make sure that the user has not modified the 433 * psl to gain improper privileges or to cause 434 * a machine fault. 435 */ 436 int 437 linux_sys_rt_sigreturn(l, v, retval) 438 struct lwp *l; 439 void *v; 440 register_t *retval; 441 { 442 struct linux_sys_rt_sigreturn_args /* { 443 syscallarg(struct linux_ucontext *) ucp; 444 } */ *uap = v; 445 struct linux_ucontext context, *ucp = SCARG(uap, ucp); 446 int error; 447 448 /* 449 * The trampoline code hands us the context. 450 * It is unsafe to keep track of it ourselves, in the event that a 451 * program jumps out of a signal handler. 452 */ 453 if ((error = copyin(ucp, &context, sizeof(*ucp))) != 0) 454 return error; 455 456 /* XXX XAX we can do better here by using more of the ucontext */ 457 return linux_restore_sigcontext(l, &context.uc_mcontext, retval); 458 } 459 460 int 461 linux_sys_sigreturn(l, v, retval) 462 struct lwp *l; 463 void *v; 464 register_t *retval; 465 { 466 struct linux_sys_sigreturn_args /* { 467 syscallarg(struct linux_sigcontext *) scp; 468 } */ *uap = v; 469 struct linux_sigcontext context, *scp = SCARG(uap, scp); 470 int error; 471 472 /* 473 * The trampoline code hands us the context. 474 * It is unsafe to keep track of it ourselves, in the event that a 475 * program jumps out of a signal handler. 476 */ 477 if ((error = copyin((caddr_t)scp, &context, sizeof(*scp))) != 0) 478 return error; 479 return linux_restore_sigcontext(l, &context, retval); 480 } 481 482 static int 483 linux_restore_sigcontext(l, scp, retval) 484 struct lwp *l; 485 struct linux_sigcontext *scp; 486 register_t *retval; 487 { 488 struct proc *p = l->l_proc; 489 struct sigaltstack *sas = &p->p_sigctx.ps_sigstk; 490 struct trapframe *tf; 491 sigset_t mask; 492 ssize_t ss_gap; 493 /* Restore register context. */ 494 tf = l->l_md.md_regs; 495 496 DPRINTF(("sigreturn enter esp=%x eip=%x\n", tf->tf_esp, tf->tf_eip)); 497 #ifdef VM86 498 if (scp->sc_eflags & PSL_VM) { 499 void syscall_vm86 __P((struct trapframe)); 500 501 tf->tf_vm86_gs = scp->sc_gs; 502 tf->tf_vm86_fs = scp->sc_fs; 503 tf->tf_vm86_es = scp->sc_es; 504 tf->tf_vm86_ds = scp->sc_ds; 505 set_vflags(l, scp->sc_eflags); 506 p->p_md.md_syscall = syscall_vm86; 507 } else 508 #endif 509 { 510 /* 511 * Check for security violations. If we're returning to 512 * protected mode, the CPU will validate the segment registers 513 * automatically and generate a trap on violations. We handle 514 * the trap, rather than doing all of the checking here. 515 */ 516 if (((scp->sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || 517 !USERMODE(scp->sc_cs, scp->sc_eflags)) 518 return EINVAL; 519 520 tf->tf_gs = scp->sc_gs; 521 tf->tf_fs = scp->sc_fs; 522 tf->tf_es = scp->sc_es; 523 tf->tf_ds = scp->sc_ds; 524 #ifdef VM86 525 if (tf->tf_eflags & PSL_VM) 526 (*p->p_emul->e_syscall_intern)(p); 527 #endif 528 tf->tf_eflags = scp->sc_eflags; 529 } 530 tf->tf_edi = scp->sc_edi; 531 tf->tf_esi = scp->sc_esi; 532 tf->tf_ebp = scp->sc_ebp; 533 tf->tf_ebx = scp->sc_ebx; 534 tf->tf_edx = scp->sc_edx; 535 tf->tf_ecx = scp->sc_ecx; 536 tf->tf_eax = scp->sc_eax; 537 tf->tf_eip = scp->sc_eip; 538 tf->tf_cs = scp->sc_cs; 539 tf->tf_esp = scp->sc_esp_at_signal; 540 tf->tf_ss = scp->sc_ss; 541 542 /* Restore signal stack. */ 543 /* 544 * Linux really does it this way; it doesn't have space in sigframe 545 * to save the onstack flag. 546 */ 547 ss_gap = (ssize_t) 548 ((caddr_t) scp->sc_esp_at_signal - (caddr_t) sas->ss_sp); 549 if (ss_gap >= 0 && ss_gap < sas->ss_size) 550 sas->ss_flags |= SS_ONSTACK; 551 else 552 sas->ss_flags &= ~SS_ONSTACK; 553 554 /* Restore signal mask. */ 555 linux_old_to_native_sigset(&mask, &scp->sc_mask); 556 (void) sigprocmask1(p, SIG_SETMASK, &mask, 0); 557 DPRINTF(("sigreturn exit esp=%x eip=%x\n", tf->tf_esp, tf->tf_eip)); 558 return EJUSTRETURN; 559 } 560 561 #ifdef USER_LDT 562 563 int 564 linux_read_ldt(l, uap, retval) 565 struct lwp *l; 566 struct linux_sys_modify_ldt_args /* { 567 syscallarg(int) func; 568 syscallarg(void *) ptr; 569 syscallarg(size_t) bytecount; 570 } */ *uap; 571 register_t *retval; 572 { 573 struct proc *p = l->l_proc; 574 struct i386_get_ldt_args gl; 575 int error; 576 caddr_t sg; 577 char *parms; 578 579 DPRINTF(("linux_read_ldt!")); 580 sg = stackgap_init(p, 0); 581 582 gl.start = 0; 583 gl.desc = SCARG(uap, ptr); 584 gl.num = SCARG(uap, bytecount) / sizeof(union descriptor); 585 586 parms = stackgap_alloc(p, &sg, sizeof(gl)); 587 588 if ((error = copyout(&gl, parms, sizeof(gl))) != 0) 589 return (error); 590 591 if ((error = i386_get_ldt(l, parms, retval)) != 0) 592 return (error); 593 594 *retval *= sizeof(union descriptor); 595 return (0); 596 } 597 598 struct linux_ldt_info { 599 u_int entry_number; 600 u_long base_addr; 601 u_int limit; 602 u_int seg_32bit:1; 603 u_int contents:2; 604 u_int read_exec_only:1; 605 u_int limit_in_pages:1; 606 u_int seg_not_present:1; 607 u_int useable:1; 608 }; 609 610 int 611 linux_write_ldt(l, uap, retval) 612 struct lwp *l; 613 struct linux_sys_modify_ldt_args /* { 614 syscallarg(int) func; 615 syscallarg(void *) ptr; 616 syscallarg(size_t) bytecount; 617 } */ *uap; 618 register_t *retval; 619 { 620 struct proc *p = l->l_proc; 621 struct linux_ldt_info ldt_info; 622 struct segment_descriptor sd; 623 struct i386_set_ldt_args sl; 624 int error; 625 caddr_t sg; 626 char *parms; 627 int oldmode = (int)retval[0]; 628 629 DPRINTF(("linux_write_ldt %d\n", oldmode)); 630 if (SCARG(uap, bytecount) != sizeof(ldt_info)) 631 return (EINVAL); 632 if ((error = copyin(SCARG(uap, ptr), &ldt_info, sizeof(ldt_info))) != 0) 633 return error; 634 if (ldt_info.entry_number >= 8192) 635 return (EINVAL); 636 if (ldt_info.contents == 3) { 637 if (oldmode) 638 return (EINVAL); 639 if (ldt_info.seg_not_present) 640 return (EINVAL); 641 } 642 643 if (ldt_info.base_addr == 0 && ldt_info.limit == 0 && 644 (oldmode || (ldt_info.contents == 0 && 645 ldt_info.read_exec_only == 1 && ldt_info.seg_32bit == 0 && 646 ldt_info.limit_in_pages == 0 && ldt_info.seg_not_present == 1 && 647 ldt_info.useable == 0))) { 648 /* this means you should zero the ldt */ 649 (void)memset(&sd, 0, sizeof(sd)); 650 } else { 651 sd.sd_lobase = ldt_info.base_addr & 0xffffff; 652 sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff; 653 sd.sd_lolimit = ldt_info.limit & 0xffff; 654 sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf; 655 sd.sd_type = 16 | (ldt_info.contents << 2) | 656 (!ldt_info.read_exec_only << 1); 657 sd.sd_dpl = SEL_UPL; 658 sd.sd_p = !ldt_info.seg_not_present; 659 sd.sd_def32 = ldt_info.seg_32bit; 660 sd.sd_gran = ldt_info.limit_in_pages; 661 if (!oldmode) 662 sd.sd_xx = ldt_info.useable; 663 else 664 sd.sd_xx = 0; 665 } 666 sg = stackgap_init(p, 0); 667 sl.start = ldt_info.entry_number; 668 sl.desc = stackgap_alloc(p, &sg, sizeof(sd)); 669 sl.num = 1; 670 671 DPRINTF(("linux_write_ldt: idx=%d, base=0x%lx, limit=0x%x\n", 672 ldt_info.entry_number, ldt_info.base_addr, ldt_info.limit)); 673 674 parms = stackgap_alloc(p, &sg, sizeof(sl)); 675 676 if ((error = copyout(&sd, sl.desc, sizeof(sd))) != 0) 677 return (error); 678 if ((error = copyout(&sl, parms, sizeof(sl))) != 0) 679 return (error); 680 681 if ((error = i386_set_ldt(l, parms, retval)) != 0) 682 return (error); 683 684 *retval = 0; 685 return (0); 686 } 687 688 #endif /* USER_LDT */ 689 690 int 691 linux_sys_modify_ldt(l, v, retval) 692 struct lwp *l; 693 void *v; 694 register_t *retval; 695 { 696 struct linux_sys_modify_ldt_args /* { 697 syscallarg(int) func; 698 syscallarg(void *) ptr; 699 syscallarg(size_t) bytecount; 700 } */ *uap = v; 701 702 switch (SCARG(uap, func)) { 703 #ifdef USER_LDT 704 case 0: 705 return linux_read_ldt(l, uap, retval); 706 case 1: 707 retval[0] = 1; 708 return linux_write_ldt(l, uap, retval); 709 case 2: 710 #ifdef notyet 711 return (linux_read_default_ldt(l, uap, retval); 712 #else 713 return (ENOSYS); 714 #endif 715 case 0x11: 716 retval[0] = 0; 717 return linux_write_ldt(l, uap, retval); 718 #endif /* USER_LDT */ 719 720 default: 721 return (ENOSYS); 722 } 723 } 724 725 /* 726 * XXX Pathetic hack to make svgalib work. This will fake the major 727 * device number of an opened VT so that svgalib likes it. grmbl. 728 * Should probably do it 'wrong the right way' and use a mapping 729 * array for all major device numbers, and map linux_mknod too. 730 */ 731 dev_t 732 linux_fakedev(dev, raw) 733 dev_t dev; 734 int raw; 735 { 736 if (raw) { 737 #if (NWSDISPLAY > 0) 738 extern const struct cdevsw wsdisplay_cdevsw; 739 if (cdevsw_lookup(dev) == &wsdisplay_cdevsw) 740 return makedev(LINUX_CONS_MAJOR, (minor(dev) + 1)); 741 #endif 742 } 743 744 return dev; 745 } 746 747 #if (NWSDISPLAY > 0) 748 /* 749 * That's not complete, but enough to get an X server running. 750 */ 751 #define NR_KEYS 128 752 static const u_short plain_map[NR_KEYS] = { 753 0x0200, 0x001b, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 754 0x0037, 0x0038, 0x0039, 0x0030, 0x002d, 0x003d, 0x007f, 0x0009, 755 0x0b71, 0x0b77, 0x0b65, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69, 756 0x0b6f, 0x0b70, 0x005b, 0x005d, 0x0201, 0x0702, 0x0b61, 0x0b73, 757 0x0b64, 0x0b66, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x003b, 758 0x0027, 0x0060, 0x0700, 0x005c, 0x0b7a, 0x0b78, 0x0b63, 0x0b76, 759 0x0b62, 0x0b6e, 0x0b6d, 0x002c, 0x002e, 0x002f, 0x0700, 0x030c, 760 0x0703, 0x0020, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 761 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0209, 0x0307, 762 0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301, 763 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x003c, 0x010a, 764 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 765 0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603, 766 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, 767 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, 768 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 769 }, shift_map[NR_KEYS] = { 770 0x0200, 0x001b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e, 771 0x0026, 0x002a, 0x0028, 0x0029, 0x005f, 0x002b, 0x007f, 0x0009, 772 0x0b51, 0x0b57, 0x0b45, 0x0b52, 0x0b54, 0x0b59, 0x0b55, 0x0b49, 773 0x0b4f, 0x0b50, 0x007b, 0x007d, 0x0201, 0x0702, 0x0b41, 0x0b53, 774 0x0b44, 0x0b46, 0x0b47, 0x0b48, 0x0b4a, 0x0b4b, 0x0b4c, 0x003a, 775 0x0022, 0x007e, 0x0700, 0x007c, 0x0b5a, 0x0b58, 0x0b43, 0x0b56, 776 0x0b42, 0x0b4e, 0x0b4d, 0x003c, 0x003e, 0x003f, 0x0700, 0x030c, 777 0x0703, 0x0020, 0x0207, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e, 778 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0213, 0x0203, 0x0307, 779 0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301, 780 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x003e, 0x010a, 781 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 782 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, 783 0x020b, 0x0601, 0x0602, 0x0117, 0x0600, 0x020a, 0x0115, 0x0116, 784 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, 785 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 786 }, altgr_map[NR_KEYS] = { 787 0x0200, 0x0200, 0x0200, 0x0040, 0x0200, 0x0024, 0x0200, 0x0200, 788 0x007b, 0x005b, 0x005d, 0x007d, 0x005c, 0x0200, 0x0200, 0x0200, 789 0x0b71, 0x0b77, 0x0918, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69, 790 0x0b6f, 0x0b70, 0x0200, 0x007e, 0x0201, 0x0702, 0x0914, 0x0b73, 791 0x0917, 0x0919, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x0200, 792 0x0200, 0x0200, 0x0700, 0x0200, 0x0b7a, 0x0b78, 0x0916, 0x0b76, 793 0x0915, 0x0b6e, 0x0b6d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c, 794 0x0703, 0x0200, 0x0207, 0x050c, 0x050d, 0x050e, 0x050f, 0x0510, 795 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0208, 0x0202, 0x0911, 796 0x0912, 0x0913, 0x030b, 0x090e, 0x090f, 0x0910, 0x030a, 0x090b, 797 0x090c, 0x090d, 0x090a, 0x0310, 0x0206, 0x0200, 0x007c, 0x0516, 798 0x0517, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 799 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, 800 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, 801 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, 802 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 803 }, ctrl_map[NR_KEYS] = { 804 0x0200, 0x0200, 0x0200, 0x0000, 0x001b, 0x001c, 0x001d, 0x001e, 805 0x001f, 0x007f, 0x0200, 0x0200, 0x001f, 0x0200, 0x0008, 0x0200, 806 0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009, 807 0x000f, 0x0010, 0x001b, 0x001d, 0x0201, 0x0702, 0x0001, 0x0013, 808 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200, 809 0x0007, 0x0000, 0x0700, 0x001c, 0x001a, 0x0018, 0x0003, 0x0016, 810 0x0002, 0x000e, 0x000d, 0x0200, 0x020e, 0x007f, 0x0700, 0x030c, 811 0x0703, 0x0000, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 812 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0204, 0x0307, 813 0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301, 814 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x010a, 815 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 816 0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603, 817 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, 818 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, 819 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 820 }; 821 822 const u_short * const linux_keytabs[] = { 823 plain_map, shift_map, altgr_map, altgr_map, ctrl_map 824 }; 825 #endif 826 827 static struct biosdisk_info * 828 fd2biosinfo(p, fp) 829 struct proc *p; 830 struct file *fp; 831 { 832 struct vnode *vp; 833 const char *blkname; 834 char diskname[16]; 835 int i; 836 struct nativedisk_info *nip; 837 struct disklist *dl = i386_alldisks; 838 839 if (fp->f_type != DTYPE_VNODE) 840 return NULL; 841 vp = (struct vnode *)fp->f_data; 842 843 if (vp->v_type != VBLK) 844 return NULL; 845 846 blkname = devsw_blk2name(major(vp->v_rdev)); 847 snprintf(diskname, sizeof diskname, "%s%u", blkname, 848 DISKUNIT(vp->v_rdev)); 849 850 for (i = 0; i < dl->dl_nnativedisks; i++) { 851 nip = &dl->dl_nativedisks[i]; 852 if (strcmp(diskname, nip->ni_devname)) 853 continue; 854 if (nip->ni_nmatches != 0) 855 return &dl->dl_biosdisks[nip->ni_biosmatches[0]]; 856 } 857 858 return NULL; 859 } 860 861 862 /* 863 * We come here in a last attempt to satisfy a Linux ioctl() call 864 */ 865 int 866 linux_machdepioctl(p, v, retval) 867 struct proc *p; 868 void *v; 869 register_t *retval; 870 { 871 struct linux_sys_ioctl_args /* { 872 syscallarg(int) fd; 873 syscallarg(u_long) com; 874 syscallarg(caddr_t) data; 875 } */ *uap = v; 876 struct sys_ioctl_args bia; 877 u_long com; 878 int error, error1; 879 #if (NWSDISPLAY > 0) 880 struct vt_mode lvt; 881 caddr_t bvtp, sg; 882 struct kbentry kbe; 883 #endif 884 struct linux_hd_geometry hdg; 885 struct linux_hd_big_geometry hdg_big; 886 struct biosdisk_info *bip; 887 struct filedesc *fdp; 888 struct file *fp; 889 int fd; 890 struct disklabel label, *labp; 891 struct partinfo partp; 892 int (*ioctlf)(struct file *, u_long, void *, struct proc *); 893 u_long start, biostotal, realtotal; 894 u_char heads, sectors; 895 u_int cylinders; 896 struct ioctl_pt pt; 897 898 fd = SCARG(uap, fd); 899 SCARG(&bia, fd) = fd; 900 SCARG(&bia, data) = SCARG(uap, data); 901 com = SCARG(uap, com); 902 903 fdp = p->p_fd; 904 905 if ((fp = fd_getfile(fdp, fd)) == NULL) 906 return (EBADF); 907 908 FILE_USE(fp); 909 910 switch (com) { 911 #if (NWSDISPLAY > 0) 912 case LINUX_KDGKBMODE: 913 com = KDGKBMODE; 914 break; 915 case LINUX_KDSKBMODE: 916 com = KDSKBMODE; 917 if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW) 918 SCARG(&bia, data) = (caddr_t)K_RAW; 919 break; 920 case LINUX_KIOCSOUND: 921 SCARG(&bia, data) = 922 (caddr_t)(((unsigned long)SCARG(&bia, data)) & 0xffff); 923 /* fall through */ 924 case LINUX_KDMKTONE: 925 com = KDMKTONE; 926 break; 927 case LINUX_KDSETMODE: 928 com = KDSETMODE; 929 break; 930 case LINUX_KDGETMODE: 931 /* KD_* values are equal to the wscons numbers */ 932 com = WSDISPLAYIO_GMODE; 933 break; 934 case LINUX_KDENABIO: 935 com = KDENABIO; 936 break; 937 case LINUX_KDDISABIO: 938 com = KDDISABIO; 939 break; 940 case LINUX_KDGETLED: 941 com = KDGETLED; 942 break; 943 case LINUX_KDSETLED: 944 com = KDSETLED; 945 break; 946 case LINUX_VT_OPENQRY: 947 com = VT_OPENQRY; 948 break; 949 case LINUX_VT_GETMODE: 950 SCARG(&bia, com) = VT_GETMODE; 951 /* XXX NJWLWP */ 952 if ((error = sys_ioctl(curlwp, &bia, retval))) 953 goto out; 954 if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt, 955 sizeof (struct vt_mode)))) 956 goto out; 957 lvt.relsig = native_to_linux_signo[lvt.relsig]; 958 lvt.acqsig = native_to_linux_signo[lvt.acqsig]; 959 lvt.frsig = native_to_linux_signo[lvt.frsig]; 960 error = copyout((caddr_t)&lvt, SCARG(uap, data), 961 sizeof (struct vt_mode)); 962 goto out; 963 case LINUX_VT_SETMODE: 964 com = VT_SETMODE; 965 if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt, 966 sizeof (struct vt_mode)))) 967 goto out; 968 lvt.relsig = linux_to_native_signo[lvt.relsig]; 969 lvt.acqsig = linux_to_native_signo[lvt.acqsig]; 970 lvt.frsig = linux_to_native_signo[lvt.frsig]; 971 sg = stackgap_init(p, 0); 972 bvtp = stackgap_alloc(p, &sg, sizeof (struct vt_mode)); 973 if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode)))) 974 goto out; 975 SCARG(&bia, data) = bvtp; 976 break; 977 case LINUX_VT_DISALLOCATE: 978 /* XXX should use WSDISPLAYIO_DELSCREEN */ 979 error = 0; 980 goto out; 981 case LINUX_VT_RELDISP: 982 com = VT_RELDISP; 983 break; 984 case LINUX_VT_ACTIVATE: 985 com = VT_ACTIVATE; 986 break; 987 case LINUX_VT_WAITACTIVE: 988 com = VT_WAITACTIVE; 989 break; 990 case LINUX_VT_GETSTATE: 991 com = VT_GETSTATE; 992 break; 993 case LINUX_KDGKBTYPE: 994 /* This is what Linux does. */ 995 error = subyte(SCARG(uap, data), KB_101); 996 goto out; 997 case LINUX_KDGKBENT: 998 /* 999 * The Linux KDGKBENT ioctl is different from the 1000 * SYSV original. So we handle it in machdep code. 1001 * XXX We should use keyboard mapping information 1002 * from wsdisplay, but this would be expensive. 1003 */ 1004 if ((error = copyin(SCARG(uap, data), &kbe, 1005 sizeof(struct kbentry)))) 1006 goto out; 1007 if (kbe.kb_table >= sizeof(linux_keytabs) / sizeof(u_short *) 1008 || kbe.kb_index >= NR_KEYS) { 1009 error = EINVAL; 1010 goto out; 1011 } 1012 kbe.kb_value = linux_keytabs[kbe.kb_table][kbe.kb_index]; 1013 error = copyout(&kbe, SCARG(uap, data), 1014 sizeof(struct kbentry)); 1015 goto out; 1016 #endif 1017 case LINUX_HDIO_GETGEO: 1018 case LINUX_HDIO_GETGEO_BIG: 1019 /* 1020 * Try to mimic Linux behaviour: return the BIOS geometry 1021 * if possible (extending its # of cylinders if it's beyond 1022 * the 1023 limit), fall back to the MI geometry (i.e. 1023 * the real geometry) if not found, by returning an 1024 * error. See common/linux_hdio.c 1025 */ 1026 bip = fd2biosinfo(p, fp); 1027 ioctlf = fp->f_ops->fo_ioctl; 1028 error = ioctlf(fp, DIOCGDEFLABEL, (caddr_t)&label, p); 1029 error1 = ioctlf(fp, DIOCGPART, (caddr_t)&partp, p); 1030 if (error != 0 && error1 != 0) { 1031 error = error1; 1032 goto out; 1033 } 1034 labp = error != 0 ? &label : partp.disklab; 1035 start = error1 != 0 ? partp.part->p_offset : 0; 1036 if (bip != NULL && bip->bi_head != 0 && bip->bi_sec != 0 1037 && bip->bi_cyl != 0) { 1038 heads = bip->bi_head; 1039 sectors = bip->bi_sec; 1040 cylinders = bip->bi_cyl; 1041 biostotal = heads * sectors * cylinders; 1042 realtotal = labp->d_ntracks * labp->d_nsectors * 1043 labp->d_ncylinders; 1044 if (realtotal > biostotal) 1045 cylinders = realtotal / (heads * sectors); 1046 } else { 1047 heads = labp->d_ntracks; 1048 cylinders = labp->d_ncylinders; 1049 sectors = labp->d_nsectors; 1050 } 1051 if (com == LINUX_HDIO_GETGEO) { 1052 hdg.start = start; 1053 hdg.heads = heads; 1054 hdg.cylinders = cylinders; 1055 hdg.sectors = sectors; 1056 error = copyout(&hdg, SCARG(uap, data), sizeof hdg); 1057 goto out; 1058 } else { 1059 hdg_big.start = start; 1060 hdg_big.heads = heads; 1061 hdg_big.cylinders = cylinders; 1062 hdg_big.sectors = sectors; 1063 error = copyout(&hdg_big, SCARG(uap, data), 1064 sizeof hdg_big); 1065 goto out; 1066 } 1067 1068 default: 1069 /* 1070 * Unknown to us. If it's on a device, just pass it through 1071 * using PTIOCLINUX, the device itself might be able to 1072 * make some sense of it. 1073 * XXX hack: if the function returns EJUSTRETURN, 1074 * it has stuffed a sysctl return value in pt.data. 1075 */ 1076 FILE_USE(fp); 1077 ioctlf = fp->f_ops->fo_ioctl; 1078 pt.com = SCARG(uap, com); 1079 pt.data = SCARG(uap, data); 1080 error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p); 1081 FILE_UNUSE(fp, p); 1082 if (error == EJUSTRETURN) { 1083 retval[0] = (register_t)pt.data; 1084 error = 0; 1085 } 1086 1087 if (error == ENOTTY) 1088 DPRINTF(("linux_machdepioctl: invalid ioctl %08lx\n", 1089 com)); 1090 goto out; 1091 } 1092 SCARG(&bia, com) = com; 1093 /* XXX NJWLWP */ 1094 error = sys_ioctl(curlwp, &bia, retval); 1095 out: 1096 FILE_UNUSE(fp ,p); 1097 return error; 1098 } 1099 1100 /* 1101 * Set I/O permissions for a process. Just set the maximum level 1102 * right away (ignoring the argument), otherwise we would have 1103 * to rely on I/O permission maps, which are not implemented. 1104 */ 1105 int 1106 linux_sys_iopl(l, v, retval) 1107 struct lwp *l; 1108 void *v; 1109 register_t *retval; 1110 { 1111 #if 0 1112 struct linux_sys_iopl_args /* { 1113 syscallarg(int) level; 1114 } */ *uap = v; 1115 #endif 1116 struct proc *p = l->l_proc; 1117 struct trapframe *fp = l->l_md.md_regs; 1118 1119 if (suser(p->p_ucred, &p->p_acflag) != 0) 1120 return EPERM; 1121 fp->tf_eflags |= PSL_IOPL; 1122 *retval = 0; 1123 return 0; 1124 } 1125 1126 /* 1127 * See above. If a root process tries to set access to an I/O port, 1128 * just let it have the whole range. 1129 */ 1130 int 1131 linux_sys_ioperm(l, v, retval) 1132 struct lwp *l; 1133 void *v; 1134 register_t *retval; 1135 { 1136 struct linux_sys_ioperm_args /* { 1137 syscallarg(unsigned int) lo; 1138 syscallarg(unsigned int) hi; 1139 syscallarg(int) val; 1140 } */ *uap = v; 1141 struct proc *p = l->l_proc; 1142 struct trapframe *fp = l->l_md.md_regs; 1143 1144 if (suser(p->p_ucred, &p->p_acflag) != 0) 1145 return EPERM; 1146 if (SCARG(uap, val)) 1147 fp->tf_eflags |= PSL_IOPL; 1148 *retval = 0; 1149 return 0; 1150 } 1151