1 /* $NetBSD: linux_machdep.c,v 1.26 2006/05/15 13:11:29 yamt Exp $ */ 2 3 /*- 4 * Copyright (c) 1995, 2000, 2001 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 and Emmanuel Dreyfus. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.26 2006/05/15 13:11:29 yamt Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/signalvar.h> 45 #include <sys/kernel.h> 46 #include <sys/proc.h> 47 #include <sys/user.h> 48 #include <sys/buf.h> 49 #include <sys/reboot.h> 50 #include <sys/conf.h> 51 #include <sys/exec.h> 52 #include <sys/file.h> 53 #include <sys/callout.h> 54 #include <sys/malloc.h> 55 #include <sys/mbuf.h> 56 #include <sys/msgbuf.h> 57 #include <sys/mount.h> 58 #include <sys/vnode.h> 59 #include <sys/device.h> 60 #include <sys/sa.h> 61 #include <sys/syscallargs.h> 62 #include <sys/filedesc.h> 63 #include <sys/exec_elf.h> 64 #include <sys/disklabel.h> 65 #include <sys/ioctl.h> 66 #include <sys/sysctl.h> 67 #include <sys/kauth.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/psl.h> 82 #include <machine/reg.h> 83 #include <machine/regnum.h> 84 #include <machine/vmparam.h> 85 #include <machine/locore.h> 86 87 #include <mips/cache.h> 88 89 /* 90 * To see whether wscons is configured (for virtual console ioctl calls). 91 */ 92 #if defined(_KERNEL_OPT) 93 #include "wsdisplay.h" 94 #endif 95 #if (NWSDISPLAY > 0) 96 #include <dev/wscons/wsconsio.h> 97 #include <dev/wscons/wsdisplay_usl_io.h> 98 #endif 99 100 /* 101 * Set set up registers on exec. 102 * XXX not used at the moment since in sys/kern/exec_conf, LINUX_COMPAT 103 * entry uses NetBSD's native setregs instead of linux_setregs 104 */ 105 void 106 linux_setregs(l, pack, stack) 107 struct lwp *l; 108 struct exec_package *pack; 109 u_long stack; 110 { 111 setregs(l, pack, stack); 112 return; 113 } 114 115 /* 116 * Send an interrupt to process. 117 * 118 * Adapted from sys/arch/mips/mips/mips_machdep.c 119 * 120 * XXX Does not work well yet with RT signals 121 * 122 */ 123 124 void 125 linux_sendsig(ksi, mask) 126 const ksiginfo_t *ksi; 127 const sigset_t *mask; 128 { 129 const int sig = ksi->ksi_signo; 130 struct lwp *l = curlwp; 131 struct proc *p = l->l_proc; 132 struct linux_sigframe *fp; 133 struct frame *f; 134 int i,onstack; 135 sig_t catcher = SIGACTION(p, sig).sa_handler; 136 struct linux_sigframe sf; 137 138 #ifdef DEBUG_LINUX 139 printf("linux_sendsig()\n"); 140 #endif /* DEBUG_LINUX */ 141 f = (struct frame *)l->l_md.md_regs; 142 143 /* 144 * Do we need to jump onto the signal stack? 145 */ 146 onstack = 147 (p->p_sigctx.ps_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && 148 (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; 149 150 /* 151 * Signal stack is broken (see at the end of linux_sigreturn), so we do 152 * not use it yet. XXX fix this. 153 */ 154 onstack=0; 155 156 /* 157 * Allocate space for the signal handler context. 158 */ 159 if (onstack) 160 fp = (struct linux_sigframe *) 161 ((caddr_t)p->p_sigctx.ps_sigstk.ss_sp 162 + p->p_sigctx.ps_sigstk.ss_size); 163 else 164 /* cast for _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN case */ 165 fp = (struct linux_sigframe *)(u_int32_t)f->f_regs[_R_SP]; 166 167 /* 168 * Build stack frame for signal trampoline. 169 */ 170 memset(&sf, 0, sizeof sf); 171 172 /* 173 * This is the signal trampoline used by Linux, we don't use it, 174 * but we set it up in case an application expects it to be there 175 */ 176 sf.lsf_code[0] = 0x24020000; /* li v0, __NR_sigreturn */ 177 sf.lsf_code[1] = 0x0000000c; /* syscall */ 178 179 native_to_linux_sigset(&sf.lsf_mask, mask); 180 for (i=0; i<32; i++) { 181 sf.lsf_sc.lsc_regs[i] = f->f_regs[i]; 182 } 183 sf.lsf_sc.lsc_mdhi = f->f_regs[_R_MULHI]; 184 sf.lsf_sc.lsc_mdlo = f->f_regs[_R_MULLO]; 185 sf.lsf_sc.lsc_pc = f->f_regs[_R_PC]; 186 sf.lsf_sc.lsc_status = f->f_regs[_R_SR]; 187 sf.lsf_sc.lsc_cause = f->f_regs[_R_CAUSE]; 188 sf.lsf_sc.lsc_badvaddr = f->f_regs[_R_BADVADDR]; 189 190 /* 191 * Save signal stack. XXX broken 192 */ 193 /* kregs.sc_onstack = p->p_sigctx.ps_sigstk.ss_flags & SS_ONSTACK; */ 194 195 /* 196 * Install the sigframe onto the stack 197 */ 198 fp -= sizeof(struct linux_sigframe); 199 if (copyout(&sf, fp, sizeof(sf)) != 0) { 200 /* 201 * Process has trashed its stack; give it an illegal 202 * instruction to halt it in its tracks. 203 */ 204 #ifdef DEBUG_LINUX 205 printf("linux_sendsig: stack trashed\n"); 206 #endif /* DEBUG_LINUX */ 207 sigexit(l, SIGILL); 208 /* NOTREACHED */ 209 } 210 211 /* Set up the registers to return to sigcode. */ 212 f->f_regs[_R_A0] = native_to_linux_signo[sig]; 213 f->f_regs[_R_A1] = 0; 214 f->f_regs[_R_A2] = (unsigned long)&fp->lsf_sc; 215 216 #ifdef DEBUG_LINUX 217 printf("sigcontext is at %p\n", &fp->lsf_sc); 218 #endif /* DEBUG_LINUX */ 219 220 f->f_regs[_R_SP] = (unsigned long)fp; 221 /* Signal trampoline code is at base of user stack. */ 222 f->f_regs[_R_RA] = (unsigned long)p->p_sigctx.ps_sigcode; 223 f->f_regs[_R_T9] = (unsigned long)catcher; 224 f->f_regs[_R_PC] = (unsigned long)catcher; 225 226 /* Remember that we're now on the signal stack. */ 227 if (onstack) 228 p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK; 229 230 return; 231 } 232 233 /* 234 * System call to cleanup state after a signal 235 * has been taken. Reset signal mask and 236 * stack state from context left by sendsig (above). 237 */ 238 int 239 linux_sys_sigreturn(l, v, retval) 240 struct lwp *l; 241 void *v; 242 register_t *retval; 243 { 244 struct linux_sys_sigreturn_args /* { 245 syscallarg(struct linux_sigframe *) sf; 246 } */ *uap = v; 247 struct proc *p = l->l_proc; 248 struct linux_sigframe *sf, ksf; 249 struct frame *f; 250 sigset_t mask; 251 int i, error; 252 253 #ifdef DEBUG_LINUX 254 printf("linux_sys_sigreturn()\n"); 255 #endif /* DEBUG_LINUX */ 256 257 /* 258 * The trampoline code hands us the context. 259 * It is unsafe to keep track of it ourselves, in the event that a 260 * program jumps out of a signal handler. 261 */ 262 sf = SCARG(uap, sf); 263 264 if ((error = copyin(sf, &ksf, sizeof(ksf))) != 0) 265 return (error); 266 267 /* Restore the register context. */ 268 f = (struct frame *)l->l_md.md_regs; 269 for (i=0; i<32; i++) 270 f->f_regs[i] = ksf.lsf_sc.lsc_regs[i]; 271 f->f_regs[_R_MULLO] = ksf.lsf_sc.lsc_mdlo; 272 f->f_regs[_R_MULHI] = ksf.lsf_sc.lsc_mdhi; 273 f->f_regs[_R_PC] = ksf.lsf_sc.lsc_pc; 274 f->f_regs[_R_BADVADDR] = ksf.lsf_sc.lsc_badvaddr; 275 f->f_regs[_R_CAUSE] = ksf.lsf_sc.lsc_cause; 276 277 /* Restore signal stack. */ 278 p->p_sigctx.ps_sigstk.ss_flags &= ~SS_ONSTACK; 279 280 /* Restore signal mask. */ 281 linux_to_native_sigset(&mask, (linux_sigset_t *)&ksf.lsf_mask); 282 (void)sigprocmask1(p, SIG_SETMASK, &mask, 0); 283 284 return (EJUSTRETURN); 285 } 286 287 288 int 289 linux_sys_rt_sigreturn(l, v, retval) 290 struct lwp *l; 291 void *v; 292 register_t *retval; 293 { 294 return (ENOSYS); 295 } 296 297 298 #if 0 299 int 300 linux_sys_modify_ldt(l, v, retval) 301 struct lwp *l; 302 void *v; 303 register_t *retval; 304 { 305 /* 306 * This syscall is not implemented in Linux/Mips: we should not 307 * be here 308 */ 309 #ifdef DEBUG_LINUX 310 printf("linux_sys_modify_ldt: should not be here.\n"); 311 #endif /* DEBUG_LINUX */ 312 return 0; 313 } 314 #endif 315 316 /* 317 * major device numbers remapping 318 */ 319 dev_t 320 linux_fakedev(dev, raw) 321 dev_t dev; 322 int raw; 323 { 324 /* XXX write me */ 325 return dev; 326 } 327 328 /* 329 * We come here in a last attempt to satisfy a Linux ioctl() call 330 */ 331 int 332 linux_machdepioctl(p, v, retval) 333 struct proc *p; 334 void *v; 335 register_t *retval; 336 { 337 return 0; 338 } 339 340 /* 341 * See above. If a root process tries to set access to an I/O port, 342 * just let it have the whole range. 343 */ 344 int 345 linux_sys_ioperm(l, v, retval) 346 struct lwp *l; 347 void *v; 348 register_t *retval; 349 { 350 /* 351 * This syscall is not implemented in Linux/Mips: we should not be here 352 */ 353 #ifdef DEBUG_LINUX 354 printf("linux_sys_ioperm: should not be here.\n"); 355 #endif /* DEBUG_LINUX */ 356 return 0; 357 } 358 359 /* 360 * wrapper linux_sys_new_uname() -> linux_sys_uname() 361 */ 362 int 363 linux_sys_new_uname(l, v, retval) 364 struct lwp *l; 365 void *v; 366 register_t *retval; 367 { 368 /* 369 * Use this if you want to try Linux emulation with a glibc-2.2 370 * or higher. Note that signals will not work 371 */ 372 #if 0 373 struct linux_sys_uname_args /* { 374 syscallarg(struct linux_utsname *) up; 375 } */ *uap = v; 376 struct linux_utsname luts; 377 378 strncpy(luts.l_sysname, linux_sysname, sizeof(luts.l_sysname)); 379 strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename)); 380 strncpy(luts.l_release, "2.4.0", sizeof(luts.l_release)); 381 strncpy(luts.l_version, linux_version, sizeof(luts.l_version)); 382 strncpy(luts.l_machine, machine, sizeof(luts.l_machine)); 383 strncpy(luts.l_domainname, domainname, sizeof(luts.l_domainname)); 384 385 return copyout(&luts, SCARG(uap, up), sizeof(luts)); 386 #else 387 return linux_sys_uname(l, v, retval); 388 #endif 389 } 390 391 /* 392 * In Linux, cacheflush is currently implemented 393 * as a whole cache flush (arguments are ignored) 394 * we emulate this broken beahior. 395 */ 396 int 397 linux_sys_cacheflush(l, v, retval) 398 struct lwp *l; 399 void *v; 400 register_t *retval; 401 { 402 mips_icache_sync_all(); 403 mips_dcache_wbinv_all(); 404 return 0; 405 } 406 407 /* 408 * This system call is depecated in Linux, but 409 * some binaries and some libraries use it. 410 */ 411 int 412 linux_sys_sysmips(l, v, retval) 413 struct lwp *l; 414 void *v; 415 register_t *retval; 416 { 417 struct linux_sys_sysmips_args { 418 syscallarg(int) cmd; 419 syscallarg(int) arg1; 420 syscallarg(int) arg2; 421 syscallarg(int) arg3; 422 } *uap = v; 423 struct proc *p = l->l_proc; 424 int error; 425 426 switch (SCARG(uap, cmd)) { 427 case LINUX_SETNAME: { 428 char nodename [LINUX___NEW_UTS_LEN + 1]; 429 int name[2]; 430 size_t len; 431 432 if ((error = kauth_authorize_generic(p->p_cred, KAUTH_GENERIC_ISSUSER, &p->p_acflag)) != 0) 433 return error; 434 if ((error = copyinstr((char *)SCARG(uap, arg1), nodename, 435 LINUX___NEW_UTS_LEN, &len)) != 0) 436 return error; 437 438 name[0] = CTL_KERN; 439 name[1] = KERN_HOSTNAME; 440 return (old_sysctl(&name[0], 2, 0, 0, nodename, len, NULL)); 441 442 break; 443 } 444 case LINUX_MIPS_ATOMIC_SET: { 445 void *addr; 446 int s; 447 u_int8_t value = 0; 448 449 addr = (void *)SCARG(uap, arg1); 450 451 s = splhigh(); 452 /* 453 * No error testing here. This is bad, but Linux does 454 * it like this. The source aknowledge "This is broken" 455 * in a comment... 456 */ 457 (void) copyin(addr, &value, 1); 458 *retval = value; 459 value = (u_int8_t) SCARG(uap, arg2); 460 error = copyout(&value, addr, 1); 461 splx(s); 462 463 return 0; 464 break; 465 } 466 case LINUX_MIPS_FIXADE: /* XXX not implemented */ 467 break; 468 case LINUX_FLUSH_CACHE: 469 mips_icache_sync_all(); 470 mips_dcache_wbinv_all(); 471 break; 472 case LINUX_MIPS_RDNVRAM: 473 return EIO; 474 break; 475 default: 476 return EINVAL; 477 break; 478 } 479 #ifdef DEBUG_LINUX 480 printf("linux_sys_sysmips(): unimplemented command %d\n", 481 SCARG(uap,cmd)); 482 #endif /* DEBUG_LINUX */ 483 return 0; 484 } 485 486 int 487 linux_usertrap(struct lwp *l, vaddr_t trapaddr, void *arg) 488 { 489 return 0; 490 } 491