Commit 3481b9aa authored by Alexander Kartashov's avatar Alexander Kartashov Committed by Pavel Emelyanov

FPU: introduced the support for multiple FPU architectures.

* The routine sigreturn_prep_xsave_frame() is renamed to sigreturn_prep_fpu_frame().

* Moved the routines sigreturn_prep_fpu_frame(), show_rt_xsave_frame(), and
  valid_xsave_frame() to the file crtools.c.

* Introduced the structure fpu_state_t to pass the FPU state to the restorer
  in a machine-independent way.
Signed-off-by: 's avatarAlexander Kartashov <alekskartashov@parallels.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent e1e23468
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "fpu.h" #include "fpu.h"
#include "elf.h" #include "elf.h"
#include "parasite-syscall.h" #include "parasite-syscall.h"
#include "restorer.h"
/* /*
* Injected syscall instruction * Injected syscall instruction
...@@ -282,3 +283,130 @@ void core_entry_free(CoreEntry *core) ...@@ -282,3 +283,130 @@ void core_entry_free(CoreEntry *core)
xfree(core->ids); xfree(core->ids);
} }
} }
static bool valid_xsave_frame(CoreEntry *core)
{
struct xsave_struct *x = NULL;
if (core->thread_info->fpregs->n_st_space < ARRAY_SIZE(x->i387.st_space)) {
pr_err("Corruption in FPU st_space area "
"(got %li but %li expected)\n",
(long)core->thread_info->fpregs->n_st_space,
(long)ARRAY_SIZE(x->i387.st_space));
return false;
}
if (core->thread_info->fpregs->n_xmm_space < ARRAY_SIZE(x->i387.xmm_space)) {
pr_err("Corruption in FPU xmm_space area "
"(got %li but %li expected)\n",
(long)core->thread_info->fpregs->n_st_space,
(long)ARRAY_SIZE(x->i387.xmm_space));
return false;
}
if (cpu_has_feature(X86_FEATURE_XSAVE)) {
if (!core->thread_info->fpregs->xsave) {
pr_err("FPU xsave area is missing, "
"but host cpu requires it\n");
return false;
}
if (core->thread_info->fpregs->xsave->n_ymmh_space < ARRAY_SIZE(x->ymmh.ymmh_space)) {
pr_err("Corruption in FPU ymmh_space area "
"(got %li but %li expected)\n",
(long)core->thread_info->fpregs->xsave->n_ymmh_space,
(long)ARRAY_SIZE(x->ymmh.ymmh_space));
return false;
}
} else {
if (core->thread_info->fpregs->xsave) {
pr_err("FPU xsave area present, "
"but host cpu doesn't support it\n");
return false;
}
return true;
}
return true;
}
static void show_rt_xsave_frame(struct xsave_struct *x)
{
struct fpx_sw_bytes *fpx = (void *)&x->i387.sw_reserved;
struct xsave_hdr_struct *xsave_hdr = &x->xsave_hdr;
struct i387_fxsave_struct *i387 = &x->i387;
pr_debug("xsave runtime structure\n");
pr_debug("-----------------------\n");
pr_debug("cwd:%x swd:%x twd:%x fop:%x mxcsr:%x mxcsr_mask:%x\n",
(int)i387->cwd, (int)i387->swd, (int)i387->twd,
(int)i387->fop, (int)i387->mxcsr, (int)i387->mxcsr_mask);
pr_debug("magic1:%x extended_size:%x xstate_bv:%lx xstate_size:%x\n",
fpx->magic1, fpx->extended_size, fpx->xstate_bv, fpx->xstate_size);
pr_debug("xstate_bv: %lx\n", xsave_hdr->xstate_bv);
pr_debug("-----------------------\n");
}
int sigreturn_prep_fpu_frame(struct thread_restore_args *args, CoreEntry *core)
{
struct xsave_struct *x = &args->fpu_state.xsave;
/*
* If no FPU information provided -- we're restoring
* old image which has no FPU support, or the dump simply
* has no FPU support at all.
*/
if (!core->thread_info->fpregs) {
args->has_fpu = false;
return 0;
}
if (!valid_xsave_frame(core))
return -1;
args->has_fpu = true;
#define assign_reg(dst, src, e) do { dst.e = (__typeof__(dst.e))src->e; } while (0)
#define assign_array(dst, src, e) memcpy(dst.e, (src)->e, sizeof(dst.e))
assign_reg(x->i387, core->thread_info->fpregs, cwd);
assign_reg(x->i387, core->thread_info->fpregs, swd);
assign_reg(x->i387, core->thread_info->fpregs, twd);
assign_reg(x->i387, core->thread_info->fpregs, fop);
assign_reg(x->i387, core->thread_info->fpregs, rip);
assign_reg(x->i387, core->thread_info->fpregs, rdp);
assign_reg(x->i387, core->thread_info->fpregs, mxcsr);
assign_reg(x->i387, core->thread_info->fpregs, mxcsr_mask);
assign_array(x->i387, core->thread_info->fpregs, st_space);
assign_array(x->i387, core->thread_info->fpregs, xmm_space);
if (cpu_has_feature(X86_FEATURE_XSAVE)) {
struct fpx_sw_bytes *fpx_sw = (void *)&x->i387.sw_reserved;
void *magic2;
x->xsave_hdr.xstate_bv = XSTATE_FP | XSTATE_SSE | XSTATE_YMM;
assign_array(x->ymmh, core->thread_info->fpregs->xsave, ymmh_space);
fpx_sw->magic1 = FP_XSTATE_MAGIC1;
fpx_sw->xstate_bv = XSTATE_FP | XSTATE_SSE | XSTATE_YMM;
fpx_sw->xstate_size = sizeof(struct xsave_struct);
fpx_sw->extended_size = sizeof(struct xsave_struct) + FP_XSTATE_MAGIC2_SIZE;
/*
* This should be at the end of xsave frame.
*/
magic2 = args->fpu_state.__pad + sizeof(struct xsave_struct);
*(u32 *)magic2 = FP_XSTATE_MAGIC2;
}
show_rt_xsave_frame(x);
#undef assign_reg
#undef assign_array
return 0;
}
...@@ -17,4 +17,7 @@ ...@@ -17,4 +17,7 @@
#define core_get_tls(pcore, ptls) #define core_get_tls(pcore, ptls)
int sigreturn_prep_fpu_frame(struct thread_restore_args *args, CoreEntry *core);
#endif #endif
...@@ -249,4 +249,18 @@ typedef struct { ...@@ -249,4 +249,18 @@ typedef struct {
typedef uint64_t auxv_t; typedef uint64_t auxv_t;
#include "fpu.h"
typedef struct {
/*
* The FPU xsave area must be continious and FP_MIN_ALIGN_BYTES
* aligned, thus make sure the compiler won't insert any hole here.
*/
union {
struct xsave_struct xsave;
unsigned char __pad[sizeof(struct xsave_struct) + FP_XSTATE_MAGIC2_SIZE];
};
} fpu_state_t;
#endif /* __CR_ASM_TYPES_H__ */ #endif /* __CR_ASM_TYPES_H__ */
...@@ -58,10 +58,10 @@ int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) ...@@ -58,10 +58,10 @@ int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r)
int restore_fpu(struct rt_sigframe *sigframe, struct thread_restore_args *args) int restore_fpu(struct rt_sigframe *sigframe, struct thread_restore_args *args)
{ {
if (args->has_fpu) { if (args->has_fpu) {
unsigned long addr = (unsigned long)(void *)&args->xsave; unsigned long addr = (unsigned long)(void *)&args->fpu_state.xsave;
if ((addr % 64ul) == 0ul) { if ((addr % 64ul) == 0ul) {
sigframe->uc.uc_mcontext.fpstate = &args->xsave; sigframe->uc.uc_mcontext.fpstate = &args->fpu_state.xsave;
} else { } else {
pr_err("Unaligned address passed: %lx\n", addr); pr_err("Unaligned address passed: %lx\n", addr);
return -1; return -1;
......
...@@ -1568,133 +1568,6 @@ static int prep_sched_info(struct rst_sched_param *sp, ThreadCoreEntry *tc) ...@@ -1568,133 +1568,6 @@ static int prep_sched_info(struct rst_sched_param *sp, ThreadCoreEntry *tc)
return 0; return 0;
} }
static bool valid_xsave_frame(CoreEntry *core)
{
struct xsave_struct *x = NULL;
if (core->thread_info->fpregs->n_st_space < ARRAY_SIZE(x->i387.st_space)) {
pr_err("Corruption in FPU st_space area "
"(got %li but %li expected)\n",
(long)core->thread_info->fpregs->n_st_space,
(long)ARRAY_SIZE(x->i387.st_space));
return false;
}
if (core->thread_info->fpregs->n_xmm_space < ARRAY_SIZE(x->i387.xmm_space)) {
pr_err("Corruption in FPU xmm_space area "
"(got %li but %li expected)\n",
(long)core->thread_info->fpregs->n_st_space,
(long)ARRAY_SIZE(x->i387.xmm_space));
return false;
}
if (cpu_has_feature(X86_FEATURE_XSAVE)) {
if (!core->thread_info->fpregs->xsave) {
pr_err("FPU xsave area is missing, "
"but host cpu requires it\n");
return false;
}
if (core->thread_info->fpregs->xsave->n_ymmh_space < ARRAY_SIZE(x->ymmh.ymmh_space)) {
pr_err("Corruption in FPU ymmh_space area "
"(got %li but %li expected)\n",
(long)core->thread_info->fpregs->xsave->n_ymmh_space,
(long)ARRAY_SIZE(x->ymmh.ymmh_space));
return false;
}
} else {
if (core->thread_info->fpregs->xsave) {
pr_err("FPU xsave area present, "
"but host cpu doesn't support it\n");
return false;
}
return true;
}
return true;
}
static void show_rt_xsave_frame(struct xsave_struct *x)
{
struct fpx_sw_bytes *fpx = (void *)&x->i387.sw_reserved;
struct xsave_hdr_struct *xsave_hdr = &x->xsave_hdr;
struct i387_fxsave_struct *i387 = &x->i387;
pr_debug("xsave runtime structure\n");
pr_debug("-----------------------\n");
pr_debug("cwd:%x swd:%x twd:%x fop:%x mxcsr:%x mxcsr_mask:%x\n",
(int)i387->cwd, (int)i387->swd, (int)i387->twd,
(int)i387->fop, (int)i387->mxcsr, (int)i387->mxcsr_mask);
pr_debug("magic1:%x extended_size:%x xstate_bv:%lx xstate_size:%x\n",
fpx->magic1, fpx->extended_size, fpx->xstate_bv, fpx->xstate_size);
pr_debug("xstate_bv: %lx\n", xsave_hdr->xstate_bv);
pr_debug("-----------------------\n");
}
static int sigreturn_prep_xsave_frame(struct thread_restore_args *args, CoreEntry *core)
{
struct xsave_struct *x = &args->xsave;
/*
* If no FPU information provided -- we're restoring
* old image which has no FPU support, or the dump simply
* has no FPU support at all.
*/
if (!core->thread_info->fpregs) {
args->has_fpu = false;
return 0;
}
if (!valid_xsave_frame(core))
return -1;
args->has_fpu = true;
#define assign_reg(dst, src, e) do { dst.e = (__typeof__(dst.e))src->e; } while (0)
#define assign_array(dst, src, e) memcpy(dst.e, (src)->e, sizeof(dst.e))
assign_reg(x->i387, core->thread_info->fpregs, cwd);
assign_reg(x->i387, core->thread_info->fpregs, swd);
assign_reg(x->i387, core->thread_info->fpregs, twd);
assign_reg(x->i387, core->thread_info->fpregs, fop);
assign_reg(x->i387, core->thread_info->fpregs, rip);
assign_reg(x->i387, core->thread_info->fpregs, rdp);
assign_reg(x->i387, core->thread_info->fpregs, mxcsr);
assign_reg(x->i387, core->thread_info->fpregs, mxcsr_mask);
assign_array(x->i387, core->thread_info->fpregs, st_space);
assign_array(x->i387, core->thread_info->fpregs, xmm_space);
if (cpu_has_feature(X86_FEATURE_XSAVE)) {
struct fpx_sw_bytes *fpx_sw = (void *)&x->i387.sw_reserved;
void *magic2;
x->xsave_hdr.xstate_bv = XSTATE_FP | XSTATE_SSE | XSTATE_YMM;
assign_array(x->ymmh, core->thread_info->fpregs->xsave, ymmh_space);
fpx_sw->magic1 = FP_XSTATE_MAGIC1;
fpx_sw->xstate_bv = XSTATE_FP | XSTATE_SSE | XSTATE_YMM;
fpx_sw->xstate_size = sizeof(struct xsave_struct);
fpx_sw->extended_size = sizeof(struct xsave_struct) + FP_XSTATE_MAGIC2_SIZE;
/*
* This should be at the end of xsave frame.
*/
magic2 = args->__pad + sizeof(struct xsave_struct);
*(u32 *)magic2 = FP_XSTATE_MAGIC2;
}
show_rt_xsave_frame(x);
#undef assign_reg
#undef assign_array
return 0;
}
extern void __gcov_flush(void) __attribute__((weak)); extern void __gcov_flush(void) __attribute__((weak));
void __gcov_flush(void) {} void __gcov_flush(void) {}
...@@ -1911,7 +1784,7 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core) ...@@ -1911,7 +1784,7 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
goto err; goto err;
} }
if (sigreturn_prep_xsave_frame(&thread_args[i], core)) if (sigreturn_prep_fpu_frame(&thread_args[i], core))
goto err; goto err;
if (thread_args[i].pid != pid) if (thread_args[i].pid != pid)
......
...@@ -81,15 +81,8 @@ struct thread_restore_args { ...@@ -81,15 +81,8 @@ struct thread_restore_args {
struct task_restore_core_args *ta; struct task_restore_core_args *ta;
/*
* The FPU xsave area must be continious and FP_MIN_ALIGN_BYTES
* aligned, thus make sure the compiler won't insert any hole here.
*/
bool has_fpu; bool has_fpu;
union { fpu_state_t fpu_state;
struct xsave_struct xsave;
unsigned char __pad[sizeof(struct xsave_struct) + FP_XSTATE_MAGIC2_SIZE];
};
u32 tls; u32 tls;
} __aligned(sizeof(long)); } __aligned(sizeof(long));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment