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