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