Page MenuHomeFreeBSD

D40444.id122902.diff
No OneTemporary

D40444.id122902.diff

diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c
--- a/sys/amd64/linux/linux_sysvec.c
+++ b/sys/amd64/linux/linux_sysvec.c
@@ -295,6 +295,58 @@
return (set_fpcontext(td, mcp, NULL, 0));
}
+static int
+linux_xrstor(struct thread *td, mcontext_t *mcp, struct l_sigcontext *sc)
+{
+ struct savefpu *svfp = (struct savefpu *)&mcp->mc_fpstate[0];
+ char *xfpustate;
+ struct proc *p;
+ int error, magic2;
+
+ p = td->td_proc;
+ mcp->mc_xfpustate_len = sc->sc_fcontext.mc_xfpustate_len;
+ if (mcp->mc_xfpustate_len > cpu_max_ext_state_size -
+ sizeof(struct savefpu)) {
+ uprintf("pid %d (%s): sigreturn xfpusave_len = 0x%zx\n",
+ p->p_pid, td->td_name, mcp->mc_xfpustate_len);
+ return (EINVAL);
+ }
+
+ /* Legacy region of an xsave area. */
+ error = copyin(PTRIN(sc->sc_fpstate), svfp, sizeof(mcp->mc_fpstate));
+ if (error != 0)
+ return (error);
+ bzero(svfp->sv_pad, sizeof(svfp->sv_pad));
+
+ /* Extended region of an xsave area. */
+ sc->sc_fpstate += sizeof(mcp->mc_fpstate);
+ xfpustate = (char *)fpu_save_area_alloc();
+ error = copyin(PTRIN(sc->sc_fpstate), xfpustate, mcp->mc_xfpustate_len);
+ if (error != 0) {
+ fpu_save_area_free((struct savefpu *)xfpustate);
+ uprintf("pid %d (%s): linux xrstor failed\n", p->p_pid,
+ td->td_name);
+ return (error);
+ }
+
+ /* Linux specific end of area marker. */
+ sc->sc_fpstate += mcp->mc_xfpustate_len;
+ error = copyin(PTRIN(sc->sc_fpstate), &magic2, LINUX_FP_XSTATE_MAGIC2_SIZE);
+ if (error != 0 || magic2 != LINUX_FP_XSTATE_MAGIC2) {
+ uprintf("pid %d (%s): sigreturn magic2 0x%d error %d\n",
+ p->p_pid, td->td_name, magic2, error);
+ return (error);
+ }
+
+ error = set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len);
+ fpu_save_area_free((struct savefpu *)xfpustate);
+ if (error != 0) {
+ uprintf("pid %d (%s): sigreturn set_fpcontext error %d\n",
+ p->p_pid, td->td_name, error);
+ }
+ return (error);
+}
+
static int
linux_copyin_fpstate(struct thread *td, struct l_ucontext *uc)
{
@@ -304,7 +356,10 @@
mc.mc_ownedfp = uc->uc_mcontext.sc_fcontext.mc_ownedfp;
mc.mc_fpformat = uc->uc_mcontext.sc_fcontext.mc_fpformat;
- return (linux_fxrstor(td, &mc, &uc->uc_mcontext));
+ if ((uc->uc_flags & LINUX_UC_FP_XSTATE) != 0)
+ return (linux_xrstor(td, &mc, &uc->uc_mcontext));
+ else
+ return (linux_fxrstor(td, &mc, &uc->uc_mcontext));
}
/*
@@ -411,23 +466,63 @@
return (copyout(fx, ufp, sizeof(*fx)));
}
+static int
+linux_xsave(mcontext_t *mcp, char *xfpusave, char *ufp)
+{
+ struct l_fpstate *fx = (struct l_fpstate *)&mcp->mc_fpstate[0];
+ int error, magic2;
+
+ /* Legacy region of an xsave area. */
+ fx->sw_reserved.magic1 = LINUX_FP_XSTATE_MAGIC1;
+ fx->sw_reserved.xstate_size = mcp->mc_xfpustate_len + sizeof(*fx);
+ fx->sw_reserved.extended_size = fx->sw_reserved.xstate_size +
+ LINUX_FP_XSTATE_MAGIC2_SIZE;
+ fx->sw_reserved.xfeatures = xsave_mask;
+
+ error = copyout(fx, ufp, sizeof(*fx));
+ if (error != 0)
+ return (error);
+ ufp += sizeof(*fx);
+
+ /* Extended region of an xsave area. */
+ error = copyout(xfpusave, ufp, mcp->mc_xfpustate_len);
+ if (error != 0)
+ return (error);
+
+ /* Linux specific end of xsave area marker. */
+ ufp += mcp->mc_xfpustate_len;
+ magic2 = LINUX_FP_XSTATE_MAGIC2;
+ return (copyout(&magic2, ufp, LINUX_FP_XSTATE_MAGIC2_SIZE));
+}
+
static int
linux_copyout_fpstate(struct thread *td, struct l_ucontext *uc, char **sp)
{
+ size_t xfpusave_len;
+ char *xfpusave;
mcontext_t mc;
char *ufp = *sp;
- get_fpcontext(td, &mc, NULL, NULL);
+ get_fpcontext(td, &mc, &xfpusave, &xfpusave_len);
KASSERT(mc.mc_fpformat != _MC_FPFMT_NODEV, ("fpu not present"));
uc->uc_mcontext.sc_fcontext.mc_ownedfp = mc.mc_ownedfp;
uc->uc_mcontext.sc_fcontext.mc_fpformat = mc.mc_fpformat;
+ uc->uc_mcontext.sc_fcontext.mc_xfpustate_len = xfpusave_len;
- /* fxsave area */
+ /* Room for fxsave area. */
ufp -= sizeof(struct l_fpstate);
+ if (xfpusave != NULL) {
+ /* Room for xsave area. */
+ ufp -= (xfpusave_len + LINUX_FP_XSTATE_MAGIC2_SIZE);
+ uc->uc_flags |= LINUX_UC_FP_XSTATE;
+ }
*sp = ufp = (char *)((unsigned long)ufp & ~0x3Ful);
- return (linux_fxsave(&mc, ufp));
+ if (xfpusave != NULL)
+ return (linux_xsave(&mc, xfpusave, ufp));
+ else
+ return (linux_fxsave(&mc, ufp));
}
/*
diff --git a/sys/x86/linux/linux_x86_sigframe.h b/sys/x86/linux/linux_x86_sigframe.h
--- a/sys/x86/linux/linux_x86_sigframe.h
+++ b/sys/x86/linux/linux_x86_sigframe.h
@@ -35,6 +35,26 @@
#ifndef _X86_LINUX_SIGFRAME_H_
#define _X86_LINUX_SIGFRAME_H_
+#define LINUX_UC_FP_XSTATE 0x1
+
+#define LINUX_FP_XSTATE_MAGIC1 0x46505853U
+#define LINUX_FP_XSTATE_MAGIC2 0x46505845U
+#define LINUX_FP_XSTATE_MAGIC2_SIZE sizeof(LINUX_FP_XSTATE_MAGIC2)
+
+struct l_fpx_sw_bytes {
+ uint32_t magic1;
+ uint32_t extended_size;
+ uint64_t xfeatures;
+ uint32_t xstate_size;
+ uint32_t padding[7];
+};
+
+struct l_header {
+ uint64_t xfeatures;
+ uint64_t reserved1[2];
+ uint64_t reserved2[5];
+};
+
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
/* The Linux sigcontext, pretty much a standard 386 trapframe. */
@@ -140,12 +160,17 @@
u_int32_t mxcsr_mask;
u_int8_t st[8][16];
u_int8_t xmm[16][16];
- u_int32_t reserved2[24];
+ u_int32_t reserved2[12];
+ union {
+ u_int32_t reserved3[12];
+ struct l_fpx_sw_bytes sw_reserved;
+ };
};
struct l_fcontext {
long mc_fpformat;
long mc_ownedfp;
+ register_t mc_xfpustate_len;
};
struct l_sigcontext {
@@ -182,7 +207,7 @@
* of extended memory layout.
*/
l_uintptr_t sc_fpstate;
- l_ulong sc_reserved1[6];
+ l_ulong sc_reserved1[5];
struct l_fcontext sc_fcontext;
};

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 28, 10:09 PM (12 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26304730
Default Alt Text
D40444.id122902.diff (5 KB)

Event Timeline