void cpu_lwp_free(struct lwp *l, int proc) { if (l->l_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(l, 0); }
void cpu_swapout(struct proc *p) { /* * Make sure we save the FP state before the user area vanishes. */ fpusave_proc(p, 1); }
/* * Finish a fork operation, with process p2 nearly set up. * Copy and update the kernel stack and pcb, making the child * ready to run, and marking it so that it can return differently * than the parent. Returns 1 in the child process, 0 in the parent. */ void cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize, void (*func)(void *), void *arg) { struct pcb *pcb = &p2->p_addr->u_pcb; struct trapframe *tf; struct switchframe *sf; /* * If fpuproc != p1, then the fpu h/w state is irrelevant and the * state had better already be in the pcb. This is true for forks * but not for dumps. * * If fpuproc == p1, then we have to save the fpu h/w state to * p1's pcb so that we can copy it. */ if (p1->p_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(p1, 1); p2->p_md.md_flags = p1->p_md.md_flags; #ifdef DIAGNOSTIC if (p1 != curproc && p1 != &proc0) panic("cpu_fork: curproc"); #endif *pcb = p1->p_addr->u_pcb; /* * Activate the address space. */ pmap_activate(p2); /* Record where this process's kernel stack is */ pcb->pcb_kstack = (u_int64_t)p2->p_addr + USPACE - 16; /* * Copy the trapframe. */ p2->p_md.md_regs = tf = (struct trapframe *)pcb->pcb_kstack - 1; *tf = *p1->p_md.md_regs; setredzone(p2); /* * If specified, give the child a different stack. */ if (stack != NULL) tf->tf_rsp = (u_int64_t)stack + stacksize; sf = (struct switchframe *)tf - 1; sf->sf_r12 = (u_int64_t)func; sf->sf_r13 = (u_int64_t)arg; sf->sf_rip = (u_int64_t)proc_trampoline; pcb->pcb_rsp = (u_int64_t)sf; pcb->pcb_rbp = 0; }
/* * cpu_exit is called as the last action during exit. * * We clean up a little and then call sched_exit() with the old proc as an * argument. */ void cpu_exit(struct proc *p) { /* If we were using the FPU, forget about it. */ if (p->p_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(p, 0); pmap_deactivate(p); sched_exit(p); }
int process_write_fpregs(struct proc *p, struct fpreg *regs) { struct fxsave64 *frame = process_fpframe(p); if (p->p_md.md_flags & MDP_USEDFPU) { fpusave_proc(p, 0); } else { p->p_md.md_flags |= MDP_USEDFPU; } memcpy(frame, ®s->fxstate, sizeof(*regs)); frame->fx_mxcsr &= fpu_mxcsr_mask; return (0); }
/* * cpu_exit is called as the last action during exit. * * We clean up a little and then call sched_exit() with the old proc as an * argument. */ void cpu_exit(struct proc *p) { /* If we were using the FPU, forget about it. */ if (p->p_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(p, 0); if (p->p_md.md_flags & MDP_USEDMTRR) mtrr_clean(p); pmap_deactivate(p); tss_free(p->p_md.md_tss_sel); sched_exit(p); }
/* * cpu_exit is called as the last action during exit. * * We clean up a little and then call switch_exit() with the old proc as an * argument. switch_exit() first switches to proc0's context, and finally * jumps into switch() to wait for another process to wake up. */ void cpu_exit(struct proc *p) { /* If we were using the FPU, forget about it. */ if (p->p_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(p, 0); if (p->p_md.md_flags & MDP_USEDMTRR) mtrr_clean(p); /* * No need to do user LDT cleanup here; it's handled in * pmap_destroy(). */ uvmexp.swtch++; switch_exit(p, exit2); }
/* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * psl to gain improper privileges or to cause * a machine fault. */ int sys_sigreturn(struct proc *p, void *v, register_t *retval) { struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; struct sigcontext *scp, ksc; struct trapframe *tf = p->p_md.md_regs; int error; scp = SCARG(uap, sigcntxp); #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) && (!sigpid || p->p_pid == sigpid)) printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); #endif if ((error = copyin((caddr_t)scp, &ksc, sizeof ksc))) return (error); if (((ksc.sc_rflags ^ tf->tf_rflags) & PSL_USERSTATIC) != 0 || !USERMODE(ksc.sc_cs, ksc.sc_eflags)) return (EINVAL); if (p->p_md.md_flags & MDP_USEDFPU) fpusave_proc(p, 0); if (ksc.sc_fpstate && (error = copyin(ksc.sc_fpstate, &p->p_addr->u_pcb.pcb_savefpu.fp_fxsave, sizeof (struct fxsave64)))) return (error); ksc.sc_trapno = tf->tf_trapno; ksc.sc_err = tf->tf_err; bcopy(&ksc, tf, sizeof(*tf)); /* Restore signal stack. */ if (ksc.sc_onstack) p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; p->p_sigmask = ksc.sc_mask & ~sigcantmask; return (EJUSTRETURN); }
/* * Clear registers on exec */ void setregs(struct proc *p, struct exec_package *pack, u_long stack, register_t *retval) { struct pcb *pcb = &p->p_addr->u_pcb; struct trapframe *tf; /* If we were using the FPU, forget about it. */ if (p->p_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(p, 0); #ifdef USER_LDT pmap_ldt_cleanup(p); #endif p->p_md.md_flags &= ~MDP_USEDFPU; pcb->pcb_flags = 0; pcb->pcb_savefpu.fp_fxsave.fx_fcw = __INITIAL_NPXCW__; pcb->pcb_savefpu.fp_fxsave.fx_mxcsr = __INITIAL_MXCSR__; pcb->pcb_savefpu.fp_fxsave.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; tf = p->p_md.md_regs; tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL); tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL); tf->tf_fs = LSEL(LUDATA_SEL, SEL_UPL); tf->tf_gs = LSEL(LUDATA_SEL, SEL_UPL); tf->tf_rdi = 0; tf->tf_rsi = 0; tf->tf_rbp = 0; tf->tf_rbx = 0; tf->tf_rdx = 0; tf->tf_rcx = 0; tf->tf_rax = 0; tf->tf_rip = pack->ep_entry; tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL); tf->tf_rflags = PSL_USERSET; tf->tf_rsp = stack; tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL); retval[1] = 0; }
int process_read_fpregs(struct proc *p, struct fpreg *regs) { struct fxsave64 *frame = process_fpframe(p); if (p->p_md.md_flags & MDP_USEDFPU) { fpusave_proc(p, 1); } else { /* Fake a FNINIT. */ memset(frame, 0, sizeof(*regs)); frame->fx_fcw = __INITIAL_NPXCW__; frame->fx_fsw = 0x0000; frame->fx_ftw = 0xff; frame->fx_mxcsr = __INITIAL_MXCSR__; frame->fx_mxcsr_mask = fpu_mxcsr_mask; p->p_md.md_flags |= MDP_USEDFPU; } memcpy(®s->fxstate, frame, sizeof(*regs)); return (0); }
/* * 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 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 }
/* * 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); } }
/* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * in u. to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ void sendsig(sig_t catcher, int sig, int mask, u_long code, int type, union sigval val) { struct proc *p = curproc; struct trapframe *tf = p->p_md.md_regs; struct sigacts * psp = p->p_sigacts; struct sigcontext ksc; siginfo_t ksi; register_t sp, scp, sip; u_long sss; #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) && (!sigpid || p->p_pid == sigpid)) printf("sendsig: %s[%d] sig %d catcher %p\n", p->p_comm, p->p_pid, sig, catcher); #endif bcopy(tf, &ksc, sizeof(*tf)); ksc.sc_onstack = psp->ps_sigstk.ss_flags & SS_ONSTACK; ksc.sc_mask = mask; ksc.sc_fpstate = NULL; /* Allocate space for the signal handler context. */ if ((psp->ps_flags & SAS_ALTSTACK) && !ksc.sc_onstack && (psp->ps_sigonstack & sigmask(sig))) { sp = (register_t)psp->ps_sigstk.ss_sp + psp->ps_sigstk.ss_size; psp->ps_sigstk.ss_flags |= SS_ONSTACK; } else sp = tf->tf_rsp - 128; sp &= ~15ULL; /* just in case */ sss = (sizeof(ksc) + 15) & ~15; if (p->p_md.md_flags & MDP_USEDFPU) { fpusave_proc(p, 1); sp -= sizeof(struct fxsave64); ksc.sc_fpstate = (struct fxsave64 *)sp; if (copyout(&p->p_addr->u_pcb.pcb_savefpu.fp_fxsave, (void *)sp, sizeof(struct fxsave64))) sigexit(p, SIGILL); } sip = 0; if (psp->ps_siginfo & sigmask(sig)) { sip = sp - ((sizeof(ksi) + 15) & ~15); sss += (sizeof(ksi) + 15) & ~15; initsiginfo(&ksi, sig, code, type, val); if (copyout(&ksi, (void *)sip, sizeof(ksi))) sigexit(p, SIGILL); } scp = sp - sss; if (copyout(&ksc, (void *)scp, sizeof(ksc))) sigexit(p, SIGILL); /* * Build context to run handler in. */ tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL); tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL); tf->tf_fs = LSEL(LUDATA_SEL, SEL_UPL); tf->tf_gs = LSEL(LUDATA_SEL, SEL_UPL); tf->tf_rax = (u_int64_t)catcher; tf->tf_rdi = sig; tf->tf_rsi = sip; tf->tf_rdx = scp; tf->tf_rip = (u_int64_t)p->p_sigcode; tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL); tf->tf_rflags &= ~(PSL_T|PSL_VM|PSL_AC); tf->tf_rsp = scp; tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL); #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) && (!sigpid || p->p_pid == sigpid)) printf("sendsig(%d): pc 0x%x, catcher 0x%x\n", p->p_pid, tf->tf_rip, tf->tf_rax); #endif }
/* * Finish a fork operation, with process p2 nearly set up. * Copy and update the kernel stack and pcb, making the child * ready to run, and marking it so that it can return differently * than the parent. Returns 1 in the child process, 0 in the parent. * We currently double-map the user area so that the stack is at the same * address in each process; in the future we will probably relocate * the frame pointers on the stack after copying. */ void cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize, void (*func)(void *), void *arg) { struct pcb *pcb = &p2->p_addr->u_pcb; struct trapframe *tf; struct switchframe *sf; /* * If fpuproc != p1, then the fpu h/w state is irrelevant and the * state had better already be in the pcb. This is true for forks * but not for dumps. * * If fpuproc == p1, then we have to save the fpu h/w state to * p1's pcb so that we can copy it. */ if (p1->p_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(p1, 1); p2->p_md.md_flags = p1->p_md.md_flags; syscall_intern(p2); /* Copy pcb from proc p1 to p2. */ if (p1 == curproc) { /* Sync the PCB before we copy it. */ savectx(curpcb); } #ifdef DIAGNOSTIC else if (p1 != &proc0) panic("cpu_fork: curproc"); #endif *pcb = p1->p_addr->u_pcb; /* * Preset these so that gdt_compact() doesn't get confused if called * during the allocations below. * * Note: pcb_ldt_sel is handled in the pmap_activate() call when * we run the new process. */ p2->p_md.md_tss_sel = GSEL(GNULL_SEL, SEL_KPL); /* * Activate the addres space. Note this will refresh pcb_ldt_sel. */ pmap_activate(p2); /* Fix up the TSS. */ pcb->pcb_tss.tss_rsp0 = (u_int64_t)p2->p_addr + USPACE - 16; pcb->pcb_tss.tss_ist[0] = (u_int64_t)p2->p_addr + PAGE_SIZE - 16; p2->p_md.md_tss_sel = tss_alloc(pcb); /* * Copy the trapframe. */ p2->p_md.md_regs = tf = (struct trapframe *)pcb->pcb_tss.tss_rsp0 - 1; *tf = *p1->p_md.md_regs; setredzone(p2); /* * If specified, give the child a different stack. */ if (stack != NULL) tf->tf_rsp = (u_int64_t)stack + stacksize; sf = (struct switchframe *)tf - 1; sf->sf_ppl = IPL_NONE; sf->sf_r12 = (u_int64_t)func; sf->sf_r13 = (u_int64_t)arg; if (func == child_return) sf->sf_rip = (u_int64_t)child_trampoline; else sf->sf_rip = (u_int64_t)proc_trampoline; pcb->pcb_rsp = (u_int64_t)sf; pcb->pcb_rbp = 0; }