[CRIU] [PATCH 6/6] compel: arch, x86 -- Convert frame for ia32 sigreturn
Cyrill Gorcunov
gorcunov at openvz.org
Mon Feb 13 07:03:23 PST 2017
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
compel/arch/x86/src/lib/include/uapi/asm/fpu.h | 3 +
compel/arch/x86/src/lib/infect.c | 87 ++++++++++++++++++++++++++
criu/arch/x86/crtools.c | 4 ++
3 files changed, 94 insertions(+)
diff --git a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h
index ee6e81bcd9d8..97fb7f921f9d 100644
--- a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h
+++ b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h
@@ -130,4 +130,7 @@ typedef struct {
uint8_t has_fpu;
} fpu_state_t;
+extern void compel_convert_from_fxsr(struct user_i387_ia32_struct *env,
+ struct i387_fxsave_struct *fxsave);
+
#endif /* __CR_ASM_FPU_H__ */
diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c
index 43b080000fe3..785761dc4e0e 100644
--- a/compel/arch/x86/src/lib/infect.c
+++ b/compel/arch/x86/src/lib/infect.c
@@ -47,6 +47,91 @@ static inline __always_unused void __check_code_syscall(void)
BUILD_BUG_ON(!is_log2(sizeof(code_syscall)));
}
+/* 10-byte legacy floating point register */
+struct fpreg {
+ uint16_t significand[4];
+ uint16_t exponent;
+};
+
+/* 16-byte floating point register */
+struct fpxreg {
+ uint16_t significand[4];
+ uint16_t exponent;
+ uint16_t padding[3];
+};
+
+#define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16)
+#define FP_EXP_TAG_VALID 0
+#define FP_EXP_TAG_ZERO 1
+#define FP_EXP_TAG_SPECIAL 2
+#define FP_EXP_TAG_EMPTY 3
+
+static inline uint32_t twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
+{
+ struct fpxreg *st;
+ uint32_t tos = (fxsave->swd >> 11) & 7;
+ uint32_t twd = (unsigned long)fxsave->twd;
+ uint32_t tag;
+ uint32_t ret = 0xffff0000u;
+ int i;
+
+ for (i = 0; i < 8; i++, twd >>= 1) {
+ if (twd & 0x1) {
+ st = FPREG_ADDR(fxsave, (i - tos) & 7);
+
+ switch (st->exponent & 0x7fff) {
+ case 0x7fff:
+ tag = FP_EXP_TAG_SPECIAL;
+ break;
+ case 0x0000:
+ if (!st->significand[0] &&
+ !st->significand[1] &&
+ !st->significand[2] &&
+ !st->significand[3])
+ tag = FP_EXP_TAG_ZERO;
+ else
+ tag = FP_EXP_TAG_SPECIAL;
+ break;
+ default:
+ if (st->significand[3] & 0x8000)
+ tag = FP_EXP_TAG_VALID;
+ else
+ tag = FP_EXP_TAG_SPECIAL;
+ break;
+ }
+ } else {
+ tag = FP_EXP_TAG_EMPTY;
+ }
+ ret |= tag << (2 * i);
+ }
+ return ret;
+}
+
+void compel_convert_from_fxsr(struct user_i387_ia32_struct *env,
+ struct i387_fxsave_struct *fxsave)
+{
+ struct fpxreg *from = (struct fpxreg *)&fxsave->st_space[0];
+ struct fpreg *to = (struct fpreg *)&env->st_space[0];
+ int i;
+
+ env->cwd = fxsave->cwd | 0xffff0000u;
+ env->swd = fxsave->swd | 0xffff0000u;
+ env->twd = twd_fxsr_to_i387(fxsave);
+
+ env->fip = fxsave->rip;
+ env->foo = fxsave->rdp;
+ /*
+ * should be actually ds/cs at fpu exception time, but
+ * that information is not available in 64bit mode.
+ */
+ env->fcs = 0x23; /* __USER32_CS */
+ env->fos = 0x2b; /* __USER32_DS */
+ env->fos |= 0xffff0000;
+
+ for (i = 0; i < 8; ++i)
+ memcpy(&to[i], &from[i], sizeof(to[0]));
+}
+
int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe,
user_regs_struct_t *regs,
user_fpregs_struct_t *fpregs)
@@ -106,6 +191,8 @@ int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe,
memcpy(&fpu_state->fpu_state_64.xsave, fpregs, sizeof(*fpregs));
} else {
memcpy(&fpu_state->fpu_state_ia32.xsave, fpregs, sizeof(*fpregs));
+ compel_convert_from_fxsr(&fpu_state->fpu_state_ia32.fregs_state.i387_ia32,
+ &fpu_state->fpu_state_ia32.xsave.i387);
}
return 0;
diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c
index 0986055d53fa..417a6725d3a3 100644
--- a/criu/arch/x86/crtools.c
+++ b/criu/arch/x86/crtools.c
@@ -337,6 +337,10 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core)
assign_array(x->i387, core->thread_info->fpregs, st_space);
assign_array(x->i387, core->thread_info->fpregs, xmm_space);
+ if (core_is_compat(core))
+ compel_convert_from_fxsr(&fpu_state->fpu_state_ia32.fregs_state.i387_ia32,
+ &fpu_state->fpu_state_ia32.xsave.i387);
+
if (cpu_has_feature(X86_FEATURE_OSXSAVE)) {
struct fpx_sw_bytes *fpx_sw = (void *)&x->i387.sw_reserved;
void *magic2;
--
2.7.4
More information about the CRIU
mailing list