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