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