/* * Dump the machine specific header information at the start of a core dump. */ int cpu_coredump(struct lwp *l, void *iocookie, struct core *chdr) { int error; struct md_coredump cpustate; struct coreseg cseg; if (iocookie == NULL) { CORE_SETMAGIC(*chdr, COREMAGIC, MID_MACHINE, 0); chdr->c_hdrsize = ALIGN(sizeof(*chdr)); chdr->c_seghdrsize = ALIGN(sizeof(cseg)); chdr->c_cpusize = sizeof(cpustate); chdr->c_nseg++; return 0; } cpustate.md_tf = *l->l_md.md_tf; cpustate.md_tf.tf_regs[FRAME_SP] = alpha_pal_rdusp(); /* XXX */ if (l->l_md.md_flags & MDP_FPUSED) { if (l->l_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(l, 1); cpustate.md_fpstate = l->l_addr->u_pcb.pcb_fp; } else memset(&cpustate.md_fpstate, 0, sizeof(cpustate.md_fpstate)); CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_MACHINE, CORE_CPU); cseg.c_addr = 0; cseg.c_size = chdr->c_cpusize; error = coredump_write(iocookie, UIO_SYSSPACE, &cseg, chdr->c_seghdrsize); if (error) return error; return coredump_write(iocookie, UIO_SYSSPACE, &cpustate, sizeof(cpustate)); }
void setup_linux_sigframe(struct trapframe *tf, const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct linux_sigframe *sfp, sigframe; int onstack, error; int fsize, rndfsize; int sig = ksi->ksi_signo; extern char linux_sigcode[], linux_esigcode[]; /* Do we need to jump onto the signal stack? */ onstack = (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; /* Allocate space for the signal handler context. */ fsize = sizeof(struct linux_sigframe); rndfsize = ((fsize + 15) / 16) * 16; if (onstack) sfp = (struct linux_sigframe *) ((char *)l->l_sigstk.ss_sp + l->l_sigstk.ss_size); else sfp = (struct linux_sigframe *)(alpha_pal_rdusp()); sfp = (struct linux_sigframe *)((char *)sfp - rndfsize); #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && (p->p_pid == sigpid)) printf("linux_sendsig(%d): sig %d ssp %p usp %p\n", p->p_pid, sig, &onstack, sfp); #endif /* DEBUG */ /* * Build the signal context to be used by sigreturn. */ memset(&sigframe.sf_sc, 0, sizeof(struct linux_sigcontext)); sigframe.sf_sc.sc_onstack = onstack; native_to_linux_old_sigset(&sigframe.sf_sc.sc_mask, mask); sigframe.sf_sc.sc_pc = tf->tf_regs[FRAME_PC]; sigframe.sf_sc.sc_ps = ALPHA_PSL_USERMODE; frametoreg(tf, (struct reg *)sigframe.sf_sc.sc_regs); sigframe.sf_sc.sc_regs[R_SP] = alpha_pal_rdusp(); if (l == fpcurlwp) { struct pcb *pcb = lwp_getpcb(l); alpha_pal_wrfen(1); savefpstate(&pcb->pcb_fp); alpha_pal_wrfen(0); sigframe.sf_sc.sc_fpcr = pcb->pcb_fp.fpr_cr; fpcurlwp = NULL; } /* XXX ownedfp ? etc...? */ sigframe.sf_sc.sc_traparg_a0 = tf->tf_regs[FRAME_A0]; sigframe.sf_sc.sc_traparg_a1 = tf->tf_regs[FRAME_A1]; sigframe.sf_sc.sc_traparg_a2 = tf->tf_regs[FRAME_A2]; sendsig_reset(l, sig); mutex_exit(p->p_lock); error = copyout((void *)&sigframe, (void *)sfp, fsize); mutex_enter(p->p_lock); if (error != 0) { #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): copyout failed on sig %d\n", p->p_pid, sig); #endif /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ sigexit(l, SIGILL); /* NOTREACHED */ } /* Pass pointers to sigcontext in the regs */ tf->tf_regs[FRAME_A1] = 0; tf->tf_regs[FRAME_A2] = (unsigned long)&sfp->sf_sc; /* Address of trampoline code. End up at this PC after mi_switch */ tf->tf_regs[FRAME_PC] = (u_int64_t)(p->p_psstrp - (linux_esigcode - linux_sigcode)); /* Adjust the stack */ alpha_pal_wrusp((unsigned long)sfp); /* Remember that we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; }
void sendsig_sigcontext(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct sigacts *ps = p->p_sigacts; int onstack, sig = ksi->ksi_signo; struct sigframe_sigcontext *fp, frame; struct trapframe *tf; sig_t catcher = SIGACTION(p, sig).sa_handler; tf = l->l_md.md_tf; fp = getframe(l, sig, &onstack), frame; fp--; #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig_sigcontext(%d): sig %d ssp %p usp %p\n", p->p_pid, sig, &onstack, fp); #endif /* Build stack frame for signal trampoline. */ frame.sf_sc.sc_pc = tf->tf_regs[FRAME_PC]; frame.sf_sc.sc_ps = tf->tf_regs[FRAME_PS]; /* Save register context. */ frametoreg(tf, (struct reg *)frame.sf_sc.sc_regs); frame.sf_sc.sc_regs[R_ZERO] = 0xACEDBADE; /* magic number */ frame.sf_sc.sc_regs[R_SP] = alpha_pal_rdusp(); /* save the floating-point state, if necessary, then copy it. */ if (l->l_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(l, 1); frame.sf_sc.sc_ownedfp = l->l_md.md_flags & MDP_FPUSED; memcpy((struct fpreg *)frame.sf_sc.sc_fpregs, &l->l_addr->u_pcb.pcb_fp, sizeof(struct fpreg)); frame.sf_sc.sc_fp_control = alpha_read_fp_c(l); memset(frame.sf_sc.sc_reserved, 0, sizeof frame.sf_sc.sc_reserved); memset(frame.sf_sc.sc_xxx, 0, sizeof frame.sf_sc.sc_xxx); /* XXX */ /* Save signal stack. */ frame.sf_sc.sc_onstack = p->p_sigctx.ps_sigstk.ss_flags & SS_ONSTACK; /* Save signal mask. */ frame.sf_sc.sc_mask = *mask; #ifdef COMPAT_13 /* * XXX We always have to save an old style signal mask because * XXX we might be delivering a signal to a process which will * XXX escape from the signal in a non-standard way and invoke * XXX sigreturn() directly. */ { /* Note: it's a long in the stack frame. */ sigset13_t mask13; native_sigset_to_sigset13(mask, &mask13); frame.sf_sc.__sc_mask13 = mask13; } #endif #ifdef COMPAT_OSF1 /* * XXX Create an OSF/1-style sigcontext and associated goo. */ #endif if (copyout(&frame, (caddr_t)fp, sizeof(frame)) != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig_sigcontext(%d): copyout failed on sig %d\n", p->p_pid, sig); #endif sigexit(l, SIGILL); /* NOTREACHED */ } #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig_sigcontext(%d): sig %d usp %p code %x\n", p->p_pid, sig, fp, ksi->ksi_code); #endif /* * Set up the registers to directly invoke the signal handler. The * signal trampoline is then used to return from the signal. Note * the trampoline version numbers are coordinated with machine- * dependent code in libc. */ switch (ps->sa_sigdesc[sig].sd_vers) { case 0: /* legacy on-stack sigtramp */ buildcontext(l,(void *)catcher, (void *)p->p_sigctx.ps_sigcode, (void *)fp); break; case 1: buildcontext(l,(void *)catcher, (void *)ps->sa_sigdesc[sig].sd_tramp, (void *)fp); break; default: /* Don't know what trampoline version; kill it. */ sigexit(l, SIGILL); } /* sigcontext specific trap frame */ tf->tf_regs[FRAME_A0] = sig; /* tf->tf_regs[FRAME_A1] = ksi->ksi_code; */ tf->tf_regs[FRAME_A1] = KSI_TRAPCODE(ksi); tf->tf_regs[FRAME_A2] = (u_int64_t)&fp->sf_sc; /* Remember that we're now on the signal stack. */ if (onstack) p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): pc %lx, catcher %lx\n", p->p_pid, tf->tf_regs[FRAME_PC], tf->tf_regs[FRAME_A3]); if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d returns\n", p->p_pid, sig); #endif }
void osf1_syscall_fancy(struct proc *p, u_int64_t code, struct trapframe *framep) { const struct sysent *callp; int error; u_int64_t rval[2]; u_int64_t *args, copyargs[10]; /* XXX */ u_int hidden, nargs; KERNEL_PROC_LOCK(p); uvmexp.syscalls++; p->p_md.md_tf = framep; callp = p->p_emul->e_sysent; switch (code) { case OSF1_SYS_syscall: /* OSF/1 syscall() */ code = framep->tf_regs[FRAME_A0]; hidden = 1; break; default: hidden = 0; break; } code &= (OSF1_SYS_NSYSENT - 1); callp += code; nargs = callp->sy_narg + hidden; switch (nargs) { default: error = copyin((caddr_t)alpha_pal_rdusp(), ©args[6], (nargs - 6) * sizeof(u_int64_t)); if (error) goto bad; case 6: copyargs[5] = framep->tf_regs[FRAME_A5]; case 5: copyargs[4] = framep->tf_regs[FRAME_A4]; case 4: copyargs[3] = framep->tf_regs[FRAME_A3]; copyargs[2] = framep->tf_regs[FRAME_A2]; copyargs[1] = framep->tf_regs[FRAME_A1]; copyargs[0] = framep->tf_regs[FRAME_A0]; args = copyargs; break; case 3: case 2: case 1: case 0: args = &framep->tf_regs[FRAME_A0]; break; } args += hidden; #ifdef KTRACE if (KTRPOINT(p, KTR_SYSCALL)) ktrsyscall(p, code, callp->sy_argsize, args); #endif #ifdef SYSCALL_DEBUG scdebug_call(p, code, args); #endif rval[0] = 0; rval[1] = 0; error = (*callp->sy_call)(p, args, rval); switch (error) { case 0: framep->tf_regs[FRAME_V0] = rval[0]; framep->tf_regs[FRAME_A4] = rval[1]; framep->tf_regs[FRAME_A3] = 0; break; case ERESTART: framep->tf_regs[FRAME_PC] -= 4; break; case EJUSTRETURN: break; default: bad: error = native_to_osf1_errno[error]; framep->tf_regs[FRAME_V0] = error; framep->tf_regs[FRAME_A3] = 1; break; } #ifdef SYSCALL_DEBUG scdebug_ret(p, code, error, rval); #endif KERNEL_PROC_UNLOCK(p); userret(p); #ifdef KTRACE if (KTRPOINT(p, KTR_SYSRET)) { KERNEL_PROC_LOCK(p); ktrsysret(p, code, error, rval[0]); KERNEL_PROC_UNLOCK(p); } #endif }
/* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb and trap frame, making the child ready to run. * * Rig the child's kernel stack so that it will start out in * lwp_trampoline() and call child_return() with p2 as an * argument. This causes the newly-created child process to go * directly to user level with an apparent return value of 0 from * fork(), while the parent process returns normally. * * p1 is the process being forked; if p1 == &proc0, we are creating * a kernel thread, and the return path and argument are specified with * `func' and `arg'. * * If an alternate user-level stack is requested (with non-zero values * in both the stack and stacksize args), set up the user stack pointer * accordingly. */ void cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize, void (*func)(void *), void *arg) { struct user *up = l2->l_addr; l2->l_md.md_tf = l1->l_md.md_tf; l2->l_md.md_flags = l1->l_md.md_flags & (MDP_FPUSED | MDP_FP_C); l2->l_md.md_astpending = 0; /* * Cache the physical address of the pcb, so we can * swap to it easily. */ l2->l_md.md_pcbpaddr = (void *)vtophys((vaddr_t)&up->u_pcb); /* * Copy floating point state from the FP chip to the PCB * if this process has state stored there. */ if (l1->l_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(l1, 1); /* * Copy pcb and user stack pointer from proc p1 to p2. * If specificed, give the child a different stack. */ l2->l_addr->u_pcb = l1->l_addr->u_pcb; if (stack != NULL) l2->l_addr->u_pcb.pcb_hw.apcb_usp = (u_long)stack + stacksize; else l2->l_addr->u_pcb.pcb_hw.apcb_usp = alpha_pal_rdusp(); simple_lock_init(&l2->l_addr->u_pcb.pcb_fpcpu_slock); /* * Arrange for a non-local goto when the new process * is started, to resume here, returning nonzero from setjmp. */ #ifdef DIAGNOSTIC /* * If l1 != curlwp && l1 == &lwp0, we are creating a kernel * thread. */ if (l1 != curlwp && l1 != &lwp0) panic("cpu_lwp_fork: curlwp"); #endif /* * create the child's kernel stack, from scratch. */ { struct trapframe *l2tf; /* * Pick a stack pointer, leaving room for a trapframe; * copy trapframe from parent so return to user mode * will be to right address, with correct registers. */ l2tf = l2->l_md.md_tf = (struct trapframe *) ((char *)l2->l_addr + USPACE - sizeof(struct trapframe)); memcpy(l2->l_md.md_tf, l1->l_md.md_tf, sizeof(struct trapframe)); /* * Set up return-value registers as fork() libc stub expects. */ l2tf->tf_regs[FRAME_V0] = l1->l_proc->p_pid; /* parent's pid */ l2tf->tf_regs[FRAME_A3] = 0; /* no error */ l2tf->tf_regs[FRAME_A4] = 1; /* is child */ cpu_setfunc(l2, func, arg); } }
/* * Process a system call. * * System calls are strange beasts. They are passed the syscall number * in v0, and the arguments in the registers (as normal). They return * an error flag in a3 (if a3 != 0 on return, the syscall had an error), * and the return value (if any) in v0. * * The assembly stub takes care of moving the call number into a register * we can get to, and moves all of the argument registers into their places * in the trap frame. On return, it restores the callee-saved registers, * a3, and v0 from the frame before returning to the user process. */ void syscall_plain(struct proc *p, u_int64_t code, struct trapframe *framep) { const struct sysent *callp; int error; u_int64_t rval[2]; u_int64_t *args, copyargs[10]; /* XXX */ u_int hidden, nargs; KERNEL_PROC_LOCK(p); uvmexp.syscalls++; p->p_md.md_tf = framep; callp = p->p_emul->e_sysent; switch (code) { case SYS_syscall: case SYS___syscall: /* * syscall() and __syscall() are handled the same on * the alpha, as everything is 64-bit aligned, anyway. */ code = framep->tf_regs[FRAME_A0]; hidden = 1; break; default: hidden = 0; break; } code &= (SYS_NSYSENT - 1); callp += code; nargs = callp->sy_narg + hidden; switch (nargs) { default: error = copyin((caddr_t)alpha_pal_rdusp(), ©args[6], (nargs - 6) * sizeof(u_int64_t)); if (error) goto bad; case 6: copyargs[5] = framep->tf_regs[FRAME_A5]; case 5: copyargs[4] = framep->tf_regs[FRAME_A4]; case 4: copyargs[3] = framep->tf_regs[FRAME_A3]; copyargs[2] = framep->tf_regs[FRAME_A2]; copyargs[1] = framep->tf_regs[FRAME_A1]; copyargs[0] = framep->tf_regs[FRAME_A0]; args = copyargs; break; case 3: case 2: case 1: case 0: args = &framep->tf_regs[FRAME_A0]; break; } args += hidden; #ifdef SYSCALL_DEBUG scdebug_call(p, code, args); #endif rval[0] = 0; rval[1] = 0; error = (*callp->sy_call)(p, args, rval); switch (error) { case 0: framep->tf_regs[FRAME_V0] = rval[0]; framep->tf_regs[FRAME_A4] = rval[1]; framep->tf_regs[FRAME_A3] = 0; break; case ERESTART: framep->tf_regs[FRAME_PC] -= 4; break; case EJUSTRETURN: break; default: bad: framep->tf_regs[FRAME_V0] = error; framep->tf_regs[FRAME_A3] = 1; break; } #ifdef SYSCALL_DEBUG scdebug_ret(p, code, error, rval); #endif KERNEL_PROC_UNLOCK(p); userret(p); }
/* * Finish a fork operation, with thread l2 nearly set up. * Copy and update the pcb and trap frame, making the child ready to run. * * Rig the child's kernel stack so that it will start out in * lwp_trampoline() and call child_return() with l2 as an * argument. This causes the newly-created child thread to go * directly to user level with an apparent return value of 0 from * fork(), while the parent process returns normally. * * l1 is the thread being forked; if l1 == &lwp0, we are creating * a kernel thread, and the return path and argument are specified with * `func' and `arg'. * * If an alternate user-level stack is requested (with non-zero values * in both the stack and stacksize args), set up the user stack pointer * accordingly. */ void cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize, void (*func)(void *), void *arg) { struct pcb *pcb1, *pcb2; extern void lwp_trampoline(void); pcb1 = lwp_getpcb(l1); pcb2 = lwp_getpcb(l2); l2->l_md.md_tf = l1->l_md.md_tf; l2->l_md.md_flags = l1->l_md.md_flags & MDLWP_FP_C; l2->l_md.md_astpending = 0; /* * Cache the physical address of the pcb, so we can * swap to it easily. */ l2->l_md.md_pcbpaddr = (void *)vtophys((vaddr_t)pcb2); /* * Copy pcb and user stack pointer from proc p1 to p2. * If specificed, give the child a different stack. * Floating point state from the FP chip has already been saved. */ *pcb2 = *pcb1; if (stack != NULL) pcb2->pcb_hw.apcb_usp = (u_long)stack + stacksize; else pcb2->pcb_hw.apcb_usp = alpha_pal_rdusp(); /* * Arrange for a non-local goto when the new process * is started, to resume here, returning nonzero from setjmp. */ #ifdef DIAGNOSTIC /* * If l1 != curlwp && l1 == &lwp0, we are creating a kernel * thread. */ if (l1 != curlwp && l1 != &lwp0) panic("cpu_lwp_fork: curlwp"); #endif /* * create the child's kernel stack, from scratch. */ { struct trapframe *l2tf; /* * Pick a stack pointer, leaving room for a trapframe; * copy trapframe from parent so return to user mode * will be to right address, with correct registers. */ l2tf = l2->l_md.md_tf = (struct trapframe *) (uvm_lwp_getuarea(l2) + USPACE - sizeof(struct trapframe)); memcpy(l2->l_md.md_tf, l1->l_md.md_tf, sizeof(struct trapframe)); /* * Set up return-value registers as fork() libc stub expects. */ l2tf->tf_regs[FRAME_V0] = l1->l_proc->p_pid; /* parent's pid */ l2tf->tf_regs[FRAME_A3] = 0; /* no error */ l2tf->tf_regs[FRAME_A4] = 1; /* is child */ pcb2->pcb_hw.apcb_ksp = (uint64_t)l2->l_md.md_tf; pcb2->pcb_context[0] = (uint64_t)func; /* s0: pc */ pcb2->pcb_context[1] = (uint64_t)exception_return; /* s1: ra */ pcb2->pcb_context[2] = (uint64_t)arg; /* s2: arg */ pcb2->pcb_context[3] = (uint64_t)l2; /* s3: lwp */ pcb2->pcb_context[7] = (uint64_t)lwp_trampoline; /* ra: assembly magic */ } }