1 /* $NetBSD: linux_machdep.c,v 1.57 2000/12/29 20:07:25 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 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 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 u_short *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_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 * Unknown to us. If it's on a device, just pass it through 776 * using PTIOCLINUX, the device itself might be able to 777 * make some sense of it. 778 * XXX hack: if the function returns EJUSTRETURN, 779 * it has stuffed a sysctl return value in pt.data. 780 */ 781 FILE_USE(fp); 782 ioctlf = fp->f_ops->fo_ioctl; 783 pt.com = SCARG(uap, com); 784 pt.data = SCARG(uap, data); 785 error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p); 786 FILE_UNUSE(fp, p); 787 if (error == EJUSTRETURN) { 788 retval[0] = (register_t)pt.data; 789 error = 0; 790 } 791 792 if (error == EINVAL) 793 printf("linux_machdepioctl: invalid ioctl %08lx\n", 794 com); 795 return error; 796 } 797 SCARG(&bia, com) = com; 798 return sys_ioctl(p, &bia, retval); 799 } 800 801 /* 802 * Set I/O permissions for a process. Just set the maximum level 803 * right away (ignoring the argument), otherwise we would have 804 * to rely on I/O permission maps, which are not implemented. 805 */ 806 int 807 linux_sys_iopl(p, v, retval) 808 struct proc *p; 809 void *v; 810 register_t *retval; 811 { 812 #if 0 813 struct linux_sys_iopl_args /* { 814 syscallarg(int) level; 815 } */ *uap = v; 816 #endif 817 struct trapframe *fp = p->p_md.md_regs; 818 819 if (suser(p->p_ucred, &p->p_acflag) != 0) 820 return EPERM; 821 fp->tf_eflags |= PSL_IOPL; 822 *retval = 0; 823 return 0; 824 } 825 826 /* 827 * See above. If a root process tries to set access to an I/O port, 828 * just let it have the whole range. 829 */ 830 int 831 linux_sys_ioperm(p, v, retval) 832 struct proc *p; 833 void *v; 834 register_t *retval; 835 { 836 struct linux_sys_ioperm_args /* { 837 syscallarg(unsigned int) lo; 838 syscallarg(unsigned int) hi; 839 syscallarg(int) val; 840 } */ *uap = v; 841 struct trapframe *fp = p->p_md.md_regs; 842 843 if (suser(p->p_ucred, &p->p_acflag) != 0) 844 return EPERM; 845 if (SCARG(uap, val)) 846 fp->tf_eflags |= PSL_IOPL; 847 *retval = 0; 848 return 0; 849 } 850