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