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