From add121a4767171fb1f5eb5de3b76086ee1ccc15d Mon Sep 17 00:00:00 2001 From: Peter Wemm Date: Tue, 27 Sep 2005 18:04:20 +0000 Subject: [PATCH] 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. --- sys/amd64/ia32/ia32_signal.c | 205 +++++++++++++++++++++------ sys/compat/freebsd32/syscalls.master | 13 +- sys/ia64/ia32/ia32_signal.c | 21 +++ 3 files changed, 193 insertions(+), 46 deletions(-) diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c index 58aeb3d4c74c..b5533b554b19 100644 --- a/sys/amd64/ia32/ia32_signal.c +++ b/sys/amd64/ia32/ia32_signal.c @@ -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. * diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 2a764bfb706b..8094be354223 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -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 diff --git a/sys/ia64/ia32/ia32_signal.c b/sys/ia64/ia32/ia32_signal.c index b001ae1c2bee..6725cb33f912 100644 --- a/sys/ia64/ia32/ia32_signal.c +++ b/sys/ia64/ia32/ia32_signal.c @@ -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)); +}