Home | History | Annotate | Line # | Download | only in i386
linux_machdep.c revision 1.44
      1 /*	$NetBSD: linux_machdep.c,v 1.44 1998/10/03 20:17:38 christos 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/common/linux_types.h>
     61 #include <compat/linux/common/linux_signal.h>
     62 #include <compat/linux/common/linux_util.h>
     63 #include <compat/linux/common/linux_ioctl.h>
     64 #include <compat/linux/common/linux_exec.h>
     65 #include <compat/linux/common/linux_machdep.h>
     66 
     67 #include <compat/linux/linux_syscallargs.h>
     68 
     69 #include <machine/cpu.h>
     70 #include <machine/cpufunc.h>
     71 #include <machine/psl.h>
     72 #include <machine/reg.h>
     73 #include <machine/segments.h>
     74 #include <machine/specialreg.h>
     75 #include <machine/sysarch.h>
     76 #include <machine/vm86.h>
     77 #include <machine/vmparam.h>
     78 
     79 /*
     80  * To see whether pcvt is configured (for virtual console ioctl calls).
     81  */
     82 #ifndef NVT
     83 #include "vt.h"
     84 #endif
     85 #if NVT > 0
     86 #include <arch/i386/isa/pcvt/pcvt_ioctl.h>
     87 #endif
     88 
     89 #include "wsdisplay.h"
     90 #if (NWSDISPLAY > 0)
     91 #include <sys/ioctl.h>
     92 #include <dev/wscons/wsdisplay_usl_io.h>
     93 #include "opt_xserver.h"
     94 #endif
     95 
     96 #ifdef USER_LDT
     97 #include <machine/cpu.h>
     98 int linux_read_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *,
     99     register_t *));
    100 int linux_write_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *,
    101     register_t *));
    102 #endif
    103 
    104 /*
    105  * Deal with some i386-specific things in the Linux emulation code.
    106  */
    107 
    108 void
    109 linux_setregs(p, epp, stack)
    110 	struct proc *p;
    111 	struct exec_package *epp;
    112 	u_long stack;
    113 {
    114 	register struct pcb *pcb = &p->p_addr->u_pcb;
    115 
    116 	pcb->pcb_savefpu.sv_env.en_cw = __Linux_NPXCW__;
    117 	setregs(p, epp, stack);
    118 }
    119 
    120 /*
    121  * Send an interrupt to process.
    122  *
    123  * Stack is set up to allow sigcode stored
    124  * in u. to call routine, followed by kcall
    125  * to sigreturn routine below.  After sigreturn
    126  * resets the signal mask, the stack, and the
    127  * frame pointer, it returns to the user
    128  * specified pc, psl.
    129  */
    130 
    131 void
    132 linux_sendsig(catcher, sig, mask, code)
    133 	sig_t catcher;
    134 	int sig;
    135 	sigset_t *mask;
    136 	u_long code;
    137 {
    138 	register struct proc *p = curproc;
    139 	register struct trapframe *tf;
    140 	struct linux_sigframe *fp, frame;
    141 	struct sigacts *psp = p->p_sigacts;
    142 
    143 	tf = p->p_md.md_regs;
    144 
    145 	/* Allocate space for the signal handler context. */
    146 	/* XXX Linux doesn't support the signal stack. */
    147 	fp = (struct linux_sigframe *)tf->tf_esp;
    148 	fp--;
    149 
    150 	/* Build stack frame for signal trampoline. */
    151 	frame.sf_handler = catcher;
    152 	frame.sf_sig = native_to_linux_sig[sig];
    153 
    154 	/* Save register context. */
    155 #ifdef VM86
    156 	if (tf->tf_eflags & PSL_VM) {
    157 		frame.sf_sc.sc_gs = tf->tf_vm86_gs;
    158 		frame.sf_sc.sc_fs = tf->tf_vm86_fs;
    159 		frame.sf_sc.sc_es = tf->tf_vm86_es;
    160 		frame.sf_sc.sc_ds = tf->tf_vm86_ds;
    161 		frame.sf_sc.sc_eflags = get_vflags(p);
    162 	} else
    163 #endif
    164 	{
    165 		__asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs));
    166 		__asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs));
    167 		frame.sf_sc.sc_es = tf->tf_es;
    168 		frame.sf_sc.sc_ds = tf->tf_ds;
    169 		frame.sf_sc.sc_eflags = tf->tf_eflags;
    170 	}
    171 	frame.sf_sc.sc_edi = tf->tf_edi;
    172 	frame.sf_sc.sc_esi = tf->tf_esi;
    173 	frame.sf_sc.sc_ebp = tf->tf_ebp;
    174 	frame.sf_sc.sc_ebx = tf->tf_ebx;
    175 	frame.sf_sc.sc_edx = tf->tf_edx;
    176 	frame.sf_sc.sc_ecx = tf->tf_ecx;
    177 	frame.sf_sc.sc_eax = tf->tf_eax;
    178 	frame.sf_sc.sc_eip = tf->tf_eip;
    179 	frame.sf_sc.sc_cs = tf->tf_cs;
    180 	frame.sf_sc.sc_esp_at_signal = tf->tf_esp;
    181 	frame.sf_sc.sc_ss = tf->tf_ss;
    182 	frame.sf_sc.sc_err = tf->tf_err;
    183 	frame.sf_sc.sc_trapno = tf->tf_trapno;
    184 
    185 	/* Save signal stack. */
    186 	/* XXX Linux doesn't support the signal stack. */
    187 
    188 	/* Save signal mask. */
    189 	native_to_linux_sigset(mask, &frame.sf_sc.sc_mask);
    190 
    191 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
    192 		/*
    193 		 * Process has trashed its stack; give it an illegal
    194 		 * instruction to halt it in its tracks.
    195 		 */
    196 		sigexit(p, SIGILL);
    197 		/* NOTREACHED */
    198 	}
    199 
    200 	/*
    201 	 * Build context to run handler in.
    202 	 */
    203 	tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
    204 	tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
    205 	tf->tf_eip = (int)psp->ps_sigcode;
    206 	tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
    207 	tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
    208 	tf->tf_esp = (int)fp;
    209 	tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
    210 
    211 	/* Remember that we're now on the signal stack. */
    212 	/* XXX Linux doesn't support the signal stack. */
    213 }
    214 
    215 /*
    216  * System call to cleanup state after a signal
    217  * has been taken.  Reset signal mask and
    218  * stack state from context left by sendsig (above).
    219  * Return to previous pc and psl as specified by
    220  * context left by sendsig. Check carefully to
    221  * make sure that the user has not modified the
    222  * psl to gain improper privileges or to cause
    223  * a machine fault.
    224  */
    225 int
    226 linux_sys_rt_sigreturn(p, v, retval)
    227 	struct proc *p;
    228 	void *v;
    229 	register_t *retval;
    230 {
    231 	/* XXX XAX write me */
    232 	return(ENOSYS);
    233 }
    234 
    235 int
    236 linux_sys_sigreturn(p, v, retval)
    237 	struct proc *p;
    238 	void *v;
    239 	register_t *retval;
    240 {
    241 	struct linux_sys_sigreturn_args /* {
    242 		syscallarg(struct linux_sigcontext *) scp;
    243 	} */ *uap = v;
    244 	struct linux_sigcontext *scp, context;
    245 	register struct trapframe *tf;
    246 	sigset_t mask;
    247 
    248 	/*
    249 	 * The trampoline code hands us the context.
    250 	 * It is unsafe to keep track of it ourselves, in the event that a
    251 	 * program jumps out of a signal handler.
    252 	 */
    253 	scp = SCARG(uap, scp);
    254 	if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
    255 		return (EFAULT);
    256 
    257 	/* Restore register context. */
    258 	tf = p->p_md.md_regs;
    259 #ifdef VM86
    260 	if (context.sc_eflags & PSL_VM) {
    261 		tf->tf_vm86_gs = context.sc_gs;
    262 		tf->tf_vm86_fs = context.sc_fs;
    263 		tf->tf_vm86_es = context.sc_es;
    264 		tf->tf_vm86_ds = context.sc_ds;
    265 		set_vflags(p, context.sc_eflags);
    266 	} else
    267 #endif
    268 	{
    269 		/*
    270 		 * Check for security violations.  If we're returning to
    271 		 * protected mode, the CPU will validate the segment registers
    272 		 * automatically and generate a trap on violations.  We handle
    273 		 * the trap, rather than doing all of the checking here.
    274 		 */
    275 		if (((context.sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 ||
    276 		    !USERMODE(context.sc_cs, context.sc_eflags))
    277 			return (EINVAL);
    278 
    279 		/* %fs and %gs were restored by the trampoline. */
    280 		tf->tf_es = context.sc_es;
    281 		tf->tf_ds = context.sc_ds;
    282 		tf->tf_eflags = context.sc_eflags;
    283 	}
    284 	tf->tf_edi = context.sc_edi;
    285 	tf->tf_esi = context.sc_esi;
    286 	tf->tf_ebp = context.sc_ebp;
    287 	tf->tf_ebx = context.sc_ebx;
    288 	tf->tf_edx = context.sc_edx;
    289 	tf->tf_ecx = context.sc_ecx;
    290 	tf->tf_eax = context.sc_eax;
    291 	tf->tf_eip = context.sc_eip;
    292 	tf->tf_cs = context.sc_cs;
    293 	tf->tf_esp = context.sc_esp_at_signal;
    294 	tf->tf_ss = context.sc_ss;
    295 
    296 	/* Restore signal stack. */
    297 	p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
    298 
    299 	/* Restore signal mask. */
    300 	linux_to_native_sigset(&context.sc_mask, &mask);
    301 	(void) sigprocmask1(p, SIG_SETMASK, &mask, 0);
    302 
    303 	return (EJUSTRETURN);
    304 }
    305 
    306 #ifdef USER_LDT
    307 
    308 int
    309 linux_read_ldt(p, uap, retval)
    310 	struct proc *p;
    311 	struct linux_sys_modify_ldt_args /* {
    312 		syscallarg(int) func;
    313 		syscallarg(void *) ptr;
    314 		syscallarg(size_t) bytecount;
    315 	} */ *uap;
    316 	register_t *retval;
    317 {
    318 	struct i386_get_ldt_args gl;
    319 	int error;
    320 	caddr_t sg;
    321 	char *parms;
    322 
    323 	sg = stackgap_init(p->p_emul);
    324 
    325 	gl.start = 0;
    326 	gl.desc = SCARG(uap, ptr);
    327 	gl.num = SCARG(uap, bytecount) / sizeof(union descriptor);
    328 
    329 	parms = stackgap_alloc(&sg, sizeof(gl));
    330 
    331 	if ((error = copyout(&gl, parms, sizeof(gl))) != 0)
    332 		return (error);
    333 
    334 	if ((error = i386_get_ldt(p, parms, retval)) != 0)
    335 		return (error);
    336 
    337 	*retval *= sizeof(union descriptor);
    338 	return (0);
    339 }
    340 
    341 struct linux_ldt_info {
    342 	u_int entry_number;
    343 	u_long base_addr;
    344 	u_int limit;
    345 	u_int seg_32bit:1;
    346 	u_int contents:2;
    347 	u_int read_exec_only:1;
    348 	u_int limit_in_pages:1;
    349 	u_int seg_not_present:1;
    350 };
    351 
    352 int
    353 linux_write_ldt(p, uap, retval)
    354 	struct proc *p;
    355 	struct linux_sys_modify_ldt_args /* {
    356 		syscallarg(int) func;
    357 		syscallarg(void *) ptr;
    358 		syscallarg(size_t) bytecount;
    359 	} */ *uap;
    360 	register_t *retval;
    361 {
    362 	struct linux_ldt_info ldt_info;
    363 	struct segment_descriptor sd;
    364 	struct i386_set_ldt_args sl;
    365 	int error;
    366 	caddr_t sg;
    367 	char *parms;
    368 
    369 	if (SCARG(uap, bytecount) != sizeof(ldt_info))
    370 		return (EINVAL);
    371 	if ((error = copyin(SCARG(uap, ptr), &ldt_info, sizeof(ldt_info))) != 0)
    372 		return error;
    373 	if (ldt_info.contents == 3)
    374 		return (EINVAL);
    375 
    376 	sg = stackgap_init(p->p_emul);
    377 
    378 	sd.sd_lobase = ldt_info.base_addr & 0xffffff;
    379 	sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff;
    380 	sd.sd_lolimit = ldt_info.limit & 0xffff;
    381 	sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf;
    382 	sd.sd_type =
    383 	    16 | (ldt_info.contents << 2) | (!ldt_info.read_exec_only << 1);
    384 	sd.sd_dpl = SEL_UPL;
    385 	sd.sd_p = !ldt_info.seg_not_present;
    386 	sd.sd_def32 = ldt_info.seg_32bit;
    387 	sd.sd_gran = ldt_info.limit_in_pages;
    388 
    389 	sl.start = ldt_info.entry_number;
    390 	sl.desc = stackgap_alloc(&sg, sizeof(sd));
    391 	sl.num = 1;
    392 
    393 #if 0
    394 	printf("linux_write_ldt: idx=%d, base=%x, limit=%x\n",
    395 	    ldt_info.entry_number, ldt_info.base_addr, ldt_info.limit);
    396 #endif
    397 
    398 	parms = stackgap_alloc(&sg, sizeof(sl));
    399 
    400 	if ((error = copyout(&sd, sl.desc, sizeof(sd))) != 0)
    401 		return (error);
    402 	if ((error = copyout(&sl, parms, sizeof(sl))) != 0)
    403 		return (error);
    404 
    405 	if ((error = i386_set_ldt(p, parms, retval)) != 0)
    406 		return (error);
    407 
    408 	*retval = 0;
    409 	return (0);
    410 }
    411 
    412 #endif /* USER_LDT */
    413 
    414 int
    415 linux_sys_modify_ldt(p, v, retval)
    416 	struct proc *p;
    417 	void *v;
    418 	register_t *retval;
    419 {
    420 	struct linux_sys_modify_ldt_args /* {
    421 		syscallarg(int) func;
    422 		syscallarg(void *) ptr;
    423 		syscallarg(size_t) bytecount;
    424 	} */ *uap = v;
    425 
    426 	switch (SCARG(uap, func)) {
    427 #ifdef USER_LDT
    428 	case 0:
    429 		return (linux_read_ldt(p, uap, retval));
    430 
    431 	case 1:
    432 		return (linux_write_ldt(p, uap, retval));
    433 #endif /* USER_LDT */
    434 
    435 	default:
    436 		return (ENOSYS);
    437 	}
    438 }
    439 
    440 /*
    441  * XXX Pathetic hack to make svgalib work. This will fake the major
    442  * device number of an opened VT so that svgalib likes it. grmbl.
    443  * Should probably do it 'wrong the right way' and use a mapping
    444  * array for all major device numbers, and map linux_mknod too.
    445  */
    446 dev_t
    447 linux_fakedev(dev)
    448 	dev_t dev;
    449 {
    450 #if (NVT > 0)
    451 	if (major(dev) == NETBSD_PCCONS_MAJOR)
    452 		return makedev(LINUX_CONS_MAJOR, (minor(dev) + 1));
    453 #endif
    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) && defined(XSERVER)
    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 (NVT > 0) || (NWSDISPLAY > 0)
    558 	int error;
    559 	struct vt_mode lvt;
    560 	caddr_t bvtp, sg;
    561 #endif
    562 #if (NWSDISPLAY > 0) && defined(XSERVER)
    563 	struct kbentry kbe;
    564 #endif
    565 
    566 	SCARG(&bia, fd) = SCARG(uap, fd);
    567 	SCARG(&bia, data) = SCARG(uap, data);
    568 	com = SCARG(uap, com);
    569 
    570 	switch (com) {
    571 #if (NVT > 0) || (NWSDISPLAY > 0)
    572 	case LINUX_KDGKBMODE:
    573 		com = KDGKBMODE;
    574 		break;
    575 	case LINUX_KDSKBMODE:
    576 		com = KDSKBMODE;
    577 		if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW)
    578 			SCARG(&bia, data) = (caddr_t)K_RAW;
    579 		break;
    580 	case LINUX_KDMKTONE:
    581 		com = KDMKTONE;
    582 		break;
    583 	case LINUX_KDSETMODE:
    584 		com = KDSETMODE;
    585 		break;
    586 	case LINUX_KDENABIO:
    587 		com = KDENABIO;
    588 		break;
    589 	case LINUX_KDDISABIO:
    590 		com = KDDISABIO;
    591 		break;
    592 	case LINUX_KDGETLED:
    593 		com = KDGETLED;
    594 		break;
    595 	case LINUX_KDSETLED:
    596 		com = KDSETLED;
    597 		break;
    598 	case LINUX_VT_OPENQRY:
    599 		com = VT_OPENQRY;
    600 		break;
    601 	case LINUX_VT_GETMODE:
    602 		SCARG(&bia, com) = VT_GETMODE;
    603 		if ((error = sys_ioctl(p, &bia, retval)))
    604 			return error;
    605 		if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
    606 		    sizeof (struct vt_mode))))
    607 			return error;
    608 		lvt.relsig = native_to_linux_sig[lvt.relsig];
    609 		lvt.acqsig = native_to_linux_sig[lvt.acqsig];
    610 		lvt.frsig = native_to_linux_sig[lvt.frsig];
    611 		return copyout((caddr_t)&lvt, SCARG(uap, data),
    612 		    sizeof (struct vt_mode));
    613 	case LINUX_VT_SETMODE:
    614 		com = VT_SETMODE;
    615 		if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
    616 		    sizeof (struct vt_mode))))
    617 			return error;
    618 		lvt.relsig = linux_to_native_sig[lvt.relsig];
    619 		lvt.acqsig = linux_to_native_sig[lvt.acqsig];
    620 		lvt.frsig = linux_to_native_sig[lvt.frsig];
    621 		sg = stackgap_init(p->p_emul);
    622 		bvtp = stackgap_alloc(&sg, sizeof (struct vt_mode));
    623 		if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode))))
    624 			return error;
    625 		SCARG(&bia, data) = bvtp;
    626 		break;
    627 	case LINUX_VT_RELDISP:
    628 		com = VT_RELDISP;
    629 		break;
    630 	case LINUX_VT_ACTIVATE:
    631 		com = VT_ACTIVATE;
    632 		break;
    633 	case LINUX_VT_WAITACTIVE:
    634 		com = VT_WAITACTIVE;
    635 		break;
    636 #endif
    637 #if (NWSDISPLAY > 0)
    638 	case LINUX_VT_GETSTATE:
    639 		com = VT_GETSTATE;
    640 		break;
    641 #ifdef XSERVER
    642 	case LINUX_KDGKBTYPE:
    643 		/* This is what Linux does. */
    644 		return (subyte(SCARG(uap, data), KB_101));
    645 	case LINUX_KDGKBENT:
    646 		/*
    647 		 * The Linux KDGKBENT ioctl is different from the
    648 		 * SYSV original. So we handle it in machdep code.
    649 		 * XXX We should use keyboard mapping information
    650 		 * from wsdisplay, but this would be expensive.
    651 		 */
    652 		if ((error = copyin(SCARG(uap, data), &kbe,
    653 				    sizeof(struct kbentry))))
    654 			return (error);
    655 		if (kbe.kb_table >= sizeof(linux_keytabs) / sizeof(u_short *)
    656 		    || kbe.kb_index >= NR_KEYS)
    657 			return (EINVAL);
    658 		kbe.kb_value = linux_keytabs[kbe.kb_table][kbe.kb_index];
    659 		return (copyout(&kbe, SCARG(uap, data),
    660 				sizeof(struct kbentry)));
    661 #endif
    662 #endif
    663 	default:
    664 		printf("linux_machdepioctl: invalid ioctl %08lx\n", com);
    665 		return EINVAL;
    666 	}
    667 	SCARG(&bia, com) = com;
    668 	return sys_ioctl(p, &bia, retval);
    669 }
    670 
    671 /*
    672  * Set I/O permissions for a process. Just set the maximum level
    673  * right away (ignoring the argument), otherwise we would have
    674  * to rely on I/O permission maps, which are not implemented.
    675  */
    676 int
    677 linux_sys_iopl(p, v, retval)
    678 	struct proc *p;
    679 	void *v;
    680 	register_t *retval;
    681 {
    682 #if 0
    683 	struct linux_sys_iopl_args /* {
    684 		syscallarg(int) level;
    685 	} */ *uap = v;
    686 #endif
    687 	struct trapframe *fp = p->p_md.md_regs;
    688 
    689 	if (suser(p->p_ucred, &p->p_acflag) != 0)
    690 		return EPERM;
    691 	fp->tf_eflags |= PSL_IOPL;
    692 	*retval = 0;
    693 	return 0;
    694 }
    695 
    696 /*
    697  * See above. If a root process tries to set access to an I/O port,
    698  * just let it have the whole range.
    699  */
    700 int
    701 linux_sys_ioperm(p, v, retval)
    702 	struct proc *p;
    703 	void *v;
    704 	register_t *retval;
    705 {
    706 	struct linux_sys_ioperm_args /* {
    707 		syscallarg(unsigned int) lo;
    708 		syscallarg(unsigned int) hi;
    709 		syscallarg(int) val;
    710 	} */ *uap = v;
    711 	struct trapframe *fp = p->p_md.md_regs;
    712 
    713 	if (suser(p->p_ucred, &p->p_acflag) != 0)
    714 		return EPERM;
    715 	if (SCARG(uap, val))
    716 		fp->tf_eflags |= PSL_IOPL;
    717 	*retval = 0;
    718 	return 0;
    719 }
    720