Home | History | Annotate | Line # | Download | only in i386
linux_machdep.c revision 1.50
      1 /*	$NetBSD: linux_machdep.c,v 1.50 2000/06/11 09:19:27 veego Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1995 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 "opt_vm86.h"
     40 #include "opt_user_ldt.h"
     41 
     42 #include <sys/param.h>
     43 #include <sys/systm.h>
     44 #include <sys/signalvar.h>
     45 #include <sys/kernel.h>
     46 #include <sys/map.h>
     47 #include <sys/proc.h>
     48 #include <sys/user.h>
     49 #include <sys/buf.h>
     50 #include <sys/reboot.h>
     51 #include <sys/conf.h>
     52 #include <sys/exec.h>
     53 #include <sys/file.h>
     54 #include <sys/callout.h>
     55 #include <sys/malloc.h>
     56 #include <sys/mbuf.h>
     57 #include <sys/msgbuf.h>
     58 #include <sys/mount.h>
     59 #include <sys/vnode.h>
     60 #include <sys/device.h>
     61 #include <sys/syscallargs.h>
     62 #include <sys/filedesc.h>
     63 #include <sys/exec_elf.h>
     64 
     65 #include <compat/linux/common/linux_types.h>
     66 #include <compat/linux/common/linux_signal.h>
     67 #include <compat/linux/common/linux_util.h>
     68 #include <compat/linux/common/linux_ioctl.h>
     69 #include <compat/linux/common/linux_exec.h>
     70 #include <compat/linux/common/linux_machdep.h>
     71 
     72 #include <compat/linux/linux_syscallargs.h>
     73 
     74 #include <machine/cpu.h>
     75 #include <machine/cpufunc.h>
     76 #include <machine/psl.h>
     77 #include <machine/reg.h>
     78 #include <machine/segments.h>
     79 #include <machine/specialreg.h>
     80 #include <machine/sysarch.h>
     81 #include <machine/vm86.h>
     82 #include <machine/vmparam.h>
     83 
     84 /*
     85  * To see whether wscons is configured (for virtual console ioctl calls).
     86  */
     87 #include "wsdisplay.h"
     88 #if (NWSDISPLAY > 0)
     89 #include <sys/ioctl.h>
     90 #include <dev/wscons/wsdisplay_usl_io.h>
     91 #include "opt_xserver.h"
     92 #endif
     93 
     94 #ifdef USER_LDT
     95 #include <machine/cpu.h>
     96 int linux_read_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *,
     97     register_t *));
     98 int linux_write_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *,
     99     register_t *));
    100 #endif
    101 
    102 /*
    103  * Deal with some i386-specific things in the Linux emulation code.
    104  */
    105 
    106 void
    107 linux_setregs(p, epp, stack)
    108 	struct proc *p;
    109 	struct exec_package *epp;
    110 	u_long stack;
    111 {
    112 	struct pcb *pcb = &p->p_addr->u_pcb;
    113 
    114 	setregs(p, epp, stack);
    115 	pcb->pcb_savefpu.sv_env.en_cw = __Linux_NPXCW__;
    116 }
    117 
    118 /*
    119  * Send an interrupt to process.
    120  *
    121  * Stack is set up to allow sigcode stored
    122  * in u. to call routine, followed by kcall
    123  * to sigreturn routine below.  After sigreturn
    124  * resets the signal mask, the stack, and the
    125  * frame pointer, it returns to the user
    126  * specified pc, psl.
    127  */
    128 
    129 void
    130 linux_sendsig(catcher, sig, mask, code)
    131 	sig_t catcher;
    132 	int sig;
    133 	sigset_t *mask;
    134 	u_long code;
    135 {
    136 	struct proc *p = curproc;
    137 	struct trapframe *tf;
    138 	struct linux_sigframe *fp, frame;
    139 	struct sigacts *psp = p->p_sigacts;
    140 
    141 	tf = p->p_md.md_regs;
    142 
    143 	/* Allocate space for the signal handler context. */
    144 	/* XXX Linux doesn't support the signal stack. */
    145 	fp = (struct linux_sigframe *)tf->tf_esp;
    146 	fp--;
    147 
    148 	/* Build stack frame for signal trampoline. */
    149 	frame.sf_handler = catcher;
    150 	frame.sf_sig = native_to_linux_sig[sig];
    151 
    152 	/* Save register context. */
    153 #ifdef VM86
    154 	if (tf->tf_eflags & PSL_VM) {
    155 		frame.sf_sc.sc_gs = tf->tf_vm86_gs;
    156 		frame.sf_sc.sc_fs = tf->tf_vm86_fs;
    157 		frame.sf_sc.sc_es = tf->tf_vm86_es;
    158 		frame.sf_sc.sc_ds = tf->tf_vm86_ds;
    159 		frame.sf_sc.sc_eflags = get_vflags(p);
    160 	} else
    161 #endif
    162 	{
    163 		__asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs));
    164 		__asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs));
    165 		frame.sf_sc.sc_es = tf->tf_es;
    166 		frame.sf_sc.sc_ds = tf->tf_ds;
    167 		frame.sf_sc.sc_eflags = tf->tf_eflags;
    168 	}
    169 	frame.sf_sc.sc_edi = tf->tf_edi;
    170 	frame.sf_sc.sc_esi = tf->tf_esi;
    171 	frame.sf_sc.sc_ebp = tf->tf_ebp;
    172 	frame.sf_sc.sc_ebx = tf->tf_ebx;
    173 	frame.sf_sc.sc_edx = tf->tf_edx;
    174 	frame.sf_sc.sc_ecx = tf->tf_ecx;
    175 	frame.sf_sc.sc_eax = tf->tf_eax;
    176 	frame.sf_sc.sc_eip = tf->tf_eip;
    177 	frame.sf_sc.sc_cs = tf->tf_cs;
    178 	frame.sf_sc.sc_esp_at_signal = tf->tf_esp;
    179 	frame.sf_sc.sc_ss = tf->tf_ss;
    180 	frame.sf_sc.sc_err = tf->tf_err;
    181 	frame.sf_sc.sc_trapno = tf->tf_trapno;
    182 
    183 	/* Save signal stack. */
    184 	/* XXX Linux doesn't support the signal stack. */
    185 
    186 	/* Save signal mask. */
    187 	native_to_linux_old_sigset(mask, &frame.sf_sc.sc_mask);
    188 
    189 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
    190 		/*
    191 		 * Process has trashed its stack; give it an illegal
    192 		 * instruction to halt it in its tracks.
    193 		 */
    194 		sigexit(p, SIGILL);
    195 		/* NOTREACHED */
    196 	}
    197 
    198 	/*
    199 	 * Build context to run handler in.
    200 	 */
    201 	tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
    202 	tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
    203 	tf->tf_eip = (int)psp->ps_sigcode;
    204 	tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
    205 	tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
    206 	tf->tf_esp = (int)fp;
    207 	tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
    208 
    209 	/* Remember that we're now on the signal stack. */
    210 	/* XXX Linux doesn't support the signal stack. */
    211 }
    212 
    213 /*
    214  * System call to cleanup state after a signal
    215  * has been taken.  Reset signal mask and
    216  * stack state from context left by sendsig (above).
    217  * Return to previous pc and psl as specified by
    218  * context left by sendsig. Check carefully to
    219  * make sure that the user has not modified the
    220  * psl to gain improper privileges or to cause
    221  * a machine fault.
    222  */
    223 int
    224 linux_sys_rt_sigreturn(p, v, retval)
    225 	struct proc *p;
    226 	void *v;
    227 	register_t *retval;
    228 {
    229 	/* XXX XAX write me */
    230 	return(ENOSYS);
    231 }
    232 
    233 int
    234 linux_sys_sigreturn(p, v, retval)
    235 	struct proc *p;
    236 	void *v;
    237 	register_t *retval;
    238 {
    239 	struct linux_sys_sigreturn_args /* {
    240 		syscallarg(struct linux_sigcontext *) scp;
    241 	} */ *uap = v;
    242 	struct linux_sigcontext *scp, context;
    243 	struct trapframe *tf;
    244 	sigset_t mask;
    245 
    246 	/*
    247 	 * The trampoline code hands us the context.
    248 	 * It is unsafe to keep track of it ourselves, in the event that a
    249 	 * program jumps out of a signal handler.
    250 	 */
    251 	scp = SCARG(uap, scp);
    252 	if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
    253 		return (EFAULT);
    254 
    255 	/* Restore register context. */
    256 	tf = p->p_md.md_regs;
    257 #ifdef VM86
    258 	if (context.sc_eflags & PSL_VM) {
    259 		tf->tf_vm86_gs = context.sc_gs;
    260 		tf->tf_vm86_fs = context.sc_fs;
    261 		tf->tf_vm86_es = context.sc_es;
    262 		tf->tf_vm86_ds = context.sc_ds;
    263 		set_vflags(p, context.sc_eflags);
    264 	} else
    265 #endif
    266 	{
    267 		/*
    268 		 * Check for security violations.  If we're returning to
    269 		 * protected mode, the CPU will validate the segment registers
    270 		 * automatically and generate a trap on violations.  We handle
    271 		 * the trap, rather than doing all of the checking here.
    272 		 */
    273 		if (((context.sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 ||
    274 		    !USERMODE(context.sc_cs, context.sc_eflags))
    275 			return (EINVAL);
    276 
    277 		/* %fs and %gs were restored by the trampoline. */
    278 		tf->tf_es = context.sc_es;
    279 		tf->tf_ds = context.sc_ds;
    280 		tf->tf_eflags = context.sc_eflags;
    281 	}
    282 	tf->tf_edi = context.sc_edi;
    283 	tf->tf_esi = context.sc_esi;
    284 	tf->tf_ebp = context.sc_ebp;
    285 	tf->tf_ebx = context.sc_ebx;
    286 	tf->tf_edx = context.sc_edx;
    287 	tf->tf_ecx = context.sc_ecx;
    288 	tf->tf_eax = context.sc_eax;
    289 	tf->tf_eip = context.sc_eip;
    290 	tf->tf_cs = context.sc_cs;
    291 	tf->tf_esp = context.sc_esp_at_signal;
    292 	tf->tf_ss = context.sc_ss;
    293 
    294 	/* Restore signal stack. */
    295 	p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
    296 
    297 	/* Restore signal mask. */
    298 	linux_old_to_native_sigset(&context.sc_mask, &mask);
    299 	(void) sigprocmask1(p, SIG_SETMASK, &mask, 0);
    300 
    301 	return (EJUSTRETURN);
    302 }
    303 
    304 #ifdef USER_LDT
    305 
    306 int
    307 linux_read_ldt(p, uap, retval)
    308 	struct proc *p;
    309 	struct linux_sys_modify_ldt_args /* {
    310 		syscallarg(int) func;
    311 		syscallarg(void *) ptr;
    312 		syscallarg(size_t) bytecount;
    313 	} */ *uap;
    314 	register_t *retval;
    315 {
    316 	struct i386_get_ldt_args gl;
    317 	int error;
    318 	caddr_t sg;
    319 	char *parms;
    320 
    321 	sg = stackgap_init(p->p_emul);
    322 
    323 	gl.start = 0;
    324 	gl.desc = SCARG(uap, ptr);
    325 	gl.num = SCARG(uap, bytecount) / sizeof(union descriptor);
    326 
    327 	parms = stackgap_alloc(&sg, sizeof(gl));
    328 
    329 	if ((error = copyout(&gl, parms, sizeof(gl))) != 0)
    330 		return (error);
    331 
    332 	if ((error = i386_get_ldt(p, parms, retval)) != 0)
    333 		return (error);
    334 
    335 	*retval *= sizeof(union descriptor);
    336 	return (0);
    337 }
    338 
    339 struct linux_ldt_info {
    340 	u_int entry_number;
    341 	u_long base_addr;
    342 	u_int limit;
    343 	u_int seg_32bit:1;
    344 	u_int contents:2;
    345 	u_int read_exec_only:1;
    346 	u_int limit_in_pages:1;
    347 	u_int seg_not_present:1;
    348 };
    349 
    350 int
    351 linux_write_ldt(p, uap, retval)
    352 	struct proc *p;
    353 	struct linux_sys_modify_ldt_args /* {
    354 		syscallarg(int) func;
    355 		syscallarg(void *) ptr;
    356 		syscallarg(size_t) bytecount;
    357 	} */ *uap;
    358 	register_t *retval;
    359 {
    360 	struct linux_ldt_info ldt_info;
    361 	struct segment_descriptor sd;
    362 	struct i386_set_ldt_args sl;
    363 	int error;
    364 	caddr_t sg;
    365 	char *parms;
    366 
    367 	if (SCARG(uap, bytecount) != sizeof(ldt_info))
    368 		return (EINVAL);
    369 	if ((error = copyin(SCARG(uap, ptr), &ldt_info, sizeof(ldt_info))) != 0)
    370 		return error;
    371 	if (ldt_info.contents == 3)
    372 		return (EINVAL);
    373 
    374 	sg = stackgap_init(p->p_emul);
    375 
    376 	sd.sd_lobase = ldt_info.base_addr & 0xffffff;
    377 	sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff;
    378 	sd.sd_lolimit = ldt_info.limit & 0xffff;
    379 	sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf;
    380 	sd.sd_type =
    381 	    16 | (ldt_info.contents << 2) | (!ldt_info.read_exec_only << 1);
    382 	sd.sd_dpl = SEL_UPL;
    383 	sd.sd_p = !ldt_info.seg_not_present;
    384 	sd.sd_def32 = ldt_info.seg_32bit;
    385 	sd.sd_gran = ldt_info.limit_in_pages;
    386 
    387 	sl.start = ldt_info.entry_number;
    388 	sl.desc = stackgap_alloc(&sg, sizeof(sd));
    389 	sl.num = 1;
    390 
    391 #if 0
    392 	printf("linux_write_ldt: idx=%d, base=%x, limit=%x\n",
    393 	    ldt_info.entry_number, ldt_info.base_addr, ldt_info.limit);
    394 #endif
    395 
    396 	parms = stackgap_alloc(&sg, sizeof(sl));
    397 
    398 	if ((error = copyout(&sd, sl.desc, sizeof(sd))) != 0)
    399 		return (error);
    400 	if ((error = copyout(&sl, parms, sizeof(sl))) != 0)
    401 		return (error);
    402 
    403 	if ((error = i386_set_ldt(p, parms, retval)) != 0)
    404 		return (error);
    405 
    406 	*retval = 0;
    407 	return (0);
    408 }
    409 
    410 #endif /* USER_LDT */
    411 
    412 int
    413 linux_sys_modify_ldt(p, v, retval)
    414 	struct proc *p;
    415 	void *v;
    416 	register_t *retval;
    417 {
    418 	struct linux_sys_modify_ldt_args /* {
    419 		syscallarg(int) func;
    420 		syscallarg(void *) ptr;
    421 		syscallarg(size_t) bytecount;
    422 	} */ *uap = v;
    423 
    424 	switch (SCARG(uap, func)) {
    425 #ifdef USER_LDT
    426 	case 0:
    427 		return (linux_read_ldt(p, uap, retval));
    428 
    429 	case 1:
    430 		return (linux_write_ldt(p, uap, retval));
    431 #endif /* USER_LDT */
    432 
    433 	default:
    434 		return (ENOSYS);
    435 	}
    436 }
    437 
    438 /*
    439  * XXX Pathetic hack to make svgalib work. This will fake the major
    440  * device number of an opened VT so that svgalib likes it. grmbl.
    441  * Should probably do it 'wrong the right way' and use a mapping
    442  * array for all major device numbers, and map linux_mknod too.
    443  */
    444 dev_t
    445 linux_fakedev(dev)
    446 	dev_t dev;
    447 {
    448 #if (NWSDISPLAY > 0)
    449 	if (major(dev) == NETBSD_WSCONS_MAJOR)
    450 		return makedev(LINUX_CONS_MAJOR, (minor(dev) + 1));
    451 #endif
    452 	return dev;
    453 }
    454 
    455 #if (NWSDISPLAY > 0)
    456 /*
    457  * That's not complete, but enough to get an X server running.
    458  */
    459 #define NR_KEYS 128
    460 static u_short plain_map[NR_KEYS] = {
    461 	0x0200,	0x001b,	0x0031,	0x0032,	0x0033,	0x0034,	0x0035,	0x0036,
    462 	0x0037,	0x0038,	0x0039,	0x0030,	0x002d,	0x003d,	0x007f,	0x0009,
    463 	0x0b71,	0x0b77,	0x0b65,	0x0b72,	0x0b74,	0x0b79,	0x0b75,	0x0b69,
    464 	0x0b6f,	0x0b70,	0x005b,	0x005d,	0x0201,	0x0702,	0x0b61,	0x0b73,
    465 	0x0b64,	0x0b66,	0x0b67,	0x0b68,	0x0b6a,	0x0b6b,	0x0b6c,	0x003b,
    466 	0x0027,	0x0060,	0x0700,	0x005c,	0x0b7a,	0x0b78,	0x0b63,	0x0b76,
    467 	0x0b62,	0x0b6e,	0x0b6d,	0x002c,	0x002e,	0x002f,	0x0700,	0x030c,
    468 	0x0703,	0x0020,	0x0207,	0x0100,	0x0101,	0x0102,	0x0103,	0x0104,
    469 	0x0105,	0x0106,	0x0107,	0x0108,	0x0109,	0x0208,	0x0209,	0x0307,
    470 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,
    471 	0x0302,	0x0303,	0x0300,	0x0310,	0x0206,	0x0200,	0x003c,	0x010a,
    472 	0x010b,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,
    473 	0x030e,	0x0702,	0x030d,	0x001c,	0x0701,	0x0205,	0x0114,	0x0603,
    474 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,
    475 	0x011a,	0x010c,	0x010d,	0x011b,	0x011c,	0x0110,	0x0311,	0x011d,
    476 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,
    477 }, shift_map[NR_KEYS] = {
    478 	0x0200,	0x001b,	0x0021,	0x0040,	0x0023,	0x0024,	0x0025,	0x005e,
    479 	0x0026,	0x002a,	0x0028,	0x0029,	0x005f,	0x002b,	0x007f,	0x0009,
    480 	0x0b51,	0x0b57,	0x0b45,	0x0b52,	0x0b54,	0x0b59,	0x0b55,	0x0b49,
    481 	0x0b4f,	0x0b50,	0x007b,	0x007d,	0x0201,	0x0702,	0x0b41,	0x0b53,
    482 	0x0b44,	0x0b46,	0x0b47,	0x0b48,	0x0b4a,	0x0b4b,	0x0b4c,	0x003a,
    483 	0x0022,	0x007e,	0x0700,	0x007c,	0x0b5a,	0x0b58,	0x0b43,	0x0b56,
    484 	0x0b42,	0x0b4e,	0x0b4d,	0x003c,	0x003e,	0x003f,	0x0700,	0x030c,
    485 	0x0703,	0x0020,	0x0207,	0x010a,	0x010b,	0x010c,	0x010d,	0x010e,
    486 	0x010f,	0x0110,	0x0111,	0x0112,	0x0113,	0x0213,	0x0203,	0x0307,
    487 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,
    488 	0x0302,	0x0303,	0x0300,	0x0310,	0x0206,	0x0200,	0x003e,	0x010a,
    489 	0x010b,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,
    490 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,
    491 	0x020b,	0x0601,	0x0602,	0x0117,	0x0600,	0x020a,	0x0115,	0x0116,
    492 	0x011a,	0x010c,	0x010d,	0x011b,	0x011c,	0x0110,	0x0311,	0x011d,
    493 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,
    494 }, altgr_map[NR_KEYS] = {
    495 	0x0200,	0x0200,	0x0200,	0x0040,	0x0200,	0x0024,	0x0200,	0x0200,
    496 	0x007b,	0x005b,	0x005d,	0x007d,	0x005c,	0x0200,	0x0200,	0x0200,
    497 	0x0b71,	0x0b77,	0x0918,	0x0b72,	0x0b74,	0x0b79,	0x0b75,	0x0b69,
    498 	0x0b6f,	0x0b70,	0x0200,	0x007e,	0x0201,	0x0702,	0x0914,	0x0b73,
    499 	0x0917,	0x0919,	0x0b67,	0x0b68,	0x0b6a,	0x0b6b,	0x0b6c,	0x0200,
    500 	0x0200,	0x0200,	0x0700,	0x0200,	0x0b7a,	0x0b78,	0x0916,	0x0b76,
    501 	0x0915,	0x0b6e,	0x0b6d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,
    502 	0x0703,	0x0200,	0x0207,	0x050c,	0x050d,	0x050e,	0x050f,	0x0510,
    503 	0x0511,	0x0512,	0x0513,	0x0514,	0x0515,	0x0208,	0x0202,	0x0911,
    504 	0x0912,	0x0913,	0x030b,	0x090e,	0x090f,	0x0910,	0x030a,	0x090b,
    505 	0x090c,	0x090d,	0x090a,	0x0310,	0x0206,	0x0200,	0x007c,	0x0516,
    506 	0x0517,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,
    507 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,
    508 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,
    509 	0x011a,	0x010c,	0x010d,	0x011b,	0x011c,	0x0110,	0x0311,	0x011d,
    510 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,
    511 }, ctrl_map[NR_KEYS] = {
    512 	0x0200,	0x0200,	0x0200,	0x0000,	0x001b,	0x001c,	0x001d,	0x001e,
    513 	0x001f,	0x007f,	0x0200,	0x0200,	0x001f,	0x0200,	0x0008,	0x0200,
    514 	0x0011,	0x0017,	0x0005,	0x0012,	0x0014,	0x0019,	0x0015,	0x0009,
    515 	0x000f,	0x0010,	0x001b,	0x001d,	0x0201,	0x0702,	0x0001,	0x0013,
    516 	0x0004,	0x0006,	0x0007,	0x0008,	0x000a,	0x000b,	0x000c,	0x0200,
    517 	0x0007,	0x0000,	0x0700,	0x001c,	0x001a,	0x0018,	0x0003,	0x0016,
    518 	0x0002,	0x000e,	0x000d,	0x0200,	0x020e,	0x007f,	0x0700,	0x030c,
    519 	0x0703,	0x0000,	0x0207,	0x0100,	0x0101,	0x0102,	0x0103,	0x0104,
    520 	0x0105,	0x0106,	0x0107,	0x0108,	0x0109,	0x0208,	0x0204,	0x0307,
    521 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,
    522 	0x0302,	0x0303,	0x0300,	0x0310,	0x0206,	0x0200,	0x0200,	0x010a,
    523 	0x010b,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,
    524 	0x030e,	0x0702,	0x030d,	0x001c,	0x0701,	0x0205,	0x0114,	0x0603,
    525 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,
    526 	0x011a,	0x010c,	0x010d,	0x011b,	0x011c,	0x0110,	0x0311,	0x011d,
    527 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,
    528 };
    529 
    530 u_short *linux_keytabs[] = {
    531 	plain_map, shift_map, altgr_map, altgr_map, ctrl_map
    532 };
    533 #endif
    534 
    535 /*
    536  * We come here in a last attempt to satisfy a Linux ioctl() call
    537  */
    538 int
    539 linux_machdepioctl(p, v, retval)
    540 	struct proc *p;
    541 	void *v;
    542 	register_t *retval;
    543 {
    544 	struct linux_sys_ioctl_args /* {
    545 		syscallarg(int) fd;
    546 		syscallarg(u_long) com;
    547 		syscallarg(caddr_t) data;
    548 	} */ *uap = v;
    549 	struct sys_ioctl_args bia;
    550 	u_long com;
    551 #if (NWSDISPLAY > 0)
    552 	int error;
    553 	struct vt_mode lvt;
    554 	caddr_t bvtp, sg;
    555 	struct kbentry kbe;
    556 #endif
    557 
    558 	SCARG(&bia, fd) = SCARG(uap, fd);
    559 	SCARG(&bia, data) = SCARG(uap, data);
    560 	com = SCARG(uap, com);
    561 
    562 	switch (com) {
    563 #if (NWSDISPLAY > 0)
    564 	case LINUX_KDGKBMODE:
    565 		com = KDGKBMODE;
    566 		break;
    567 	case LINUX_KDSKBMODE:
    568 		com = KDSKBMODE;
    569 		if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW)
    570 			SCARG(&bia, data) = (caddr_t)K_RAW;
    571 		break;
    572 	case LINUX_KDMKTONE:
    573 		com = KDMKTONE;
    574 		break;
    575 	case LINUX_KDSETMODE:
    576 		com = KDSETMODE;
    577 		break;
    578 	case LINUX_KDENABIO:
    579 		com = KDENABIO;
    580 		break;
    581 	case LINUX_KDDISABIO:
    582 		com = KDDISABIO;
    583 		break;
    584 	case LINUX_KDGETLED:
    585 		com = KDGETLED;
    586 		break;
    587 	case LINUX_KDSETLED:
    588 		com = KDSETLED;
    589 		break;
    590 	case LINUX_VT_OPENQRY:
    591 		com = VT_OPENQRY;
    592 		break;
    593 	case LINUX_VT_GETMODE:
    594 		SCARG(&bia, com) = VT_GETMODE;
    595 		if ((error = sys_ioctl(p, &bia, retval)))
    596 			return error;
    597 		if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
    598 		    sizeof (struct vt_mode))))
    599 			return error;
    600 		lvt.relsig = native_to_linux_sig[lvt.relsig];
    601 		lvt.acqsig = native_to_linux_sig[lvt.acqsig];
    602 		lvt.frsig = native_to_linux_sig[lvt.frsig];
    603 		return copyout((caddr_t)&lvt, SCARG(uap, data),
    604 		    sizeof (struct vt_mode));
    605 	case LINUX_VT_SETMODE:
    606 		com = VT_SETMODE;
    607 		if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
    608 		    sizeof (struct vt_mode))))
    609 			return error;
    610 		lvt.relsig = linux_to_native_sig[lvt.relsig];
    611 		lvt.acqsig = linux_to_native_sig[lvt.acqsig];
    612 		lvt.frsig = linux_to_native_sig[lvt.frsig];
    613 		sg = stackgap_init(p->p_emul);
    614 		bvtp = stackgap_alloc(&sg, sizeof (struct vt_mode));
    615 		if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode))))
    616 			return error;
    617 		SCARG(&bia, data) = bvtp;
    618 		break;
    619 	case LINUX_VT_RELDISP:
    620 		com = VT_RELDISP;
    621 		break;
    622 	case LINUX_VT_ACTIVATE:
    623 		com = VT_ACTIVATE;
    624 		break;
    625 	case LINUX_VT_WAITACTIVE:
    626 		com = VT_WAITACTIVE;
    627 		break;
    628 	case LINUX_VT_GETSTATE:
    629 		com = VT_GETSTATE;
    630 		break;
    631 	case LINUX_KDGKBTYPE:
    632 		/* This is what Linux does. */
    633 		return (subyte(SCARG(uap, data), KB_101));
    634 	case LINUX_KDGKBENT:
    635 		/*
    636 		 * The Linux KDGKBENT ioctl is different from the
    637 		 * SYSV original. So we handle it in machdep code.
    638 		 * XXX We should use keyboard mapping information
    639 		 * from wsdisplay, but this would be expensive.
    640 		 */
    641 		if ((error = copyin(SCARG(uap, data), &kbe,
    642 				    sizeof(struct kbentry))))
    643 			return (error);
    644 		if (kbe.kb_table >= sizeof(linux_keytabs) / sizeof(u_short *)
    645 		    || kbe.kb_index >= NR_KEYS)
    646 			return (EINVAL);
    647 		kbe.kb_value = linux_keytabs[kbe.kb_table][kbe.kb_index];
    648 		return (copyout(&kbe, SCARG(uap, data),
    649 				sizeof(struct kbentry)));
    650 #endif
    651 	default:
    652 		printf("linux_machdepioctl: invalid ioctl %08lx\n", com);
    653 		return EINVAL;
    654 	}
    655 	SCARG(&bia, com) = com;
    656 	return sys_ioctl(p, &bia, retval);
    657 }
    658 
    659 /*
    660  * Set I/O permissions for a process. Just set the maximum level
    661  * right away (ignoring the argument), otherwise we would have
    662  * to rely on I/O permission maps, which are not implemented.
    663  */
    664 int
    665 linux_sys_iopl(p, v, retval)
    666 	struct proc *p;
    667 	void *v;
    668 	register_t *retval;
    669 {
    670 #if 0
    671 	struct linux_sys_iopl_args /* {
    672 		syscallarg(int) level;
    673 	} */ *uap = v;
    674 #endif
    675 	struct trapframe *fp = p->p_md.md_regs;
    676 
    677 	if (suser(p->p_ucred, &p->p_acflag) != 0)
    678 		return EPERM;
    679 	fp->tf_eflags |= PSL_IOPL;
    680 	*retval = 0;
    681 	return 0;
    682 }
    683 
    684 /*
    685  * See above. If a root process tries to set access to an I/O port,
    686  * just let it have the whole range.
    687  */
    688 int
    689 linux_sys_ioperm(p, v, retval)
    690 	struct proc *p;
    691 	void *v;
    692 	register_t *retval;
    693 {
    694 	struct linux_sys_ioperm_args /* {
    695 		syscallarg(unsigned int) lo;
    696 		syscallarg(unsigned int) hi;
    697 		syscallarg(int) val;
    698 	} */ *uap = v;
    699 	struct trapframe *fp = p->p_md.md_regs;
    700 
    701 	if (suser(p->p_ucred, &p->p_acflag) != 0)
    702 		return EPERM;
    703 	if (SCARG(uap, val))
    704 		fp->tf_eflags |= PSL_IOPL;
    705 	*retval = 0;
    706 	return 0;
    707 }
    708