int process_write_regs(struct lwp *l, const struct reg *regs) { struct trapframe *tf = process_frame(l); #ifdef VM86 if (regs->r_eflags & PSL_VM) { void syscall_vm86(struct trapframe *); tf->tf_vm86_gs = regs->r_gs; tf->tf_vm86_fs = regs->r_fs; tf->tf_vm86_es = regs->r_es; tf->tf_vm86_ds = regs->r_ds; set_vflags(l, regs->r_eflags); /* * Make sure that attempts at system calls from vm86 * mode die horribly. */ l->l_proc->p_md.md_syscall = syscall_vm86; } else #endif { /* * Check for security violations. */ if (((regs->r_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || !USERMODE(regs->r_cs, regs->r_eflags)) return (EINVAL); tf->tf_gs = regs->r_gs; tf->tf_fs = regs->r_fs; tf->tf_es = regs->r_es; tf->tf_ds = regs->r_ds; #ifdef VM86 /* Restore normal syscall handler */ if (tf->tf_eflags & PSL_VM) (*l->l_proc->p_emul->e_syscall_intern)(l->l_proc); #endif tf->tf_eflags = regs->r_eflags; } tf->tf_edi = regs->r_edi; tf->tf_esi = regs->r_esi; tf->tf_ebp = regs->r_ebp; tf->tf_ebx = regs->r_ebx; tf->tf_edx = regs->r_edx; tf->tf_ecx = regs->r_ecx; tf->tf_eax = regs->r_eax; tf->tf_eip = regs->r_eip; tf->tf_cs = regs->r_cs; tf->tf_esp = regs->r_esp; tf->tf_ss = regs->r_ss; return (0); }
static int linux_restore_sigcontext(struct lwp *l, struct linux_sigcontext *scp, register_t *retval) { struct proc *p = l->l_proc; struct sigaltstack *sas = &l->l_sigstk; struct trapframe *tf; sigset_t mask; ssize_t ss_gap; /* Restore register context. */ tf = l->l_md.md_regs; DPRINTF(("sigreturn enter esp=0x%x eip=0x%x\n", tf->tf_esp, tf->tf_eip)); #ifdef VM86 if (scp->sc_eflags & PSL_VM) { void syscall_vm86(struct trapframe *); tf->tf_vm86_gs = scp->sc_gs; tf->tf_vm86_fs = scp->sc_fs; tf->tf_vm86_es = scp->sc_es; tf->tf_vm86_ds = scp->sc_ds; set_vflags(l, scp->sc_eflags); p->p_md.md_syscall = syscall_vm86; } else #endif { /* * Check for security violations. If we're returning to * protected mode, the CPU will validate the segment registers * automatically and generate a trap on violations. We handle * the trap, rather than doing all of the checking here. */ if (((scp->sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || !USERMODE(scp->sc_cs, scp->sc_eflags)) return EINVAL; tf->tf_gs = scp->sc_gs; tf->tf_fs = scp->sc_fs; tf->tf_es = scp->sc_es; tf->tf_ds = scp->sc_ds; #ifdef VM86 if (tf->tf_eflags & PSL_VM) (*p->p_emul->e_syscall_intern)(p); #endif tf->tf_eflags = scp->sc_eflags; } tf->tf_edi = scp->sc_edi; tf->tf_esi = scp->sc_esi; tf->tf_ebp = scp->sc_ebp; tf->tf_ebx = scp->sc_ebx; tf->tf_edx = scp->sc_edx; tf->tf_ecx = scp->sc_ecx; tf->tf_eax = scp->sc_eax; tf->tf_eip = scp->sc_eip; tf->tf_cs = scp->sc_cs; tf->tf_esp = scp->sc_esp_at_signal; tf->tf_ss = scp->sc_ss; /* Restore signal stack. */ /* * Linux really does it this way; it doesn't have space in sigframe * to save the onstack flag. */ mutex_enter(p->p_lock); ss_gap = (ssize_t)((char *)scp->sc_esp_at_signal - (char *)sas->ss_sp); if (ss_gap >= 0 && ss_gap < sas->ss_size) sas->ss_flags |= SS_ONSTACK; else sas->ss_flags &= ~SS_ONSTACK; /* Restore signal mask. */ linux_old_to_native_sigset(&mask, &scp->sc_mask); (void) sigprocmask1(l, SIG_SETMASK, &mask, 0); mutex_exit(p->p_lock); DPRINTF(("sigreturn exit esp=0x%x eip=0x%x\n", tf->tf_esp, tf->tf_eip)); return EJUSTRETURN; }
/* * 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 linux_sys_sigreturn(struct proc *p, void *v, register_t *retval) { struct linux_sys_sigreturn_args /* { syscallarg(struct linux_sigcontext *) scp; } */ *uap = v; struct linux_sigcontext *scp, context; struct trapframe *tf; tf = p->p_md.md_regs; /* * The trampoline code hands us the context. * It is unsafe to keep track of it ourselves, in the event that a * program jumps out of a signal handler. */ scp = SCARG(uap, scp); if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0) return (EFAULT); /* * Restore signal context. */ #ifdef VM86 if (context.sc_eflags & PSL_VM) { tf->tf_vm86_gs = context.sc_gs; tf->tf_vm86_fs = context.sc_fs; tf->tf_vm86_es = context.sc_es; tf->tf_vm86_ds = context.sc_ds; set_vflags(p, context.sc_eflags); } else #endif { /* * Check for security violations. If we're returning to * protected mode, the CPU will validate the segment registers * automatically and generate a trap on violations. We handle * the trap, rather than doing all of the checking here. */ if (((context.sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || !USERMODE(context.sc_cs, context.sc_eflags)) return (EINVAL); tf->tf_fs = context.sc_fs; tf->tf_gs = context.sc_gs; tf->tf_es = context.sc_es; tf->tf_ds = context.sc_ds; tf->tf_eflags = context.sc_eflags; } tf->tf_edi = context.sc_edi; tf->tf_esi = context.sc_esi; tf->tf_ebp = context.sc_ebp; tf->tf_ebx = context.sc_ebx; tf->tf_edx = context.sc_edx; tf->tf_ecx = context.sc_ecx; tf->tf_eax = context.sc_eax; tf->tf_eip = context.sc_eip; tf->tf_cs = context.sc_cs; tf->tf_esp = context.sc_esp_at_signal; tf->tf_ss = context.sc_ss; p->p_sigstk.ss_flags &= ~SS_ONSTACK; p->p_sigmask = context.sc_mask & ~sigcantmask; return (EJUSTRETURN); }
int i386_vm86(struct proc *p, char *args, register_t *retval) { struct trapframe *tf = p->p_md.md_regs; struct pcb *pcb = &p->p_addr->u_pcb; struct vm86_kern vm86s; int error; error = copyin(args, &vm86s, sizeof(vm86s)); if (error) return (error); pcb->vm86_userp = (void *)args; /* * Keep mask of flags we simulate to simulate a particular type of * processor. */ switch (vm86s.ss_cpu_type) { case VCPU_086: case VCPU_186: case VCPU_286: pcb->vm86_flagmask = PSL_ID|PSL_AC|PSL_NT|PSL_IOPL; break; case VCPU_386: pcb->vm86_flagmask = PSL_ID|PSL_AC; break; case VCPU_486: pcb->vm86_flagmask = PSL_ID; break; case VCPU_586: pcb->vm86_flagmask = 0; break; default: return (EINVAL); } #define DOVREG(reg) tf->tf_vm86_##reg = (u_short) vm86s.regs.vmsc.sc_##reg #define DOREG(reg) tf->tf_##reg = (u_short) vm86s.regs.vmsc.sc_##reg DOVREG(ds); DOVREG(es); DOVREG(fs); DOVREG(gs); DOREG(edi); DOREG(esi); DOREG(ebp); DOREG(eax); DOREG(ebx); DOREG(ecx); DOREG(edx); DOREG(eip); DOREG(cs); DOREG(esp); DOREG(ss); #undef DOVREG #undef DOREG /* Going into vm86 mode jumps off the signal stack. */ p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; set_vflags(p, vm86s.regs.vmsc.sc_eflags | PSL_VM); return (EJUSTRETURN); }
/* * Handle a GP fault that occurred while in VM86 mode. Things that are easy * to handle here are done here (much more efficient than trapping to 32-bit * handler code and then having it restart VM86 mode). */ void vm86_gpfault(struct proc *p, int type) { struct trapframe *tf = p->p_md.md_regs; union sigval sv; /* * we want to fetch some stuff from the current user virtual * address space for checking. remember that the frame's * segment selectors are real-mode style selectors. */ u_long cs, ip, ss, sp; u_char tmpbyte; int trace; cs = CS(tf) << 4; ip = IP(tf); ss = SS(tf) << 4; sp = SP(tf); trace = tf->tf_eflags & PSL_T; /* * For most of these, we must set all the registers before calling * macros/functions which might do a vm86_return. */ tmpbyte = getbyte(cs, ip); IP(tf) = ip; switch (tmpbyte) { case CLI: /* simulate handling of IF */ clr_vif(p); break; case STI: /* simulate handling of IF. * XXX the i386 enables interrupts one instruction later. * code here is wrong, but much simpler than doing it Right. */ set_vif(p); break; case INTxx: /* try fast intxx, or return to 32bit mode to handle it. */ tmpbyte = getbyte(cs, ip); IP(tf) = ip; fast_intxx(p, tmpbyte); break; case INTO: if (tf->tf_eflags & PSL_V) fast_intxx(p, 4); break; case PUSHF: putword(ss, sp, get_vflags_short(p)); SP(tf) = sp; break; case IRET: IP(tf) = getword(ss, sp); CS(tf) = getword(ss, sp); case POPF: set_vflags_short(p, getword(ss, sp)); SP(tf) = sp; break; case OPSIZ: tmpbyte = getbyte(cs, ip); IP(tf) = ip; switch (tmpbyte) { case PUSHF: putdword(ss, sp, get_vflags(p) & ~PSL_VM); SP(tf) = sp; break; case IRET: IP(tf) = getdword(ss, sp); CS(tf) = getdword(ss, sp); case POPF: set_vflags(p, getdword(ss, sp) | PSL_VM); SP(tf) = sp; break; default: IP(tf) -= 2; goto bad; } break; case LOCK: default: IP(tf) -= 1; goto bad; } if (trace && tf->tf_eflags & PSL_VM) { sv.sival_int = 0; trapsignal(p, SIGTRAP, T_TRCTRAP, TRAP_TRACE, sv); } return; bad: vm86_return(p, VM86_UNKNOWN); return; }
/* * Set to ucontext specified. * has been taken. Reset signal mask and * stack state from context. * 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 svr4_setcontext(struct proc *p, struct svr4_ucontext *uc) { struct sigacts *psp = p->p_sigacts; struct trapframe *tf; svr4_greg_t *r = uc->uc_mcontext.greg; struct svr4_sigaltstack *s = &uc->uc_stack; struct sigaltstack *sf = &psp->ps_sigstk; int mask; /* * XXX: * Should we check the value of flags to determine what to restore? * What to do with uc_link? * What to do with floating point stuff? * Should we bother with the rest of the registers that we * set to 0 right now? */ tf = p->p_md.md_regs; /* * Restore register context. */ #ifdef VM86 if (r[SVR4_X86_EFL] & PSL_VM) { tf->tf_vm86_gs = r[SVR4_X86_GS]; tf->tf_vm86_fs = r[SVR4_X86_FS]; tf->tf_vm86_es = r[SVR4_X86_ES]; tf->tf_vm86_ds = r[SVR4_X86_DS]; set_vflags(p, r[SVR4_X86_EFL]); } else #endif { /* * Check for security violations. If we're returning to * protected mode, the CPU will validate the segment registers * automatically and generate a trap on violations. We handle * the trap, rather than doing all of the checking here. */ if (((r[SVR4_X86_EFL] ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || !USERMODE(r[SVR4_X86_CS], r[SVR4_X86_EFL])) return (EINVAL); tf->tf_fs = r[SVR4_X86_FS]; tf->tf_gs = r[SVR4_X86_GS]; tf->tf_es = r[SVR4_X86_ES]; tf->tf_ds = r[SVR4_X86_DS]; tf->tf_eflags = r[SVR4_X86_EFL]; } tf->tf_edi = r[SVR4_X86_EDI]; tf->tf_esi = r[SVR4_X86_ESI]; tf->tf_ebp = r[SVR4_X86_EBP]; tf->tf_ebx = r[SVR4_X86_EBX]; tf->tf_edx = r[SVR4_X86_EDX]; tf->tf_ecx = r[SVR4_X86_ECX]; tf->tf_eax = r[SVR4_X86_EAX]; tf->tf_eip = r[SVR4_X86_EIP]; tf->tf_cs = r[SVR4_X86_CS]; tf->tf_ss = r[SVR4_X86_SS]; tf->tf_esp = r[SVR4_X86_ESP]; /* * restore signal stack */ svr4_to_bsd_sigaltstack(s, sf); /* * restore signal mask */ svr4_to_bsd_sigset(&uc->uc_sigmask, &mask); p->p_sigmask = mask & ~sigcantmask; return EJUSTRETURN; }
int compat_13_sys_sigreturn(struct lwp *l, const struct compat_13_sys_sigreturn_args *uap, register_t *retval) { /* { syscallarg(struct sigcontext13 *) sigcntxp; } */ struct proc *p = l->l_proc; struct sigcontext13 *scp, context; struct trapframe *tf; sigset_t mask; /* * The trampoline code hands us the context. * It is unsafe to keep track of it ourselves, in the event that a * program jumps out of a signal handler. */ scp = SCARG(uap, sigcntxp); if (copyin((void *)scp, &context, sizeof(*scp)) != 0) return (EFAULT); /* Restore register context. */ tf = l->l_md.md_regs; #ifdef VM86 if (context.sc_eflags & PSL_VM) { void syscall_vm86(struct trapframe *); tf->tf_vm86_gs = context.sc_gs; tf->tf_vm86_fs = context.sc_fs; tf->tf_vm86_es = context.sc_es; tf->tf_vm86_ds = context.sc_ds; set_vflags(l, context.sc_eflags); p->p_md.md_syscall = syscall_vm86; } else #endif { /* * Check for security violations. If we're returning to * protected mode, the CPU will validate the segment registers * automatically and generate a trap on violations. We handle * the trap, rather than doing all of the checking here. */ if (((context.sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || !USERMODE(context.sc_cs, context.sc_eflags)) return (EINVAL); tf->tf_gs = context.sc_gs; tf->tf_fs = context.sc_fs; tf->tf_es = context.sc_es; tf->tf_ds = context.sc_ds; tf->tf_eflags &= ~PSL_USER; tf->tf_eflags |= context.sc_eflags & PSL_USER; } tf->tf_edi = context.sc_edi; tf->tf_esi = context.sc_esi; tf->tf_ebp = context.sc_ebp; tf->tf_ebx = context.sc_ebx; tf->tf_edx = context.sc_edx; tf->tf_ecx = context.sc_ecx; tf->tf_eax = context.sc_eax; tf->tf_eip = context.sc_eip; tf->tf_cs = context.sc_cs; tf->tf_esp = context.sc_esp; tf->tf_ss = context.sc_ss; mutex_enter(p->p_lock); /* Restore signal stack. */ if (context.sc_onstack & SS_ONSTACK) l->l_sigstk.ss_flags |= SS_ONSTACK; else l->l_sigstk.ss_flags &= ~SS_ONSTACK; /* Restore signal mask. */ native_sigset13_to_sigset(&context.sc_mask, &mask); (void) sigprocmask1(l, SIG_SETMASK, &mask, 0); mutex_exit(p->p_lock); return (EJUSTRETURN); }