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