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