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