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