1 /* $NetBSD: linux_machdep.c,v 1.65 2001/06/17 21:01:38 sommerfeld 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_OPT) 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_OPT) 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_OPT) 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 frame.sf_sc.sc_gs = tf->tf_gs; 177 frame.sf_sc.sc_fs = tf->tf_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 ((fp = fd_getfile(fdp, fd)) == NULL) 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