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