@@ -1186,9 +1186,10 @@ int arch_set_info_guest(
is_pv_64bit_domain(d) )
v->arch.flags &= ~TF_kernel_mode;
- vcpu_setup_fpu(v, v->arch.xsave_area,
- flags & VGCF_I387_VALID ? &c.nat->fpu_ctxt : NULL,
- FCW_DEFAULT);
+ if ( flags & VGCF_I387_VALID )
+ vcpu_setup_fpu(v, &c.nat->fpu_ctxt);
+ else
+ vcpu_reset_fpu(v);
if ( !compat )
{
@@ -1163,10 +1163,10 @@ static int cf_check hvm_load_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
seg.attr = ctxt.ldtr_arbytes;
hvm_set_segment_register(v, x86_seg_ldtr, &seg);
- /* Cover xsave-absent save file restoration on xsave-capable host. */
- vcpu_setup_fpu(v, xsave_enabled(v) ? NULL : v->arch.xsave_area,
- ctxt.flags & XEN_X86_FPU_INITIALISED ? ctxt.fpu_regs : NULL,
- FCW_RESET);
+ if ( ctxt.flags & XEN_X86_FPU_INITIALISED )
+ vcpu_setup_fpu(v, &ctxt.fpu_regs);
+ else
+ vcpu_reset_fpu(v);
v->arch.user_regs.rax = ctxt.rax;
v->arch.user_regs.rbx = ctxt.rbx;
@@ -4006,9 +4006,7 @@ void hvm_vcpu_reset_state(struct vcpu *v, uint16_t cs, uint16_t ip)
v->arch.guest_table = pagetable_null();
}
- if ( v->arch.xsave_area )
- v->arch.xsave_area->xsave_hdr.xstate_bv = 0;
- vcpu_setup_fpu(v, v->arch.xsave_area, NULL, FCW_RESET);
+ vcpu_reset_fpu(v);
arch_vcpu_regs_init(v);
v->arch.user_regs.rip = ip;
@@ -303,41 +303,26 @@ int vcpu_init_fpu(struct vcpu *v)
return xstate_alloc_save_area(v);
}
-void vcpu_setup_fpu(struct vcpu *v, struct xsave_struct *xsave_area,
- const void *data, unsigned int fcw_default)
+void vcpu_reset_fpu(struct vcpu *v)
{
- fpusse_t *fpu_sse = &v->arch.xsave_area->fpu_sse;
-
- ASSERT(!xsave_area || xsave_area == v->arch.xsave_area);
-
- v->fpu_initialised = !!data;
-
- if ( data )
- {
- memcpy(fpu_sse, data, sizeof(*fpu_sse));
- if ( xsave_area )
- xsave_area->xsave_hdr.xstate_bv = XSTATE_FP_SSE;
- }
- else if ( xsave_area && fcw_default == FCW_DEFAULT )
- {
- xsave_area->xsave_hdr.xstate_bv = 0;
- fpu_sse->mxcsr = MXCSR_DEFAULT;
- }
- else
- {
- memset(fpu_sse, 0, sizeof(*fpu_sse));
- fpu_sse->fcw = fcw_default;
- fpu_sse->mxcsr = MXCSR_DEFAULT;
- if ( v->arch.xsave_area )
- {
- v->arch.xsave_area->xsave_hdr.xstate_bv &= ~XSTATE_FP_SSE;
- if ( fcw_default != FCW_DEFAULT )
- v->arch.xsave_area->xsave_hdr.xstate_bv |= X86_XCR0_X87;
- }
- }
+ v->fpu_initialised = false;
+ *v->arch.xsave_area = (struct xsave_struct) {
+ .fpu_sse = {
+ .mxcsr = MXCSR_DEFAULT,
+ .fcw = FCW_RESET,
+ .ftw = FXSAVE_FTW_RESET,
+ },
+ .xsave_hdr.xstate_bv = X86_XCR0_X87,
+ };
+}
- if ( xsave_area )
- xsave_area->xsave_hdr.xcomp_bv = 0;
+void vcpu_setup_fpu(struct vcpu *v, const void *data)
+{
+ v->fpu_initialised = true;
+ *v->arch.xsave_area = (struct xsave_struct) {
+ .fpu_sse = *(const fpusse_t*)data,
+ .xsave_hdr.xstate_bv = XSTATE_FP_SSE,
+ };
}
/* Free FPU's context save area */
@@ -31,10 +31,23 @@ void vcpu_restore_fpu_nonlazy(struct vcpu *v, bool need_stts);
void vcpu_restore_fpu_lazy(struct vcpu *v);
void vcpu_save_fpu(struct vcpu *v);
void save_fpu_enable(void);
-
int vcpu_init_fpu(struct vcpu *v);
-struct xsave_struct;
-void vcpu_setup_fpu(struct vcpu *v, struct xsave_struct *xsave_area,
- const void *data, unsigned int fcw_default);
void vcpu_destroy_fpu(struct vcpu *v);
+
+/*
+ * Restore v's FPU to power-on reset values
+ *
+ * @param v vCPU containing the FPU
+ */
+void vcpu_reset_fpu(struct vcpu *v);
+
+/*
+ * Load x87/SSE state into v's FPU
+ *
+ * Overrides the XSAVE header to set the state components to be x87 and SSE.
+ *
+ * @param v vCPU containing the FPU
+ * @param data 512-octet blob for x87/SSE state
+ */
+void vcpu_setup_fpu(struct vcpu *v, const void *data);
#endif /* __ASM_I386_I387_H */
@@ -14,6 +14,7 @@
#define FCW_DEFAULT 0x037f
#define FCW_RESET 0x0040
+#define FXSAVE_FTW_RESET 0xFF /* Abridged Tag Word format */
#define MXCSR_DEFAULT 0x1f80
extern uint32_t mxcsr_mask;