Changeset View
Changeset View
Standalone View
Standalone View
sys/i386/i386/machdep.c
Show First 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | |||||
/* Sanity check for __curthread() */ | /* Sanity check for __curthread() */ | ||||
CTASSERT(offsetof(struct pcpu, pc_curthread) == 0); | CTASSERT(offsetof(struct pcpu, pc_curthread) == 0); | ||||
register_t init386(int first); | register_t init386(int first); | ||||
void dblfault_handler(void); | void dblfault_handler(void); | ||||
void identify_cpu(void); | void identify_cpu(void); | ||||
static void cpu_startup(void *); | static void cpu_startup(void *); | ||||
static void fpstate_drop(struct thread *td); | |||||
static void get_fpcontext(struct thread *td, mcontext_t *mcp, | |||||
char *xfpusave, size_t xfpusave_len); | |||||
static int set_fpcontext(struct thread *td, mcontext_t *mcp, | |||||
char *xfpustate, size_t xfpustate_len); | |||||
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); | SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); | ||||
/* Intel ICH registers */ | /* Intel ICH registers */ | ||||
#define ICH_PMBASE 0x400 | #define ICH_PMBASE 0x400 | ||||
#define ICH_SMI_EN ICH_PMBASE + 0x30 | #define ICH_SMI_EN ICH_PMBASE + 0x30 | ||||
int _udatasel, _ucodesel; | int _udatasel, _ucodesel; | ||||
u_int basemem; | u_int basemem; | ||||
static int above4g_allow = 1; | static int above4g_allow = 1; | ||||
static int above24g_allow = 0; | static int above24g_allow = 0; | ||||
int cold = 1; | int cold = 1; | ||||
#ifdef COMPAT_43 | |||||
static void osendsig(sig_t catcher, ksiginfo_t *, sigset_t *mask); | |||||
#endif | |||||
#ifdef COMPAT_FREEBSD4 | |||||
static void freebsd4_sendsig(sig_t catcher, ksiginfo_t *, sigset_t *mask); | |||||
#endif | |||||
long Maxmem = 0; | long Maxmem = 0; | ||||
long realmem = 0; | long realmem = 0; | ||||
#ifdef PAE | #ifdef PAE | ||||
FEATURE(pae, "Physical Address Extensions"); | FEATURE(pae, "Physical Address Extensions"); | ||||
#endif | #endif | ||||
struct kva_md_info kmi; | struct kva_md_info kmi; | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Set up buffers, so they can be used to read disk labels. | * Set up buffers, so they can be used to read disk labels. | ||||
*/ | */ | ||||
bufinit(); | bufinit(); | ||||
vm_pager_bufferinit(); | vm_pager_bufferinit(); | ||||
cpu_setregs(); | cpu_setregs(); | ||||
} | } | ||||
/* | |||||
* Send an interrupt to process. | |||||
* | |||||
* Stack is set up to allow sigcode stored | |||||
* at top to call routine, followed by call | |||||
* to sigreturn routine below. After sigreturn | |||||
* resets the signal mask, the stack, and the | |||||
* frame pointer, it returns to the user | |||||
* specified pc, psl. | |||||
*/ | |||||
#ifdef COMPAT_43 | |||||
static void | |||||
osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) | |||||
{ | |||||
struct osigframe sf, *fp; | |||||
struct proc *p; | |||||
struct thread *td; | |||||
struct sigacts *psp; | |||||
struct trapframe *regs; | |||||
int sig; | |||||
int oonstack; | |||||
td = curthread; | |||||
p = td->td_proc; | |||||
PROC_LOCK_ASSERT(p, MA_OWNED); | |||||
sig = ksi->ksi_signo; | |||||
psp = p->p_sigacts; | |||||
mtx_assert(&psp->ps_mtx, MA_OWNED); | |||||
regs = td->td_frame; | |||||
oonstack = sigonstack(regs->tf_esp); | |||||
/* Allocate space for the signal handler context. */ | |||||
if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && | |||||
SIGISMEMBER(psp->ps_sigonstack, sig)) { | |||||
fp = (struct osigframe *)((uintptr_t)td->td_sigstk.ss_sp + | |||||
td->td_sigstk.ss_size - sizeof(struct osigframe)); | |||||
#if defined(COMPAT_43) | |||||
td->td_sigstk.ss_flags |= SS_ONSTACK; | |||||
#endif | |||||
} else | |||||
fp = (struct osigframe *)regs->tf_esp - 1; | |||||
/* Build the argument list for the signal handler. */ | |||||
sf.sf_signum = sig; | |||||
sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc; | |||||
bzero(&sf.sf_siginfo, sizeof(sf.sf_siginfo)); | |||||
if (SIGISMEMBER(psp->ps_siginfo, sig)) { | |||||
/* Signal handler installed with SA_SIGINFO. */ | |||||
sf.sf_arg2 = (register_t)&fp->sf_siginfo; | |||||
sf.sf_siginfo.si_signo = sig; | |||||
sf.sf_siginfo.si_code = ksi->ksi_code; | |||||
sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher; | |||||
sf.sf_addr = 0; | |||||
} else { | |||||
/* Old FreeBSD-style arguments. */ | |||||
sf.sf_arg2 = ksi->ksi_code; | |||||
sf.sf_addr = (register_t)ksi->ksi_addr; | |||||
sf.sf_ahu.sf_handler = catcher; | |||||
} | |||||
mtx_unlock(&psp->ps_mtx); | |||||
PROC_UNLOCK(p); | |||||
/* Save most if not all of trap frame. */ | |||||
sf.sf_siginfo.si_sc.sc_eax = regs->tf_eax; | |||||
sf.sf_siginfo.si_sc.sc_ebx = regs->tf_ebx; | |||||
sf.sf_siginfo.si_sc.sc_ecx = regs->tf_ecx; | |||||
sf.sf_siginfo.si_sc.sc_edx = regs->tf_edx; | |||||
sf.sf_siginfo.si_sc.sc_esi = regs->tf_esi; | |||||
sf.sf_siginfo.si_sc.sc_edi = regs->tf_edi; | |||||
sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs; | |||||
sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds; | |||||
sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss; | |||||
sf.sf_siginfo.si_sc.sc_es = regs->tf_es; | |||||
sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs; | |||||
sf.sf_siginfo.si_sc.sc_gs = rgs(); | |||||
sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp; | |||||
/* Build the signal context to be used by osigreturn(). */ | |||||
sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0; | |||||
SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask); | |||||
sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp; | |||||
sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp; | |||||
sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip; | |||||
sf.sf_siginfo.si_sc.sc_ps = regs->tf_eflags; | |||||
sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno; | |||||
sf.sf_siginfo.si_sc.sc_err = regs->tf_err; | |||||
/* | |||||
* If we're a vm86 process, we want to save the segment registers. | |||||
* We also change eflags to be our emulated eflags, not the actual | |||||
* eflags. | |||||
*/ | |||||
if (regs->tf_eflags & PSL_VM) { | |||||
/* XXX confusing names: `tf' isn't a trapframe; `regs' is. */ | |||||
struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; | |||||
struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86; | |||||
sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs; | |||||
sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs; | |||||
sf.sf_siginfo.si_sc.sc_es = tf->tf_vm86_es; | |||||
sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds; | |||||
if (vm86->vm86_has_vme == 0) | |||||
sf.sf_siginfo.si_sc.sc_ps = | |||||
(tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | | |||||
(vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); | |||||
/* See sendsig() for comments. */ | |||||
tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP); | |||||
} | |||||
/* | |||||
* Copy the sigframe out to the user's stack. | |||||
*/ | |||||
if (copyout(&sf, fp, sizeof(*fp)) != 0) { | |||||
PROC_LOCK(p); | |||||
sigexit(td, SIGILL); | |||||
} | |||||
regs->tf_esp = (int)fp; | |||||
if (p->p_sysent->sv_sigcode_base != 0) { | |||||
regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode - | |||||
szosigcode; | |||||
} else { | |||||
/* a.out sysentvec does not use shared page */ | |||||
regs->tf_eip = p->p_sysent->sv_psstrings - szosigcode; | |||||
} | |||||
regs->tf_eflags &= ~(PSL_T | PSL_D); | |||||
regs->tf_cs = _ucodesel; | |||||
regs->tf_ds = _udatasel; | |||||
regs->tf_es = _udatasel; | |||||
regs->tf_fs = _udatasel; | |||||
load_gs(_udatasel); | |||||
regs->tf_ss = _udatasel; | |||||
PROC_LOCK(p); | |||||
mtx_lock(&psp->ps_mtx); | |||||
} | |||||
#endif /* COMPAT_43 */ | |||||
#ifdef COMPAT_FREEBSD4 | |||||
static void | |||||
freebsd4_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) | |||||
{ | |||||
struct sigframe4 sf, *sfp; | |||||
struct proc *p; | |||||
struct thread *td; | |||||
struct sigacts *psp; | |||||
struct trapframe *regs; | |||||
int sig; | |||||
int oonstack; | |||||
td = curthread; | |||||
p = td->td_proc; | |||||
PROC_LOCK_ASSERT(p, MA_OWNED); | |||||
sig = ksi->ksi_signo; | |||||
psp = p->p_sigacts; | |||||
mtx_assert(&psp->ps_mtx, MA_OWNED); | |||||
regs = td->td_frame; | |||||
oonstack = sigonstack(regs->tf_esp); | |||||
/* Save user context. */ | |||||
bzero(&sf, sizeof(sf)); | |||||
sf.sf_uc.uc_sigmask = *mask; | |||||
sf.sf_uc.uc_stack = td->td_sigstk; | |||||
sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) | |||||
? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; | |||||
sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; | |||||
sf.sf_uc.uc_mcontext.mc_gs = rgs(); | |||||
bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs)); | |||||
bzero(sf.sf_uc.uc_mcontext.mc_fpregs, | |||||
sizeof(sf.sf_uc.uc_mcontext.mc_fpregs)); | |||||
bzero(sf.sf_uc.uc_mcontext.__spare__, | |||||
sizeof(sf.sf_uc.uc_mcontext.__spare__)); | |||||
bzero(sf.sf_uc.__spare__, sizeof(sf.sf_uc.__spare__)); | |||||
/* Allocate space for the signal handler context. */ | |||||
if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && | |||||
SIGISMEMBER(psp->ps_sigonstack, sig)) { | |||||
sfp = (struct sigframe4 *)((uintptr_t)td->td_sigstk.ss_sp + | |||||
td->td_sigstk.ss_size - sizeof(struct sigframe4)); | |||||
#if defined(COMPAT_43) | |||||
td->td_sigstk.ss_flags |= SS_ONSTACK; | |||||
#endif | |||||
} else | |||||
sfp = (struct sigframe4 *)regs->tf_esp - 1; | |||||
/* Build the argument list for the signal handler. */ | |||||
sf.sf_signum = sig; | |||||
sf.sf_ucontext = (register_t)&sfp->sf_uc; | |||||
bzero(&sf.sf_si, sizeof(sf.sf_si)); | |||||
if (SIGISMEMBER(psp->ps_siginfo, sig)) { | |||||
/* Signal handler installed with SA_SIGINFO. */ | |||||
sf.sf_siginfo = (register_t)&sfp->sf_si; | |||||
sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; | |||||
/* Fill in POSIX parts */ | |||||
sf.sf_si.si_signo = sig; | |||||
sf.sf_si.si_code = ksi->ksi_code; | |||||
sf.sf_si.si_addr = ksi->ksi_addr; | |||||
} else { | |||||
/* Old FreeBSD-style arguments. */ | |||||
sf.sf_siginfo = ksi->ksi_code; | |||||
sf.sf_addr = (register_t)ksi->ksi_addr; | |||||
sf.sf_ahu.sf_handler = catcher; | |||||
} | |||||
mtx_unlock(&psp->ps_mtx); | |||||
PROC_UNLOCK(p); | |||||
/* | |||||
* If we're a vm86 process, we want to save the segment registers. | |||||
* We also change eflags to be our emulated eflags, not the actual | |||||
* eflags. | |||||
*/ | |||||
if (regs->tf_eflags & PSL_VM) { | |||||
struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; | |||||
struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86; | |||||
sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; | |||||
sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs; | |||||
sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es; | |||||
sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds; | |||||
if (vm86->vm86_has_vme == 0) | |||||
sf.sf_uc.uc_mcontext.mc_eflags = | |||||
(tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | | |||||
(vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); | |||||
/* | |||||
* Clear PSL_NT to inhibit T_TSSFLT faults on return from | |||||
* syscalls made by the signal handler. This just avoids | |||||
* wasting time for our lazy fixup of such faults. PSL_NT | |||||
* does nothing in vm86 mode, but vm86 programs can set it | |||||
* almost legitimately in probes for old cpu types. | |||||
*/ | |||||
tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP); | |||||
} | |||||
/* | |||||
* Copy the sigframe out to the user's stack. | |||||
*/ | |||||
if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { | |||||
PROC_LOCK(p); | |||||
sigexit(td, SIGILL); | |||||
} | |||||
regs->tf_esp = (int)sfp; | |||||
regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode - | |||||
szfreebsd4_sigcode; | |||||
regs->tf_eflags &= ~(PSL_T | PSL_D); | |||||
regs->tf_cs = _ucodesel; | |||||
regs->tf_ds = _udatasel; | |||||
regs->tf_es = _udatasel; | |||||
regs->tf_fs = _udatasel; | |||||
regs->tf_ss = _udatasel; | |||||
PROC_LOCK(p); | |||||
mtx_lock(&psp->ps_mtx); | |||||
} | |||||
#endif /* COMPAT_FREEBSD4 */ | |||||
void | void | ||||
sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) | |||||
{ | |||||
struct sigframe sf, *sfp; | |||||
struct proc *p; | |||||
struct thread *td; | |||||
struct sigacts *psp; | |||||
char *sp; | |||||
struct trapframe *regs; | |||||
struct segment_descriptor *sdp; | |||||
char *xfpusave; | |||||
size_t xfpusave_len; | |||||
int sig; | |||||
int oonstack; | |||||
td = curthread; | |||||
p = td->td_proc; | |||||
PROC_LOCK_ASSERT(p, MA_OWNED); | |||||
sig = ksi->ksi_signo; | |||||
psp = p->p_sigacts; | |||||
mtx_assert(&psp->ps_mtx, MA_OWNED); | |||||
#ifdef COMPAT_FREEBSD4 | |||||
if (SIGISMEMBER(psp->ps_freebsd4, sig)) { | |||||
freebsd4_sendsig(catcher, ksi, mask); | |||||
return; | |||||
} | |||||
#endif | |||||
#ifdef COMPAT_43 | |||||
if (SIGISMEMBER(psp->ps_osigset, sig)) { | |||||
osendsig(catcher, ksi, mask); | |||||
return; | |||||
} | |||||
#endif | |||||
regs = td->td_frame; | |||||
oonstack = sigonstack(regs->tf_esp); | |||||
if (cpu_max_ext_state_size > sizeof(union savefpu) && use_xsave) { | |||||
xfpusave_len = cpu_max_ext_state_size - sizeof(union savefpu); | |||||
xfpusave = __builtin_alloca(xfpusave_len); | |||||
} else { | |||||
xfpusave_len = 0; | |||||
xfpusave = NULL; | |||||
} | |||||
/* Save user context. */ | |||||
bzero(&sf, sizeof(sf)); | |||||
sf.sf_uc.uc_sigmask = *mask; | |||||
sf.sf_uc.uc_stack = td->td_sigstk; | |||||
sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) | |||||
? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; | |||||
sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; | |||||
sf.sf_uc.uc_mcontext.mc_gs = rgs(); | |||||
bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs)); | |||||
sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */ | |||||
get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len); | |||||
fpstate_drop(td); | |||||
/* | |||||
* Unconditionally fill the fsbase and gsbase into the mcontext. | |||||
*/ | |||||
sdp = &td->td_pcb->pcb_fsd; | |||||
sf.sf_uc.uc_mcontext.mc_fsbase = sdp->sd_hibase << 24 | | |||||
sdp->sd_lobase; | |||||
sdp = &td->td_pcb->pcb_gsd; | |||||
sf.sf_uc.uc_mcontext.mc_gsbase = sdp->sd_hibase << 24 | | |||||
sdp->sd_lobase; | |||||
bzero(sf.sf_uc.uc_mcontext.mc_spare2, | |||||
sizeof(sf.sf_uc.uc_mcontext.mc_spare2)); | |||||
/* Allocate space for the signal handler context. */ | |||||
if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && | |||||
SIGISMEMBER(psp->ps_sigonstack, sig)) { | |||||
sp = (char *)td->td_sigstk.ss_sp + td->td_sigstk.ss_size; | |||||
#if defined(COMPAT_43) | |||||
td->td_sigstk.ss_flags |= SS_ONSTACK; | |||||
#endif | |||||
} else | |||||
sp = (char *)regs->tf_esp - 128; | |||||
if (xfpusave != NULL) { | |||||
sp -= xfpusave_len; | |||||
sp = (char *)((unsigned int)sp & ~0x3F); | |||||
sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp; | |||||
} | |||||
sp -= sizeof(struct sigframe); | |||||
/* Align to 16 bytes. */ | |||||
sfp = (struct sigframe *)((unsigned int)sp & ~0xF); | |||||
/* Build the argument list for the signal handler. */ | |||||
sf.sf_signum = sig; | |||||
sf.sf_ucontext = (register_t)&sfp->sf_uc; | |||||
bzero(&sf.sf_si, sizeof(sf.sf_si)); | |||||
if (SIGISMEMBER(psp->ps_siginfo, sig)) { | |||||
/* Signal handler installed with SA_SIGINFO. */ | |||||
sf.sf_siginfo = (register_t)&sfp->sf_si; | |||||
sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; | |||||
/* Fill in POSIX parts */ | |||||
sf.sf_si = ksi->ksi_info; | |||||
sf.sf_si.si_signo = sig; /* maybe a translated signal */ | |||||
} else { | |||||
/* Old FreeBSD-style arguments. */ | |||||
sf.sf_siginfo = ksi->ksi_code; | |||||
sf.sf_addr = (register_t)ksi->ksi_addr; | |||||
sf.sf_ahu.sf_handler = catcher; | |||||
} | |||||
mtx_unlock(&psp->ps_mtx); | |||||
PROC_UNLOCK(p); | |||||
/* | |||||
* If we're a vm86 process, we want to save the segment registers. | |||||
* We also change eflags to be our emulated eflags, not the actual | |||||
* eflags. | |||||
*/ | |||||
if (regs->tf_eflags & PSL_VM) { | |||||
struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; | |||||
struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86; | |||||
sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; | |||||
sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs; | |||||
sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es; | |||||
sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds; | |||||
if (vm86->vm86_has_vme == 0) | |||||
sf.sf_uc.uc_mcontext.mc_eflags = | |||||
(tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | | |||||
(vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); | |||||
/* | |||||
* Clear PSL_NT to inhibit T_TSSFLT faults on return from | |||||
* syscalls made by the signal handler. This just avoids | |||||
* wasting time for our lazy fixup of such faults. PSL_NT | |||||
* does nothing in vm86 mode, but vm86 programs can set it | |||||
* almost legitimately in probes for old cpu types. | |||||
*/ | |||||
tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP); | |||||
} | |||||
/* | |||||
* Copy the sigframe out to the user's stack. | |||||
*/ | |||||
if (copyout(&sf, sfp, sizeof(*sfp)) != 0 || | |||||
(xfpusave != NULL && copyout(xfpusave, | |||||
(void *)sf.sf_uc.uc_mcontext.mc_xfpustate, xfpusave_len) | |||||
!= 0)) { | |||||
PROC_LOCK(p); | |||||
sigexit(td, SIGILL); | |||||
} | |||||
regs->tf_esp = (int)sfp; | |||||
regs->tf_eip = p->p_sysent->sv_sigcode_base; | |||||
if (regs->tf_eip == 0) | |||||
regs->tf_eip = p->p_sysent->sv_psstrings - szsigcode; | |||||
regs->tf_eflags &= ~(PSL_T | PSL_D); | |||||
regs->tf_cs = _ucodesel; | |||||
regs->tf_ds = _udatasel; | |||||
regs->tf_es = _udatasel; | |||||
regs->tf_fs = _udatasel; | |||||
regs->tf_ss = _udatasel; | |||||
PROC_LOCK(p); | |||||
mtx_lock(&psp->ps_mtx); | |||||
} | |||||
/* | |||||
* 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 | |||||
* state to gain improper privileges. | |||||
* | |||||
* MPSAFE | |||||
jrtc27: These got lost, I assume deliberate because of where our SMP support is these days :) | |||||
Done Inline ActionsYes, MPSAFE annotations are pointless today. kib: Yes, MPSAFE annotations are pointless today. | |||||
*/ | |||||
#ifdef COMPAT_43 | |||||
int | |||||
osigreturn(td, uap) | |||||
struct thread *td; | |||||
struct osigreturn_args /* { | |||||
struct osigcontext *sigcntxp; | |||||
} */ *uap; | |||||
{ | |||||
struct osigcontext sc; | |||||
struct trapframe *regs; | |||||
struct osigcontext *scp; | |||||
int eflags, error; | |||||
ksiginfo_t ksi; | |||||
regs = td->td_frame; | |||||
error = copyin(uap->sigcntxp, &sc, sizeof(sc)); | |||||
if (error != 0) | |||||
return (error); | |||||
scp = ≻ | |||||
eflags = scp->sc_ps; | |||||
if (eflags & PSL_VM) { | |||||
struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; | |||||
struct vm86_kernel *vm86; | |||||
/* | |||||
* if pcb_ext == 0 or vm86_inited == 0, the user hasn't | |||||
* set up the vm86 area, and we can't enter vm86 mode. | |||||
*/ | |||||
if (td->td_pcb->pcb_ext == 0) | |||||
return (EINVAL); | |||||
vm86 = &td->td_pcb->pcb_ext->ext_vm86; | |||||
if (vm86->vm86_inited == 0) | |||||
return (EINVAL); | |||||
/* Go back to user mode if both flags are set. */ | |||||
if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) { | |||||
ksiginfo_init_trap(&ksi); | |||||
ksi.ksi_signo = SIGBUS; | |||||
ksi.ksi_code = BUS_OBJERR; | |||||
ksi.ksi_addr = (void *)regs->tf_eip; | |||||
trapsignal(td, &ksi); | |||||
} | |||||
if (vm86->vm86_has_vme) { | |||||
eflags = (tf->tf_eflags & ~VME_USERCHANGE) | | |||||
(eflags & VME_USERCHANGE) | PSL_VM; | |||||
} else { | |||||
vm86->vm86_eflags = eflags; /* save VIF, VIP */ | |||||
eflags = (tf->tf_eflags & ~VM_USERCHANGE) | | |||||
(eflags & VM_USERCHANGE) | PSL_VM; | |||||
} | |||||
tf->tf_vm86_ds = scp->sc_ds; | |||||
tf->tf_vm86_es = scp->sc_es; | |||||
tf->tf_vm86_fs = scp->sc_fs; | |||||
tf->tf_vm86_gs = scp->sc_gs; | |||||
tf->tf_ds = _udatasel; | |||||
tf->tf_es = _udatasel; | |||||
tf->tf_fs = _udatasel; | |||||
} else { | |||||
/* | |||||
* Don't allow users to change privileged or reserved flags. | |||||
*/ | |||||
if (!EFL_SECURE(eflags, regs->tf_eflags)) { | |||||
return (EINVAL); | |||||
} | |||||
/* | |||||
* Don't allow users to load a valid privileged %cs. Let the | |||||
* hardware check for invalid selectors, excess privilege in | |||||
* other selectors, invalid %eip's and invalid %esp's. | |||||
*/ | |||||
if (!CS_SECURE(scp->sc_cs)) { | |||||
ksiginfo_init_trap(&ksi); | |||||
ksi.ksi_signo = SIGBUS; | |||||
ksi.ksi_code = BUS_OBJERR; | |||||
ksi.ksi_trapno = T_PROTFLT; | |||||
ksi.ksi_addr = (void *)regs->tf_eip; | |||||
trapsignal(td, &ksi); | |||||
return (EINVAL); | |||||
} | |||||
regs->tf_ds = scp->sc_ds; | |||||
regs->tf_es = scp->sc_es; | |||||
regs->tf_fs = scp->sc_fs; | |||||
} | |||||
/* Restore remaining registers. */ | |||||
regs->tf_eax = scp->sc_eax; | |||||
regs->tf_ebx = scp->sc_ebx; | |||||
regs->tf_ecx = scp->sc_ecx; | |||||
regs->tf_edx = scp->sc_edx; | |||||
regs->tf_esi = scp->sc_esi; | |||||
regs->tf_edi = scp->sc_edi; | |||||
regs->tf_cs = scp->sc_cs; | |||||
regs->tf_ss = scp->sc_ss; | |||||
regs->tf_isp = scp->sc_isp; | |||||
regs->tf_ebp = scp->sc_fp; | |||||
regs->tf_esp = scp->sc_sp; | |||||
regs->tf_eip = scp->sc_pc; | |||||
regs->tf_eflags = eflags; | |||||
#if defined(COMPAT_43) | |||||
if (scp->sc_onstack & 1) | |||||
td->td_sigstk.ss_flags |= SS_ONSTACK; | |||||
else | |||||
td->td_sigstk.ss_flags &= ~SS_ONSTACK; | |||||
#endif | |||||
kern_sigprocmask(td, SIG_SETMASK, (sigset_t *)&scp->sc_mask, NULL, | |||||
SIGPROCMASK_OLD); | |||||
return (EJUSTRETURN); | |||||
} | |||||
#endif /* COMPAT_43 */ | |||||
#ifdef COMPAT_FREEBSD4 | |||||
/* | |||||
* MPSAFE | |||||
*/ | |||||
int | |||||
freebsd4_sigreturn(td, uap) | |||||
struct thread *td; | |||||
struct freebsd4_sigreturn_args /* { | |||||
const ucontext4 *sigcntxp; | |||||
} */ *uap; | |||||
{ | |||||
struct ucontext4 uc; | |||||
struct trapframe *regs; | |||||
struct ucontext4 *ucp; | |||||
int cs, eflags, error; | |||||
ksiginfo_t ksi; | |||||
error = copyin(uap->sigcntxp, &uc, sizeof(uc)); | |||||
if (error != 0) | |||||
return (error); | |||||
ucp = &uc; | |||||
regs = td->td_frame; | |||||
eflags = ucp->uc_mcontext.mc_eflags; | |||||
if (eflags & PSL_VM) { | |||||
struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; | |||||
struct vm86_kernel *vm86; | |||||
/* | |||||
* if pcb_ext == 0 or vm86_inited == 0, the user hasn't | |||||
* set up the vm86 area, and we can't enter vm86 mode. | |||||
*/ | |||||
if (td->td_pcb->pcb_ext == 0) | |||||
return (EINVAL); | |||||
vm86 = &td->td_pcb->pcb_ext->ext_vm86; | |||||
if (vm86->vm86_inited == 0) | |||||
return (EINVAL); | |||||
/* Go back to user mode if both flags are set. */ | |||||
if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) { | |||||
ksiginfo_init_trap(&ksi); | |||||
ksi.ksi_signo = SIGBUS; | |||||
ksi.ksi_code = BUS_OBJERR; | |||||
ksi.ksi_addr = (void *)regs->tf_eip; | |||||
trapsignal(td, &ksi); | |||||
} | |||||
if (vm86->vm86_has_vme) { | |||||
eflags = (tf->tf_eflags & ~VME_USERCHANGE) | | |||||
(eflags & VME_USERCHANGE) | PSL_VM; | |||||
} else { | |||||
vm86->vm86_eflags = eflags; /* save VIF, VIP */ | |||||
eflags = (tf->tf_eflags & ~VM_USERCHANGE) | | |||||
(eflags & VM_USERCHANGE) | PSL_VM; | |||||
} | |||||
bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe)); | |||||
tf->tf_eflags = eflags; | |||||
tf->tf_vm86_ds = tf->tf_ds; | |||||
tf->tf_vm86_es = tf->tf_es; | |||||
tf->tf_vm86_fs = tf->tf_fs; | |||||
tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; | |||||
tf->tf_ds = _udatasel; | |||||
tf->tf_es = _udatasel; | |||||
tf->tf_fs = _udatasel; | |||||
} else { | |||||
/* | |||||
* Don't allow users to change privileged or reserved flags. | |||||
*/ | |||||
if (!EFL_SECURE(eflags, regs->tf_eflags)) { | |||||
uprintf("pid %d (%s): freebsd4_sigreturn eflags = 0x%x\n", | |||||
td->td_proc->p_pid, td->td_name, eflags); | |||||
return (EINVAL); | |||||
} | |||||
/* | |||||
* Don't allow users to load a valid privileged %cs. Let the | |||||
* hardware check for invalid selectors, excess privilege in | |||||
* other selectors, invalid %eip's and invalid %esp's. | |||||
*/ | |||||
cs = ucp->uc_mcontext.mc_cs; | |||||
if (!CS_SECURE(cs)) { | |||||
uprintf("pid %d (%s): freebsd4_sigreturn cs = 0x%x\n", | |||||
td->td_proc->p_pid, td->td_name, cs); | |||||
ksiginfo_init_trap(&ksi); | |||||
ksi.ksi_signo = SIGBUS; | |||||
ksi.ksi_code = BUS_OBJERR; | |||||
ksi.ksi_trapno = T_PROTFLT; | |||||
ksi.ksi_addr = (void *)regs->tf_eip; | |||||
trapsignal(td, &ksi); | |||||
return (EINVAL); | |||||
} | |||||
bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs)); | |||||
} | |||||
#if defined(COMPAT_43) | |||||
if (ucp->uc_mcontext.mc_onstack & 1) | |||||
td->td_sigstk.ss_flags |= SS_ONSTACK; | |||||
else | |||||
td->td_sigstk.ss_flags &= ~SS_ONSTACK; | |||||
#endif | |||||
kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0); | |||||
return (EJUSTRETURN); | |||||
} | |||||
#endif /* COMPAT_FREEBSD4 */ | |||||
/* | |||||
* MPSAFE | |||||
*/ | |||||
int | |||||
sys_sigreturn(td, uap) | |||||
struct thread *td; | |||||
struct sigreturn_args /* { | |||||
const struct __ucontext *sigcntxp; | |||||
} */ *uap; | |||||
{ | |||||
ucontext_t uc; | |||||
struct proc *p; | |||||
struct trapframe *regs; | |||||
ucontext_t *ucp; | |||||
char *xfpustate; | |||||
size_t xfpustate_len; | |||||
int cs, eflags, error, ret; | |||||
ksiginfo_t ksi; | |||||
p = td->td_proc; | |||||
error = copyin(uap->sigcntxp, &uc, sizeof(uc)); | |||||
if (error != 0) | |||||
return (error); | |||||
ucp = &uc; | |||||
if ((ucp->uc_mcontext.mc_flags & ~_MC_FLAG_MASK) != 0) { | |||||
uprintf("pid %d (%s): sigreturn mc_flags %x\n", p->p_pid, | |||||
td->td_name, ucp->uc_mcontext.mc_flags); | |||||
return (EINVAL); | |||||
} | |||||
regs = td->td_frame; | |||||
eflags = ucp->uc_mcontext.mc_eflags; | |||||
if (eflags & PSL_VM) { | |||||
struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; | |||||
struct vm86_kernel *vm86; | |||||
/* | |||||
* if pcb_ext == 0 or vm86_inited == 0, the user hasn't | |||||
* set up the vm86 area, and we can't enter vm86 mode. | |||||
*/ | |||||
if (td->td_pcb->pcb_ext == 0) | |||||
return (EINVAL); | |||||
vm86 = &td->td_pcb->pcb_ext->ext_vm86; | |||||
if (vm86->vm86_inited == 0) | |||||
return (EINVAL); | |||||
/* Go back to user mode if both flags are set. */ | |||||
if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) { | |||||
ksiginfo_init_trap(&ksi); | |||||
ksi.ksi_signo = SIGBUS; | |||||
ksi.ksi_code = BUS_OBJERR; | |||||
ksi.ksi_addr = (void *)regs->tf_eip; | |||||
trapsignal(td, &ksi); | |||||
} | |||||
if (vm86->vm86_has_vme) { | |||||
eflags = (tf->tf_eflags & ~VME_USERCHANGE) | | |||||
(eflags & VME_USERCHANGE) | PSL_VM; | |||||
} else { | |||||
vm86->vm86_eflags = eflags; /* save VIF, VIP */ | |||||
eflags = (tf->tf_eflags & ~VM_USERCHANGE) | | |||||
(eflags & VM_USERCHANGE) | PSL_VM; | |||||
} | |||||
bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe)); | |||||
tf->tf_eflags = eflags; | |||||
tf->tf_vm86_ds = tf->tf_ds; | |||||
tf->tf_vm86_es = tf->tf_es; | |||||
tf->tf_vm86_fs = tf->tf_fs; | |||||
tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; | |||||
tf->tf_ds = _udatasel; | |||||
tf->tf_es = _udatasel; | |||||
tf->tf_fs = _udatasel; | |||||
} else { | |||||
/* | |||||
* Don't allow users to change privileged or reserved flags. | |||||
*/ | |||||
if (!EFL_SECURE(eflags, regs->tf_eflags)) { | |||||
uprintf("pid %d (%s): sigreturn eflags = 0x%x\n", | |||||
td->td_proc->p_pid, td->td_name, eflags); | |||||
return (EINVAL); | |||||
} | |||||
/* | |||||
* Don't allow users to load a valid privileged %cs. Let the | |||||
* hardware check for invalid selectors, excess privilege in | |||||
* other selectors, invalid %eip's and invalid %esp's. | |||||
*/ | |||||
cs = ucp->uc_mcontext.mc_cs; | |||||
if (!CS_SECURE(cs)) { | |||||
uprintf("pid %d (%s): sigreturn cs = 0x%x\n", | |||||
td->td_proc->p_pid, td->td_name, cs); | |||||
ksiginfo_init_trap(&ksi); | |||||
ksi.ksi_signo = SIGBUS; | |||||
ksi.ksi_code = BUS_OBJERR; | |||||
ksi.ksi_trapno = T_PROTFLT; | |||||
ksi.ksi_addr = (void *)regs->tf_eip; | |||||
trapsignal(td, &ksi); | |||||
return (EINVAL); | |||||
} | |||||
if ((uc.uc_mcontext.mc_flags & _MC_HASFPXSTATE) != 0) { | |||||
xfpustate_len = uc.uc_mcontext.mc_xfpustate_len; | |||||
if (xfpustate_len > cpu_max_ext_state_size - | |||||
sizeof(union savefpu)) { | |||||
uprintf( | |||||
"pid %d (%s): sigreturn xfpusave_len = 0x%zx\n", | |||||
p->p_pid, td->td_name, xfpustate_len); | |||||
return (EINVAL); | |||||
} | |||||
xfpustate = __builtin_alloca(xfpustate_len); | |||||
error = copyin((const void *)uc.uc_mcontext.mc_xfpustate, | |||||
xfpustate, xfpustate_len); | |||||
if (error != 0) { | |||||
uprintf( | |||||
"pid %d (%s): sigreturn copying xfpustate failed\n", | |||||
p->p_pid, td->td_name); | |||||
return (error); | |||||
} | |||||
} else { | |||||
xfpustate = NULL; | |||||
xfpustate_len = 0; | |||||
} | |||||
ret = set_fpcontext(td, &ucp->uc_mcontext, xfpustate, | |||||
xfpustate_len); | |||||
if (ret != 0) | |||||
return (ret); | |||||
bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs)); | |||||
} | |||||
#if defined(COMPAT_43) | |||||
if (ucp->uc_mcontext.mc_onstack & 1) | |||||
td->td_sigstk.ss_flags |= SS_ONSTACK; | |||||
else | |||||
td->td_sigstk.ss_flags &= ~SS_ONSTACK; | |||||
#endif | |||||
kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0); | |||||
return (EJUSTRETURN); | |||||
} | |||||
#ifdef COMPAT_43 | |||||
static void | |||||
setup_priv_lcall_gate(struct proc *p) | |||||
{ | |||||
struct i386_ldt_args uap; | |||||
union descriptor desc; | |||||
u_int lcall_addr; | |||||
bzero(&uap, sizeof(uap)); | |||||
uap.start = 0; | |||||
uap.num = 1; | |||||
lcall_addr = p->p_sysent->sv_psstrings - sz_lcall_tramp; | |||||
bzero(&desc, sizeof(desc)); | |||||
desc.sd.sd_type = SDT_MEMERA; | |||||
desc.sd.sd_dpl = SEL_UPL; | |||||
desc.sd.sd_p = 1; | |||||
desc.sd.sd_def32 = 1; | |||||
desc.sd.sd_gran = 1; | |||||
desc.sd.sd_lolimit = 0xffff; | |||||
desc.sd.sd_hilimit = 0xf; | |||||
desc.sd.sd_lobase = lcall_addr; | |||||
desc.sd.sd_hibase = lcall_addr >> 24; | |||||
i386_set_ldt(curthread, &uap, &desc); | |||||
} | |||||
#endif | |||||
/* | |||||
* Reset the hardware debug registers if they were in use. | |||||
* They won't have any meaning for the newly exec'd process. | |||||
*/ | |||||
void | |||||
x86_clear_dbregs(struct pcb *pcb) | |||||
{ | |||||
if ((pcb->pcb_flags & PCB_DBREGS) == 0) | |||||
return; | |||||
pcb->pcb_dr0 = 0; | |||||
pcb->pcb_dr1 = 0; | |||||
pcb->pcb_dr2 = 0; | |||||
pcb->pcb_dr3 = 0; | |||||
pcb->pcb_dr6 = 0; | |||||
pcb->pcb_dr7 = 0; | |||||
if (pcb == curpcb) { | |||||
/* | |||||
* Clear the debug registers on the running CPU, | |||||
* otherwise they will end up affecting the next | |||||
* process we switch to. | |||||
*/ | |||||
reset_dbregs(); | |||||
} | |||||
pcb->pcb_flags &= ~PCB_DBREGS; | |||||
} | |||||
/* | |||||
* Reset registers to default values on exec. | |||||
*/ | |||||
void | |||||
exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack) | |||||
{ | |||||
struct trapframe *regs; | |||||
struct pcb *pcb; | |||||
register_t saved_eflags; | |||||
regs = td->td_frame; | |||||
pcb = td->td_pcb; | |||||
/* Reset pc->pcb_gs and %gs before possibly invalidating it. */ | |||||
pcb->pcb_gs = _udatasel; | |||||
load_gs(_udatasel); | |||||
mtx_lock_spin(&dt_lock); | |||||
if (td->td_proc->p_md.md_ldt != NULL) | |||||
user_ldt_free(td); | |||||
else | |||||
mtx_unlock_spin(&dt_lock); | |||||
#ifdef COMPAT_43 | |||||
if (td->td_proc->p_sysent->sv_psstrings != | |||||
elf32_freebsd_sysvec.sv_psstrings) | |||||
setup_priv_lcall_gate(td->td_proc); | |||||
#endif | |||||
/* | |||||
* Reset the fs and gs bases. The values from the old address | |||||
* space do not make sense for the new program. In particular, | |||||
* gsbase might be the TLS base for the old program but the new | |||||
* program has no TLS now. | |||||
*/ | |||||
set_fsbase(td, 0); | |||||
set_gsbase(td, 0); | |||||
/* Make sure edx is 0x0 on entry. Linux binaries depend on it. */ | |||||
saved_eflags = regs->tf_eflags & PSL_T; | |||||
bzero((char *)regs, sizeof(struct trapframe)); | |||||
regs->tf_eip = imgp->entry_addr; | |||||
regs->tf_esp = stack; | |||||
regs->tf_eflags = PSL_USER | saved_eflags; | |||||
regs->tf_ss = _udatasel; | |||||
regs->tf_ds = _udatasel; | |||||
regs->tf_es = _udatasel; | |||||
regs->tf_fs = _udatasel; | |||||
regs->tf_cs = _ucodesel; | |||||
/* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */ | |||||
regs->tf_ebx = (register_t)imgp->ps_strings; | |||||
x86_clear_dbregs(pcb); | |||||
pcb->pcb_initial_npxcw = __INITIAL_NPXCW__; | |||||
/* | |||||
* Drop the FP state if we hold it, so that the process gets a | |||||
* clean FP state if it uses the FPU again. | |||||
*/ | |||||
fpstate_drop(td); | |||||
} | |||||
void | |||||
cpu_setregs(void) | cpu_setregs(void) | ||||
{ | { | ||||
unsigned int cr0; | unsigned int cr0; | ||||
cr0 = rcr0(); | cr0 = rcr0(); | ||||
/* | /* | ||||
* CR0_MP, CR0_NE and CR0_TS are set for NPX (FPU) support: | * CR0_MP, CR0_NE and CR0_TS are set for NPX (FPU) support: | ||||
▲ Show 20 Lines • Show All 1,530 Lines • ▼ Show 20 Lines | makectx(struct trapframe *tf, struct pcb *pcb) | ||||
pcb->pcb_edi = tf->tf_edi; | pcb->pcb_edi = tf->tf_edi; | ||||
pcb->pcb_esi = tf->tf_esi; | pcb->pcb_esi = tf->tf_esi; | ||||
pcb->pcb_ebp = tf->tf_ebp; | pcb->pcb_ebp = tf->tf_ebp; | ||||
pcb->pcb_ebx = tf->tf_ebx; | pcb->pcb_ebx = tf->tf_ebx; | ||||
pcb->pcb_eip = tf->tf_eip; | pcb->pcb_eip = tf->tf_eip; | ||||
pcb->pcb_esp = (ISPL(tf->tf_cs)) ? tf->tf_esp : (int)(tf + 1) - 8; | pcb->pcb_esp = (ISPL(tf->tf_cs)) ? tf->tf_esp : (int)(tf + 1) - 8; | ||||
pcb->pcb_gs = rgs(); | pcb->pcb_gs = rgs(); | ||||
} | |||||
int | |||||
ptrace_set_pc(struct thread *td, u_long addr) | |||||
{ | |||||
td->td_frame->tf_eip = addr; | |||||
return (0); | |||||
} | |||||
int | |||||
ptrace_single_step(struct thread *td) | |||||
{ | |||||
PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); | |||||
if ((td->td_frame->tf_eflags & PSL_T) == 0) { | |||||
td->td_frame->tf_eflags |= PSL_T; | |||||
td->td_dbgflags |= TDB_STEP; | |||||
} | |||||
return (0); | |||||
} | |||||
int | |||||
ptrace_clear_single_step(struct thread *td) | |||||
{ | |||||
PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); | |||||
td->td_frame->tf_eflags &= ~PSL_T; | |||||
td->td_dbgflags &= ~TDB_STEP; | |||||
return (0); | |||||
} | |||||
int | |||||
fill_regs(struct thread *td, struct reg *regs) | |||||
{ | |||||
struct pcb *pcb; | |||||
struct trapframe *tp; | |||||
tp = td->td_frame; | |||||
pcb = td->td_pcb; | |||||
regs->r_gs = pcb->pcb_gs; | |||||
return (fill_frame_regs(tp, regs)); | |||||
} | |||||
int | |||||
fill_frame_regs(struct trapframe *tp, struct reg *regs) | |||||
{ | |||||
regs->r_fs = tp->tf_fs; | |||||
regs->r_es = tp->tf_es; | |||||
regs->r_ds = tp->tf_ds; | |||||
regs->r_edi = tp->tf_edi; | |||||
regs->r_esi = tp->tf_esi; | |||||
regs->r_ebp = tp->tf_ebp; | |||||
regs->r_ebx = tp->tf_ebx; | |||||
regs->r_edx = tp->tf_edx; | |||||
regs->r_ecx = tp->tf_ecx; | |||||
regs->r_eax = tp->tf_eax; | |||||
regs->r_eip = tp->tf_eip; | |||||
regs->r_cs = tp->tf_cs; | |||||
regs->r_eflags = tp->tf_eflags; | |||||
regs->r_esp = tp->tf_esp; | |||||
regs->r_ss = tp->tf_ss; | |||||
regs->r_err = 0; | |||||
regs->r_trapno = 0; | |||||
return (0); | |||||
} | |||||
int | |||||
set_regs(struct thread *td, struct reg *regs) | |||||
{ | |||||
struct pcb *pcb; | |||||
struct trapframe *tp; | |||||
tp = td->td_frame; | |||||
if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) || | |||||
!CS_SECURE(regs->r_cs)) | |||||
return (EINVAL); | |||||
pcb = td->td_pcb; | |||||
tp->tf_fs = regs->r_fs; | |||||
tp->tf_es = regs->r_es; | |||||
tp->tf_ds = regs->r_ds; | |||||
tp->tf_edi = regs->r_edi; | |||||
tp->tf_esi = regs->r_esi; | |||||
tp->tf_ebp = regs->r_ebp; | |||||
tp->tf_ebx = regs->r_ebx; | |||||
tp->tf_edx = regs->r_edx; | |||||
tp->tf_ecx = regs->r_ecx; | |||||
tp->tf_eax = regs->r_eax; | |||||
tp->tf_eip = regs->r_eip; | |||||
tp->tf_cs = regs->r_cs; | |||||
tp->tf_eflags = regs->r_eflags; | |||||
tp->tf_esp = regs->r_esp; | |||||
tp->tf_ss = regs->r_ss; | |||||
pcb->pcb_gs = regs->r_gs; | |||||
return (0); | |||||
} | |||||
int | |||||
fill_fpregs(struct thread *td, struct fpreg *fpregs) | |||||
{ | |||||
KASSERT(td == curthread || TD_IS_SUSPENDED(td) || | |||||
P_SHOULDSTOP(td->td_proc), | |||||
("not suspended thread %p", td)); | |||||
npxgetregs(td); | |||||
if (cpu_fxsr) | |||||
npx_fill_fpregs_xmm(&get_pcb_user_save_td(td)->sv_xmm, | |||||
(struct save87 *)fpregs); | |||||
else | |||||
bcopy(&get_pcb_user_save_td(td)->sv_87, fpregs, | |||||
sizeof(*fpregs)); | |||||
return (0); | |||||
} | |||||
int | |||||
set_fpregs(struct thread *td, struct fpreg *fpregs) | |||||
{ | |||||
critical_enter(); | |||||
if (cpu_fxsr) | |||||
npx_set_fpregs_xmm((struct save87 *)fpregs, | |||||
&get_pcb_user_save_td(td)->sv_xmm); | |||||
else | |||||
bcopy(fpregs, &get_pcb_user_save_td(td)->sv_87, | |||||
sizeof(*fpregs)); | |||||
npxuserinited(td); | |||||
critical_exit(); | |||||
return (0); | |||||
} | |||||
/* | |||||
* Get machine context. | |||||
*/ | |||||
int | |||||
get_mcontext(struct thread *td, mcontext_t *mcp, int flags) | |||||
{ | |||||
struct trapframe *tp; | |||||
struct segment_descriptor *sdp; | |||||
tp = td->td_frame; | |||||
PROC_LOCK(curthread->td_proc); | |||||
mcp->mc_onstack = sigonstack(tp->tf_esp); | |||||
PROC_UNLOCK(curthread->td_proc); | |||||
mcp->mc_gs = td->td_pcb->pcb_gs; | |||||
mcp->mc_fs = tp->tf_fs; | |||||
mcp->mc_es = tp->tf_es; | |||||
mcp->mc_ds = tp->tf_ds; | |||||
mcp->mc_edi = tp->tf_edi; | |||||
mcp->mc_esi = tp->tf_esi; | |||||
mcp->mc_ebp = tp->tf_ebp; | |||||
mcp->mc_isp = tp->tf_isp; | |||||
mcp->mc_eflags = tp->tf_eflags; | |||||
if (flags & GET_MC_CLEAR_RET) { | |||||
mcp->mc_eax = 0; | |||||
mcp->mc_edx = 0; | |||||
mcp->mc_eflags &= ~PSL_C; | |||||
} else { | |||||
mcp->mc_eax = tp->tf_eax; | |||||
mcp->mc_edx = tp->tf_edx; | |||||
} | |||||
mcp->mc_ebx = tp->tf_ebx; | |||||
mcp->mc_ecx = tp->tf_ecx; | |||||
mcp->mc_eip = tp->tf_eip; | |||||
mcp->mc_cs = tp->tf_cs; | |||||
mcp->mc_esp = tp->tf_esp; | |||||
mcp->mc_ss = tp->tf_ss; | |||||
mcp->mc_len = sizeof(*mcp); | |||||
get_fpcontext(td, mcp, NULL, 0); | |||||
sdp = &td->td_pcb->pcb_fsd; | |||||
mcp->mc_fsbase = sdp->sd_hibase << 24 | sdp->sd_lobase; | |||||
sdp = &td->td_pcb->pcb_gsd; | |||||
mcp->mc_gsbase = sdp->sd_hibase << 24 | sdp->sd_lobase; | |||||
mcp->mc_flags = 0; | |||||
mcp->mc_xfpustate = 0; | |||||
mcp->mc_xfpustate_len = 0; | |||||
bzero(mcp->mc_spare2, sizeof(mcp->mc_spare2)); | |||||
return (0); | |||||
} | |||||
/* | |||||
* Set machine context. | |||||
* | |||||
* However, we don't set any but the user modifiable flags, and we won't | |||||
* touch the cs selector. | |||||
*/ | |||||
int | |||||
set_mcontext(struct thread *td, mcontext_t *mcp) | |||||
{ | |||||
struct trapframe *tp; | |||||
char *xfpustate; | |||||
int eflags, ret; | |||||
tp = td->td_frame; | |||||
if (mcp->mc_len != sizeof(*mcp) || | |||||
(mcp->mc_flags & ~_MC_FLAG_MASK) != 0) | |||||
return (EINVAL); | |||||
eflags = (mcp->mc_eflags & PSL_USERCHANGE) | | |||||
(tp->tf_eflags & ~PSL_USERCHANGE); | |||||
if (mcp->mc_flags & _MC_HASFPXSTATE) { | |||||
if (mcp->mc_xfpustate_len > cpu_max_ext_state_size - | |||||
sizeof(union savefpu)) | |||||
return (EINVAL); | |||||
xfpustate = __builtin_alloca(mcp->mc_xfpustate_len); | |||||
ret = copyin((void *)mcp->mc_xfpustate, xfpustate, | |||||
mcp->mc_xfpustate_len); | |||||
if (ret != 0) | |||||
return (ret); | |||||
} else | |||||
xfpustate = NULL; | |||||
ret = set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len); | |||||
if (ret != 0) | |||||
return (ret); | |||||
tp->tf_fs = mcp->mc_fs; | |||||
tp->tf_es = mcp->mc_es; | |||||
tp->tf_ds = mcp->mc_ds; | |||||
tp->tf_edi = mcp->mc_edi; | |||||
tp->tf_esi = mcp->mc_esi; | |||||
tp->tf_ebp = mcp->mc_ebp; | |||||
tp->tf_ebx = mcp->mc_ebx; | |||||
tp->tf_edx = mcp->mc_edx; | |||||
tp->tf_ecx = mcp->mc_ecx; | |||||
tp->tf_eax = mcp->mc_eax; | |||||
tp->tf_eip = mcp->mc_eip; | |||||
tp->tf_eflags = eflags; | |||||
tp->tf_esp = mcp->mc_esp; | |||||
tp->tf_ss = mcp->mc_ss; | |||||
td->td_pcb->pcb_gs = mcp->mc_gs; | |||||
return (0); | |||||
} | |||||
static void | |||||
get_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpusave, | |||||
size_t xfpusave_len) | |||||
{ | |||||
size_t max_len, len; | |||||
mcp->mc_ownedfp = npxgetregs(td); | |||||
bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate[0], | |||||
sizeof(mcp->mc_fpstate)); | |||||
mcp->mc_fpformat = npxformat(); | |||||
if (!use_xsave || xfpusave_len == 0) | |||||
return; | |||||
max_len = cpu_max_ext_state_size - sizeof(union savefpu); | |||||
len = xfpusave_len; | |||||
if (len > max_len) { | |||||
len = max_len; | |||||
bzero(xfpusave + max_len, len - max_len); | |||||
} | |||||
mcp->mc_flags |= _MC_HASFPXSTATE; | |||||
mcp->mc_xfpustate_len = len; | |||||
bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len); | |||||
} | |||||
static int | |||||
set_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpustate, | |||||
size_t xfpustate_len) | |||||
{ | |||||
int error; | |||||
if (mcp->mc_fpformat == _MC_FPFMT_NODEV) | |||||
return (0); | |||||
else if (mcp->mc_fpformat != _MC_FPFMT_387 && | |||||
mcp->mc_fpformat != _MC_FPFMT_XMM) | |||||
return (EINVAL); | |||||
else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE) { | |||||
/* We don't care what state is left in the FPU or PCB. */ | |||||
fpstate_drop(td); | |||||
error = 0; | |||||
} else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU || | |||||
mcp->mc_ownedfp == _MC_FPOWNED_PCB) { | |||||
error = npxsetregs(td, (union savefpu *)&mcp->mc_fpstate, | |||||
xfpustate, xfpustate_len); | |||||
} else | |||||
return (EINVAL); | |||||
return (error); | |||||
} | |||||
static void | |||||
fpstate_drop(struct thread *td) | |||||
{ | |||||
KASSERT(PCB_USER_FPU(td->td_pcb), ("fpstate_drop: kernel-owned fpu")); | |||||
critical_enter(); | |||||
if (PCPU_GET(fpcurthread) == td) | |||||
npxdrop(); | |||||
/* | |||||
* XXX force a full drop of the npx. The above only drops it if we | |||||
* owned it. npxgetregs() has the same bug in the !cpu_fxsr case. | |||||
* | |||||
* XXX I don't much like npxgetregs()'s semantics of doing a full | |||||
* drop. Dropping only to the pcb matches fnsave's behaviour. | |||||
* We only need to drop to !PCB_INITDONE in sendsig(). But | |||||
* sendsig() is the only caller of npxgetregs()... perhaps we just | |||||
* have too many layers. | |||||
*/ | |||||
curthread->td_pcb->pcb_flags &= ~(PCB_NPXINITDONE | | |||||
PCB_NPXUSERINITDONE); | |||||
critical_exit(); | |||||
} | |||||
int | |||||
fill_dbregs(struct thread *td, struct dbreg *dbregs) | |||||
{ | |||||
struct pcb *pcb; | |||||
if (td == NULL) { | |||||
dbregs->dr[0] = rdr0(); | |||||
dbregs->dr[1] = rdr1(); | |||||
dbregs->dr[2] = rdr2(); | |||||
dbregs->dr[3] = rdr3(); | |||||
dbregs->dr[6] = rdr6(); | |||||
dbregs->dr[7] = rdr7(); | |||||
} else { | |||||
pcb = td->td_pcb; | |||||
dbregs->dr[0] = pcb->pcb_dr0; | |||||
dbregs->dr[1] = pcb->pcb_dr1; | |||||
dbregs->dr[2] = pcb->pcb_dr2; | |||||
dbregs->dr[3] = pcb->pcb_dr3; | |||||
dbregs->dr[6] = pcb->pcb_dr6; | |||||
dbregs->dr[7] = pcb->pcb_dr7; | |||||
} | |||||
dbregs->dr[4] = 0; | |||||
dbregs->dr[5] = 0; | |||||
return (0); | |||||
} | |||||
int | |||||
set_dbregs(struct thread *td, struct dbreg *dbregs) | |||||
{ | |||||
struct pcb *pcb; | |||||
int i; | |||||
if (td == NULL) { | |||||
load_dr0(dbregs->dr[0]); | |||||
load_dr1(dbregs->dr[1]); | |||||
load_dr2(dbregs->dr[2]); | |||||
load_dr3(dbregs->dr[3]); | |||||
load_dr6(dbregs->dr[6]); | |||||
load_dr7(dbregs->dr[7]); | |||||
} else { | |||||
/* | |||||
* Don't let an illegal value for dr7 get set. Specifically, | |||||
* check for undefined settings. Setting these bit patterns | |||||
* result in undefined behaviour and can lead to an unexpected | |||||
* TRCTRAP. | |||||
*/ | |||||
for (i = 0; i < 4; i++) { | |||||
if (DBREG_DR7_ACCESS(dbregs->dr[7], i) == 0x02) | |||||
return (EINVAL); | |||||
if (DBREG_DR7_LEN(dbregs->dr[7], i) == 0x02) | |||||
return (EINVAL); | |||||
} | |||||
pcb = td->td_pcb; | |||||
/* | |||||
* Don't let a process set a breakpoint that is not within the | |||||
* process's address space. If a process could do this, it | |||||
* could halt the system by setting a breakpoint in the kernel | |||||
* (if ddb was enabled). Thus, we need to check to make sure | |||||
* that no breakpoints are being enabled for addresses outside | |||||
* process's address space. | |||||
* | |||||
* XXX - what about when the watched area of the user's | |||||
* address space is written into from within the kernel | |||||
* ... wouldn't that still cause a breakpoint to be generated | |||||
* from within kernel mode? | |||||
*/ | |||||
if (DBREG_DR7_ENABLED(dbregs->dr[7], 0)) { | |||||
/* dr0 is enabled */ | |||||
if (dbregs->dr[0] >= VM_MAXUSER_ADDRESS) | |||||
return (EINVAL); | |||||
} | |||||
if (DBREG_DR7_ENABLED(dbregs->dr[7], 1)) { | |||||
/* dr1 is enabled */ | |||||
if (dbregs->dr[1] >= VM_MAXUSER_ADDRESS) | |||||
return (EINVAL); | |||||
} | |||||
if (DBREG_DR7_ENABLED(dbregs->dr[7], 2)) { | |||||
/* dr2 is enabled */ | |||||
if (dbregs->dr[2] >= VM_MAXUSER_ADDRESS) | |||||
return (EINVAL); | |||||
} | |||||
if (DBREG_DR7_ENABLED(dbregs->dr[7], 3)) { | |||||
/* dr3 is enabled */ | |||||
if (dbregs->dr[3] >= VM_MAXUSER_ADDRESS) | |||||
return (EINVAL); | |||||
} | |||||
pcb->pcb_dr0 = dbregs->dr[0]; | |||||
pcb->pcb_dr1 = dbregs->dr[1]; | |||||
pcb->pcb_dr2 = dbregs->dr[2]; | |||||
pcb->pcb_dr3 = dbregs->dr[3]; | |||||
pcb->pcb_dr6 = dbregs->dr[6]; | |||||
pcb->pcb_dr7 = dbregs->dr[7]; | |||||
pcb->pcb_flags |= PCB_DBREGS; | |||||
} | |||||
return (0); | |||||
} | |||||
/* | |||||
* Return > 0 if a hardware breakpoint has been hit, and the | |||||
* breakpoint was in user space. Return 0, otherwise. | |||||
*/ | |||||
int | |||||
user_dbreg_trap(register_t dr6) | |||||
{ | |||||
u_int32_t dr7; | |||||
u_int32_t bp; /* breakpoint bits extracted from dr6 */ | |||||
int nbp; /* number of breakpoints that triggered */ | |||||
caddr_t addr[4]; /* breakpoint addresses */ | |||||
int i; | |||||
bp = dr6 & DBREG_DR6_BMASK; | |||||
if (bp == 0) { | |||||
/* | |||||
* None of the breakpoint bits are set meaning this | |||||
* trap was not caused by any of the debug registers | |||||
*/ | |||||
return 0; | |||||
} | |||||
dr7 = rdr7(); | |||||
if ((dr7 & 0x000000ff) == 0) { | |||||
/* | |||||
* all GE and LE bits in the dr7 register are zero, | |||||
* thus the trap couldn't have been caused by the | |||||
* hardware debug registers | |||||
*/ | |||||
return 0; | |||||
} | |||||
nbp = 0; | |||||
/* | |||||
* at least one of the breakpoints were hit, check to see | |||||
* which ones and if any of them are user space addresses | |||||
*/ | |||||
if (bp & 0x01) { | |||||
addr[nbp++] = (caddr_t)rdr0(); | |||||
} | |||||
if (bp & 0x02) { | |||||
addr[nbp++] = (caddr_t)rdr1(); | |||||
} | |||||
if (bp & 0x04) { | |||||
addr[nbp++] = (caddr_t)rdr2(); | |||||
} | |||||
if (bp & 0x08) { | |||||
addr[nbp++] = (caddr_t)rdr3(); | |||||
} | |||||
for (i = 0; i < nbp; i++) { | |||||
if (addr[i] < (caddr_t)VM_MAXUSER_ADDRESS) { | |||||
/* | |||||
* addr[i] is in user space | |||||
*/ | |||||
return nbp; | |||||
} | |||||
} | |||||
/* | |||||
* None of the breakpoints are in user space. | |||||
*/ | |||||
return 0; | |||||
} | } | ||||
#ifdef KDB | #ifdef KDB | ||||
/* | /* | ||||
* Provide inb() and outb() as functions. They are normally only available as | * Provide inb() and outb() as functions. They are normally only available as | ||||
* inline functions, thus cannot be called from the debugger. | * inline functions, thus cannot be called from the debugger. | ||||
*/ | */ | ||||
Show All 18 Lines |
These got lost, I assume deliberate because of where our SMP support is these days :)