Implement 32 bit getcontext/setcontext/swapcontext on amd64. I've added
stubs for ia64 to keep it compiling. These are used by 32 bit apps such as gdb.
This commit is contained in:
parent
55b4a5ae0d
commit
add121a476
@ -92,38 +92,14 @@ extern int _ucode32sel, _udatasel;
|
||||
static void
|
||||
ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp)
|
||||
{
|
||||
struct savefpu *addr;
|
||||
|
||||
/*
|
||||
* XXX mc_fpstate might be misaligned, since its declaration is not
|
||||
* unportabilized using __attribute__((aligned(16))) like the
|
||||
* declaration of struct savemm, and anyway, alignment doesn't work
|
||||
* for auto variables since we don't use gcc's pessimal stack
|
||||
* alignment. Work around this by abusing the spare fields after
|
||||
* mcp->mc_fpstate.
|
||||
*
|
||||
* XXX unpessimize most cases by only aligning when fxsave might be
|
||||
* called, although this requires knowing too much about
|
||||
* fpugetregs()'s internals.
|
||||
*/
|
||||
addr = (struct savefpu *)&mcp->mc_fpstate;
|
||||
if (td == PCPU_GET(fpcurthread) && ((uintptr_t)(void *)addr & 0xF)) {
|
||||
do
|
||||
addr = (void *)((char *)addr + 4);
|
||||
while ((uintptr_t)(void *)addr & 0xF);
|
||||
}
|
||||
mcp->mc_ownedfp = fpugetregs(td, addr);
|
||||
if (addr != (struct savefpu *)&mcp->mc_fpstate) {
|
||||
bcopy(addr, &mcp->mc_fpstate, sizeof(mcp->mc_fpstate));
|
||||
bzero(&mcp->mc_spare2, sizeof(mcp->mc_spare2));
|
||||
}
|
||||
mcp->mc_ownedfp = fpugetregs(td, (struct savefpu *)&mcp->mc_fpstate);
|
||||
mcp->mc_fpformat = fpuformat();
|
||||
}
|
||||
|
||||
static int
|
||||
ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp)
|
||||
{
|
||||
struct savefpu *addr;
|
||||
|
||||
if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
|
||||
return (0);
|
||||
@ -134,30 +110,179 @@ ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp)
|
||||
fpstate_drop(td);
|
||||
else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
|
||||
mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
|
||||
/* XXX align as above. */
|
||||
addr = (struct savefpu *)&mcp->mc_fpstate;
|
||||
if (td == PCPU_GET(fpcurthread) &&
|
||||
((uintptr_t)(void *)addr & 0xF)) {
|
||||
do
|
||||
addr = (void *)((char *)addr + 4);
|
||||
while ((uintptr_t)(void *)addr & 0xF);
|
||||
bcopy(&mcp->mc_fpstate, addr, sizeof(mcp->mc_fpstate));
|
||||
}
|
||||
/*
|
||||
* XXX we violate the dubious requirement that fpusetregs()
|
||||
* be called with interrupts disabled.
|
||||
*/
|
||||
fpusetregs(td, addr);
|
||||
/*
|
||||
* Don't bother putting things back where they were in the
|
||||
* misaligned case, since we know that the caller won't use
|
||||
* them again.
|
||||
*/
|
||||
fpusetregs(td, (struct savefpu *)&mcp->mc_fpstate);
|
||||
} else
|
||||
return (EINVAL);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get machine context.
|
||||
*/
|
||||
static int
|
||||
ia32_get_mcontext(struct thread *td, struct ia32_mcontext *mcp, int flags)
|
||||
{
|
||||
struct trapframe *tp;
|
||||
|
||||
tp = td->td_frame;
|
||||
|
||||
PROC_LOCK(curthread->td_proc);
|
||||
mcp->mc_onstack = sigonstack(tp->tf_rsp);
|
||||
PROC_UNLOCK(curthread->td_proc);
|
||||
mcp->mc_gs = td->td_pcb->pcb_gs;
|
||||
mcp->mc_fs = td->td_pcb->pcb_fs;
|
||||
mcp->mc_es = td->td_pcb->pcb_es;
|
||||
mcp->mc_ds = td->td_pcb->pcb_ds;
|
||||
mcp->mc_edi = tp->tf_rdi;
|
||||
mcp->mc_esi = tp->tf_rsi;
|
||||
mcp->mc_ebp = tp->tf_rbp;
|
||||
mcp->mc_isp = tp->tf_rsp;
|
||||
if (flags & GET_MC_CLEAR_RET) {
|
||||
mcp->mc_eax = 0;
|
||||
mcp->mc_edx = 0;
|
||||
} else {
|
||||
mcp->mc_eax = tp->tf_rax;
|
||||
mcp->mc_edx = tp->tf_rdx;
|
||||
}
|
||||
mcp->mc_ebx = tp->tf_rbx;
|
||||
mcp->mc_ecx = tp->tf_rcx;
|
||||
mcp->mc_eip = tp->tf_rip;
|
||||
mcp->mc_cs = tp->tf_cs;
|
||||
mcp->mc_eflags = tp->tf_rflags;
|
||||
mcp->mc_esp = tp->tf_rsp;
|
||||
mcp->mc_ss = tp->tf_ss;
|
||||
mcp->mc_len = sizeof(*mcp);
|
||||
ia32_get_fpcontext(td, mcp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set machine context.
|
||||
*
|
||||
* However, we don't set any but the user modifiable flags, and we won't
|
||||
* touch the cs selector.
|
||||
*/
|
||||
static int
|
||||
ia32_set_mcontext(struct thread *td, const struct ia32_mcontext *mcp)
|
||||
{
|
||||
struct trapframe *tp;
|
||||
long rflags;
|
||||
int ret;
|
||||
|
||||
tp = td->td_frame;
|
||||
if (mcp->mc_len != sizeof(*mcp))
|
||||
return (EINVAL);
|
||||
rflags = (mcp->mc_eflags & PSL_USERCHANGE) |
|
||||
(tp->tf_rflags & ~PSL_USERCHANGE);
|
||||
ret = ia32_set_fpcontext(td, mcp);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
#if 0 /* XXX deal with load_fs() and friends */
|
||||
tp->tf_fs = mcp->mc_fs;
|
||||
tp->tf_es = mcp->mc_es;
|
||||
tp->tf_ds = mcp->mc_ds;
|
||||
#endif
|
||||
tp->tf_rdi = mcp->mc_edi;
|
||||
tp->tf_rsi = mcp->mc_esi;
|
||||
tp->tf_rbp = mcp->mc_ebp;
|
||||
tp->tf_rbx = mcp->mc_ebx;
|
||||
tp->tf_rdx = mcp->mc_edx;
|
||||
tp->tf_rcx = mcp->mc_ecx;
|
||||
tp->tf_rax = mcp->mc_eax;
|
||||
/* trapno, err */
|
||||
tp->tf_rip = mcp->mc_eip;
|
||||
tp->tf_rflags = rflags;
|
||||
tp->tf_rsp = mcp->mc_esp;
|
||||
tp->tf_ss = mcp->mc_ss;
|
||||
#if 0 /* XXX deal with load_gs() and friends */
|
||||
td->td_pcb->pcb_gs = mcp->mc_gs;
|
||||
#endif
|
||||
td->td_pcb->pcb_flags |= PCB_FULLCTX;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The first two fields of a ucontext_t are the signal mask and
|
||||
* the machine context. The next field is uc_link; we want to
|
||||
* avoid destroying the link when copying out contexts.
|
||||
*/
|
||||
#define UC_COPY_SIZE offsetof(struct ia32_ucontext, uc_link)
|
||||
|
||||
int
|
||||
freebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap)
|
||||
{
|
||||
struct ia32_ucontext uc;
|
||||
int ret;
|
||||
|
||||
if (uap->ucp == NULL)
|
||||
ret = EINVAL;
|
||||
else {
|
||||
ia32_get_mcontext(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
|
||||
PROC_LOCK(td->td_proc);
|
||||
uc.uc_sigmask = td->td_sigmask;
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
ret = copyout(&uc, uap->ucp, UC_COPY_SIZE);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap)
|
||||
{
|
||||
struct ia32_ucontext uc;
|
||||
int ret;
|
||||
|
||||
if (uap->ucp == NULL)
|
||||
ret = EINVAL;
|
||||
else {
|
||||
ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
|
||||
if (ret == 0) {
|
||||
ret = ia32_set_mcontext(td, &uc.uc_mcontext);
|
||||
if (ret == 0) {
|
||||
SIG_CANTMASK(uc.uc_sigmask);
|
||||
PROC_LOCK(td->td_proc);
|
||||
td->td_sigmask = uc.uc_sigmask;
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ret == 0 ? EJUSTRETURN : ret);
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap)
|
||||
{
|
||||
struct ia32_ucontext uc;
|
||||
int ret;
|
||||
|
||||
if (uap->oucp == NULL || uap->ucp == NULL)
|
||||
ret = EINVAL;
|
||||
else {
|
||||
ia32_get_mcontext(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
|
||||
PROC_LOCK(td->td_proc);
|
||||
uc.uc_sigmask = td->td_sigmask;
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
ret = copyout(&uc, uap->oucp, UC_COPY_SIZE);
|
||||
if (ret == 0) {
|
||||
ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
|
||||
if (ret == 0) {
|
||||
ret = ia32_set_mcontext(td, &uc.uc_mcontext);
|
||||
if (ret == 0) {
|
||||
SIG_CANTMASK(uc.uc_sigmask);
|
||||
PROC_LOCK(td->td_proc);
|
||||
td->td_sigmask = uc.uc_sigmask;
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ret == 0 ? EJUSTRETURN : ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an interrupt to process.
|
||||
*
|
||||
|
@ -693,12 +693,13 @@
|
||||
418 AUE_NULL UNIMPL __xstat
|
||||
419 AUE_NULL UNIMPL __xfstat
|
||||
420 AUE_NULL UNIMPL __xlstat
|
||||
; XXX implement
|
||||
421 AUE_NULL UNIMPL getcontext
|
||||
; XXX implement
|
||||
422 AUE_NULL UNIMPL setcontext
|
||||
; XXX implement
|
||||
423 AUE_NULL UNIMPL swapcontext
|
||||
421 AUE_NULL MSTD { int freebsd32_getcontext( \
|
||||
struct freebsd32_ucontext *ucp); }
|
||||
422 AUE_NULL MSTD { int freebsd32_setcontext( \
|
||||
const struct freebsd32_ucontext *ucp); }
|
||||
423 AUE_NULL MSTD { int freebsd32_swapcontext( \
|
||||
struct freebsd32_ucontext *oucp, \
|
||||
const struct freebsd32_ucontext *ucp); }
|
||||
424 AUE_NULL UNIMPL swapoff
|
||||
425 AUE_NULL UNIMPL __acl_get_link
|
||||
426 AUE_NULL UNIMPL __acl_set_link
|
||||
|
@ -263,3 +263,24 @@ ia32_savectx(struct pcb *pcb)
|
||||
pcb->pcb_ia32_fir = ia64_get_fir();
|
||||
pcb->pcb_ia32_fsr = ia64_get_fsr();
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap)
|
||||
{
|
||||
|
||||
return (nosys(td, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap)
|
||||
{
|
||||
|
||||
return (nosys(td, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap)
|
||||
{
|
||||
|
||||
return (nosys(td, NULL));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user