1 /* $NetBSD: linux_machdep.c,v 1.14 2002/05/20 06:26:47 jdolecek 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.14 2002/05/20 06:26:47 jdolecek 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/map.h> 47 #include <sys/proc.h> 48 #include <sys/user.h> 49 #include <sys/buf.h> 50 #include <sys/reboot.h> 51 #include <sys/conf.h> 52 #include <sys/exec.h> 53 #include <sys/file.h> 54 #include <sys/callout.h> 55 #include <sys/malloc.h> 56 #include <sys/mbuf.h> 57 #include <sys/msgbuf.h> 58 #include <sys/mount.h> 59 #include <sys/vnode.h> 60 #include <sys/device.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 <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/psl.h> 81 #include <machine/reg.h> 82 #include <machine/regnum.h> 83 #include <machine/vmparam.h> 84 #include <machine/locore.h> 85 86 #include <mips/cache.h> 87 88 /* 89 * To see whether wscons is configured (for virtual console ioctl calls). 90 */ 91 #if defined(_KERNEL_OPT) 92 #include "wsdisplay.h" 93 #endif 94 #if (NWSDISPLAY > 0) 95 #include <dev/wscons/wsconsio.h> 96 #include <dev/wscons/wsdisplay_usl_io.h> 97 #endif 98 99 /* 100 * Set set up registers on exec. 101 * XXX not used at the moment since in sys/kern/exec_conf, LINUX_COMPAT 102 * entry uses NetBSD's native setregs instead of linux_setregs 103 */ 104 void 105 linux_setregs(p, pack, stack) 106 struct proc *p; 107 struct exec_package *pack; 108 u_long stack; 109 { 110 setregs(p, pack, stack); 111 return; 112 } 113 114 /* 115 * Send an interrupt to process. 116 * 117 * Adapted from sys/arch/mips/mips/mips_machdep.c 118 * 119 * XXX Does not work well yet with RT signals 120 * 121 */ 122 123 void 124 linux_sendsig(catcher, sig, mask, code) /* XXX Check me */ 125 sig_t catcher; 126 int sig; 127 sigset_t *mask; 128 u_long code; 129 { 130 struct proc *p = curproc; 131 struct linux_sigframe *fp; 132 struct frame *f; 133 int i,onstack; 134 struct linux_sigframe sf; 135 136 #ifdef DEBUG_LINUX 137 printf("linux_sendsig()\n"); 138 #endif /* DEBUG_LINUX */ 139 f = (struct frame *)p->p_md.md_regs; 140 141 /* 142 * Do we need to jump onto the signal stack? 143 */ 144 onstack = 145 (p->p_sigctx.ps_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && 146 (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; 147 148 /* 149 * Signal stack is broken (see at the end of linux_sigreturn), so we do 150 * not use it yet. XXX fix this. 151 */ 152 onstack=0; 153 154 /* 155 * Allocate space for the signal handler context. 156 */ 157 if (onstack) 158 fp = (struct linux_sigframe *) 159 ((caddr_t)p->p_sigctx.ps_sigstk.ss_sp 160 + p->p_sigctx.ps_sigstk.ss_size); 161 else 162 /* cast for _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN case */ 163 fp = (struct linux_sigframe *)(u_int32_t)f->f_regs[SP]; 164 165 /* 166 * Build stack frame for signal trampoline. 167 */ 168 memset(&sf, 0, sizeof sf); 169 170 /* 171 * This is the signal trampoline used by Linux, we don't use it, 172 * but we set it up in case an application expects it to be there 173 */ 174 sf.lsf_code[0] = 0x24020000; /* li v0, __NR_sigreturn */ 175 sf.lsf_code[1] = 0x0000000c; /* syscall */ 176 177 native_to_linux_sigset(&sf.lsf_mask, mask); 178 for (i=0; i<32; i++) { 179 sf.lsf_sc.lsc_regs[i] = f->f_regs[i]; 180 } 181 sf.lsf_sc.lsc_mdhi = f->f_regs[MULHI]; 182 sf.lsf_sc.lsc_mdlo = f->f_regs[MULLO]; 183 sf.lsf_sc.lsc_pc = f->f_regs[PC]; 184 sf.lsf_sc.lsc_status = f->f_regs[SR]; 185 sf.lsf_sc.lsc_cause = f->f_regs[CAUSE]; 186 sf.lsf_sc.lsc_badvaddr = f->f_regs[BADVADDR]; 187 188 /* 189 * Save signal stack. XXX broken 190 */ 191 /* kregs.sc_onstack = p->p_sigctx.ps_sigstk.ss_flags & SS_ONSTACK; */ 192 193 /* 194 * Install the sigframe onto the stack 195 */ 196 fp -= sizeof(struct linux_sigframe); 197 if (copyout(&sf, fp, sizeof(sf)) != 0) { 198 /* 199 * Process has trashed its stack; give it an illegal 200 * instruction to halt it in its tracks. 201 */ 202 #ifdef DEBUG_LINUX 203 printf("linux_sendsig: stack trashed\n"); 204 #endif /* DEBUG_LINUX */ 205 sigexit(p, SIGILL); 206 /* NOTREACHED */ 207 } 208 209 /* Set up the registers to return to sigcode. */ 210 f->f_regs[A0] = native_to_linux_signo[sig]; 211 f->f_regs[A1] = 0; 212 f->f_regs[A2] = (unsigned long)&fp->lsf_sc; 213 214 #ifdef DEBUG_LINUX 215 printf("sigcontext is at %p\n", &fp->lsf_sc); 216 #endif /* DEBUG_LINUX */ 217 218 f->f_regs[SP] = (unsigned long)fp; 219 /* Signal trampoline code is at base of user stack. */ 220 f->f_regs[RA] = (unsigned long)p->p_sigctx.ps_sigcode; 221 f->f_regs[T9] = (unsigned long)catcher; 222 f->f_regs[PC] = (unsigned long)catcher; 223 224 /* Remember that we're now on the signal stack. */ 225 if (onstack) 226 p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK; 227 228 return; 229 } 230 231 /* 232 * System call to cleanup state after a signal 233 * has been taken. Reset signal mask and 234 * stack state from context left by sendsig (above). 235 */ 236 int 237 linux_sys_sigreturn(p, v, retval) 238 struct proc *p; 239 void *v; 240 register_t *retval; 241 { 242 struct linux_sys_sigreturn_args /* { 243 syscallarg(struct linux_sigframe *) sf; 244 } */ *uap = v; 245 struct linux_sigframe *sf, ksf; 246 struct frame *f; 247 sigset_t mask; 248 int i, error; 249 250 #ifdef DEBUG_LINUX 251 printf("linux_sys_sigreturn()\n"); 252 #endif /* DEBUG_LINUX */ 253 254 /* 255 * The trampoline code hands us the context. 256 * It is unsafe to keep track of it ourselves, in the event that a 257 * program jumps out of a signal handler. 258 */ 259 sf = SCARG(uap, sf); 260 261 if ((error = copyin(sf, &ksf, sizeof(ksf))) != 0) 262 return (error); 263 264 /* Restore the register context. */ 265 f = (struct frame *)p->p_md.md_regs; 266 for (i=0; i<32; i++) 267 f->f_regs[i] = ksf.lsf_sc.lsc_regs[i]; 268 f->f_regs[MULLO] = ksf.lsf_sc.lsc_mdlo; 269 f->f_regs[MULHI] = ksf.lsf_sc.lsc_mdhi; 270 f->f_regs[PC] = ksf.lsf_sc.lsc_pc; 271 f->f_regs[BADVADDR] = ksf.lsf_sc.lsc_badvaddr; 272 f->f_regs[CAUSE] = ksf.lsf_sc.lsc_cause; 273 274 /* Restore signal stack. */ 275 p->p_sigctx.ps_sigstk.ss_flags &= ~SS_ONSTACK; 276 277 /* Restore signal mask. */ 278 linux_to_native_sigset(&mask, (linux_sigset_t *)&ksf.lsf_mask); 279 (void)sigprocmask1(p, SIG_SETMASK, &mask, 0); 280 281 return (EJUSTRETURN); 282 } 283 284 285 int 286 linux_sys_rt_sigreturn(p, v, retval) 287 struct proc *p; 288 void *v; 289 register_t *retval; 290 { 291 return 0; 292 } 293 294 295 #if 0 296 int 297 linux_sys_modify_ldt(p, v, retval) 298 struct proc *p; 299 void *v; 300 register_t *retval; 301 { 302 /* 303 * This syscall is not implemented in Linux/Mips: we should not 304 * be here 305 */ 306 #ifdef DEBUG_LINUX 307 printf("linux_sys_modify_ldt: should not be here.\n"); 308 #endif /* DEBUG_LINUX */ 309 return 0; 310 } 311 #endif 312 313 /* 314 * major device numbers remapping 315 */ 316 dev_t 317 linux_fakedev(dev, raw) 318 dev_t dev; 319 int raw; 320 { 321 /* XXX write me */ 322 return dev; 323 } 324 325 /* 326 * We come here in a last attempt to satisfy a Linux ioctl() call 327 */ 328 int 329 linux_machdepioctl(p, v, retval) 330 struct proc *p; 331 void *v; 332 register_t *retval; 333 { 334 return 0; 335 } 336 337 /* 338 * See above. If a root process tries to set access to an I/O port, 339 * just let it have the whole range. 340 */ 341 int 342 linux_sys_ioperm(p, v, retval) 343 struct proc *p; 344 void *v; 345 register_t *retval; 346 { 347 /* 348 * This syscall is not implemented in Linux/Mips: we should not be here 349 */ 350 #ifdef DEBUG_LINUX 351 printf("linux_sys_ioperm: should not be here.\n"); 352 #endif /* DEBUG_LINUX */ 353 return 0; 354 } 355 356 /* 357 * wrapper linux_sys_new_uname() -> linux_sys_uname() 358 */ 359 int 360 linux_sys_new_uname(p, v, retval) 361 struct proc *p; 362 void *v; 363 register_t *retval; 364 { 365 /* 366 * Use this if you want to try Linux emulation with a glibc-2.2 367 * or higher. Note that signals will not work 368 */ 369 #if 0 370 struct linux_sys_uname_args /* { 371 syscallarg(struct linux_utsname *) up; 372 } */ *uap = v; 373 struct linux_utsname luts; 374 375 strncpy(luts.l_sysname, linux_sysname, sizeof(luts.l_sysname)); 376 strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename)); 377 strncpy(luts.l_release, "2.4.0", sizeof(luts.l_release)); 378 strncpy(luts.l_version, linux_version, sizeof(luts.l_version)); 379 strncpy(luts.l_machine, machine, sizeof(luts.l_machine)); 380 strncpy(luts.l_domainname, domainname, sizeof(luts.l_domainname)); 381 382 return copyout(&luts, SCARG(uap, up), sizeof(luts)); 383 #else 384 return linux_sys_uname(p, v, retval); 385 #endif 386 } 387 388 /* 389 * In Linux, cacheflush is icurrently implemented 390 * as a whole cache flush (arguments are ignored) 391 * we emulate this broken beahior. 392 */ 393 int 394 linux_sys_cacheflush(p, v, retval) 395 struct proc *p; 396 void *v; 397 register_t *retval; 398 { 399 mips_icache_sync_all(); 400 mips_dcache_wbinv_all(); 401 return 0; 402 } 403 404 /* 405 * This system call is depecated in Linux, but 406 * some binaries and some libraries use it. 407 */ 408 int 409 linux_sys_sysmips(p, v, retval) 410 struct proc *p; 411 void *v; 412 register_t *retval; 413 { 414 struct linux_sys_sysmips_args { 415 syscallarg(int) cmd; 416 syscallarg(int) arg1; 417 syscallarg(int) arg2; 418 syscallarg(int) arg3; 419 } *uap = v; 420 int error; 421 422 switch (SCARG(uap, cmd)) { 423 case LINUX_SETNAME: { 424 char nodename [LINUX___NEW_UTS_LEN + 1]; 425 int name; 426 size_t len; 427 428 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 429 return error; 430 if ((error = copyinstr((char *)SCARG(uap, arg1), nodename, 431 LINUX___NEW_UTS_LEN, &len)) != 0) 432 return error; 433 434 name = KERN_HOSTNAME; 435 return (kern_sysctl(&name, 1, 0, 0, nodename, len, p)); 436 437 break; 438 } 439 case LINUX_MIPS_ATOMIC_SET: { 440 void *addr; 441 int s; 442 443 addr = (void *)SCARG(uap, arg1); 444 445 if ((uvm_useracc((caddr_t)addr, sizeof(int), 446 B_READ | B_WRITE)) != 1) 447 return EFAULT; 448 449 s = splhigh(); 450 /* 451 * No error testing here. This is bad, but Linux does 452 * it like this. The source aknowledge "This is broken" 453 * in a comment... 454 */ 455 *retval = (register_t)fubyte(addr); 456 error = subyte(addr, SCARG(uap, arg2)); 457 splx(s); 458 459 return 0; 460 break; 461 } 462 case LINUX_MIPS_FIXADE: /* XXX not implemented */ 463 break; 464 case LINUX_FLUSH_CACHE: 465 mips_icache_sync_all(); 466 mips_dcache_wbinv_all(); 467 break; 468 case LINUX_MIPS_RDNVRAM: 469 return EIO; 470 break; 471 default: 472 return EINVAL; 473 break; 474 } 475 #ifdef DEBUG_LINUX 476 printf("linux_sys_sysmips(): unimplemented command %d\n", 477 SCARG(uap,cmd)); 478 #endif /* DEBUG_LINUX */ 479 return 0; 480 } 481