From: David Vrabel <david.vrabel@citrix.com>
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper <andrew.cooper3@citrix.com>,
David Vrabel <david.vrabel@citrix.com>,
Jan Beulich <jbeulich@suse.com>
Subject: [PATCHv1 3/5] x86/fpu: Add a per-domain field to set the width of FIP/FDP
Date: Thu, 18 Feb 2016 18:52:08 +0000 [thread overview]
Message-ID: <1455821530-4263-4-git-send-email-david.vrabel@citrix.com> (raw)
In-Reply-To: <1455821530-4263-1-git-send-email-david.vrabel@citrix.com>
The x86 architecture allows either: a) the 64-bit FIP/FDP registers to be
restored (clearing FCS and FDS); or b) the 32-bit FIP/FDP and FCS/FDS
registers to be restored (clearing the upper 32-bits).
Add a per-domain field to indicate which of these options a guest needs.
The options are: 8, 4 or 0. Where 0 indicates that the hypervisor should
automatically guess the FIP width by checking the value of FIP/FDP when
saving the state (this is the existing behaviour).
The FIP width is initially automatic but is set explicitly in the following
cases:
- 32-bit PV guest: 4
- 64-bit PV guest: 8
- Newer CPUs that do not save FCS/FDS: 8
xsave() has been simplified to not require clearing the FCS/FDS fields --
either these are updated by the XSAVE* instruction or they are not
written.
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
---
xen/arch/x86/domain.c | 10 ++++++++++
xen/arch/x86/i387.c | 15 ++++++++-------
xen/arch/x86/xstate.c | 43 +++++++++++--------------------------------
xen/include/asm-x86/domain.h | 15 +++++++++++++++
4 files changed, 44 insertions(+), 39 deletions(-)
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 9d43f7b..a15cdf7 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -343,6 +343,8 @@ int switch_native(struct domain *d)
hvm_set_mode(v, 8);
}
+ d->arch.x87_fip_width = 8;
+
return 0;
}
@@ -377,6 +379,8 @@ int switch_compat(struct domain *d)
domain_set_alloc_bitsize(d);
+ d->arch.x87_fip_width = 4;
+
return 0;
undo_and_fail:
@@ -653,6 +657,12 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags,
/* PV/PVH guests get an emulated PIT too for video BIOSes to use. */
pit_init(d, cpu_khz);
+ /*
+ * If the FPU not to save FCS/FDS then we can always save/restore
+ * the 64-bit FIP/FDP and ignore the selectors.
+ */
+ d->arch.x87_fip_width = cpu_has_fpu_sel ? 0 : 8;
+
return 0;
fail:
diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c
index 67016c9..ef08a52 100644
--- a/xen/arch/x86/i387.c
+++ b/xen/arch/x86/i387.c
@@ -144,9 +144,9 @@ static inline void fpu_xsave(struct vcpu *v)
static inline void fpu_fxsave(struct vcpu *v)
{
typeof(v->arch.xsave_area->fpu_sse) *fpu_ctxt = v->arch.fpu_ctxt;
- int word_size = cpu_has_fpu_sel ? 8 : 0;
+ unsigned int fip_width = v->domain->arch.x87_fip_width;
- if ( !is_pv_32bit_vcpu(v) )
+ if ( fip_width != 4 )
{
/*
* The only way to force fxsaveq on a wide range of gas versions.
@@ -164,7 +164,7 @@ static inline void fpu_fxsave(struct vcpu *v)
boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
return;
- if ( word_size > 0 &&
+ if ( !fip_width &&
!((fpu_ctxt->fip.addr | fpu_ctxt->fdp.addr) >> 32) )
{
struct ix87_env fpu_env;
@@ -172,17 +172,18 @@ static inline void fpu_fxsave(struct vcpu *v)
asm volatile ( "fnstenv %0" : "=m" (fpu_env) );
fpu_ctxt->fip.sel = fpu_env.fcs;
fpu_ctxt->fdp.sel = fpu_env.fds;
- word_size = 4;
+ fip_width = 4;
}
+ else
+ fip_width = 8;
}
else
{
asm volatile ( "fxsave %0" : "=m" (*fpu_ctxt) );
- word_size = 4;
+ fip_width = 4;
}
- if ( word_size >= 0 )
- fpu_ctxt->x[FPU_WORD_SIZE_OFFSET] = word_size;
+ fpu_ctxt->x[FPU_WORD_SIZE_OFFSET] = fip_width;
}
/*******************************/
diff --git a/xen/arch/x86/xstate.c b/xen/arch/x86/xstate.c
index 4f2fb8e..c4cc071 100644
--- a/xen/arch/x86/xstate.c
+++ b/xen/arch/x86/xstate.c
@@ -249,7 +249,7 @@ void xsave(struct vcpu *v, uint64_t mask)
struct xsave_struct *ptr = v->arch.xsave_area;
uint32_t hmask = mask >> 32;
uint32_t lmask = mask;
- int word_size = mask & XSTATE_FP ? (cpu_has_fpu_sel ? 8 : 0) : -1;
+ unsigned int fip_width = v->domain->arch.x87_fip_width;
#define XSAVE(pfx) \
alternative_io_3(".byte " pfx "0x0f,0xae,0x27\n", /* xsave */ \
".byte " pfx "0x0f,0xae,0x37\n", /* xsaveopt */ \
@@ -261,28 +261,8 @@ void xsave(struct vcpu *v, uint64_t mask)
"=m" (*ptr), \
"a" (lmask), "d" (hmask), "D" (ptr))
- if ( word_size <= 0 || !is_pv_32bit_vcpu(v) )
+ if ( fip_width != 4 )
{
- typeof(ptr->fpu_sse.fip.sel) fcs = ptr->fpu_sse.fip.sel;
- typeof(ptr->fpu_sse.fdp.sel) fds = ptr->fpu_sse.fdp.sel;
-
- if ( cpu_has_xsaveopt || cpu_has_xsaves )
- {
- /*
- * XSAVEOPT/XSAVES may not write the FPU portion even when the
- * respective mask bit is set. For the check further down to work
- * we hence need to put the save image back into the state that
- * it was in right after the previous XSAVEOPT.
- */
- if ( word_size > 0 &&
- (ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] == 4 ||
- ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] == 2) )
- {
- ptr->fpu_sse.fip.sel = 0;
- ptr->fpu_sse.fdp.sel = 0;
- }
- }
-
XSAVE("0x48,");
if ( !(mask & ptr->xsave_hdr.xstate_bv & XSTATE_FP) ||
@@ -293,15 +273,14 @@ void xsave(struct vcpu *v, uint64_t mask)
(!(ptr->fpu_sse.fsw & 0x0080) &&
boot_cpu_data.x86_vendor == X86_VENDOR_AMD) )
{
- if ( (cpu_has_xsaveopt || cpu_has_xsaves) && word_size > 0 )
- {
- ptr->fpu_sse.fip.sel = fcs;
- ptr->fpu_sse.fdp.sel = fds;
- }
return;
}
- if ( word_size > 0 &&
+ /*
+ * If the FIP/FDP[63:32] are both zero, it is safe to use the
+ * 32-bit restore to also restore the selectors.
+ */
+ if ( !fip_width &&
!((ptr->fpu_sse.fip.addr | ptr->fpu_sse.fdp.addr) >> 32) )
{
struct ix87_env fpu_env;
@@ -309,17 +288,17 @@ void xsave(struct vcpu *v, uint64_t mask)
asm volatile ( "fnstenv %0" : "=m" (fpu_env) );
ptr->fpu_sse.fip.sel = fpu_env.fcs;
ptr->fpu_sse.fdp.sel = fpu_env.fds;
- word_size = 4;
+ fip_width = 4;
}
+ else
+ fip_width = 8;
}
else
{
XSAVE("");
- word_size = 4;
}
#undef XSAVE
- if ( word_size >= 0 )
- ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] = word_size;
+ ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] = fip_width;
}
void xrstor(struct vcpu *v, uint64_t mask)
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index 4fad638..362fd8f 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -394,6 +394,21 @@ struct arch_domain
/* Emulated devices enabled bitmap. */
uint32_t emulation_flags;
+
+ /*
+ * The width of the FIP/FDP register in the FPU that needs to be
+ * saved/restored during a context switch. This is needed because
+ * the FPU can either: a) restore the 64-bit FIP/FDP and clear FCS
+ * and FDS; or b) retstore the 32-bit FIP/FDP (clearing the upper
+ * 32-bits) and restore FCS/FDS.
+ *
+ * Which one is needed depends on the guest.
+ *
+ * This can be either: 8, 4 or 0. 0 means auto-detect the size
+ * based on the width of FIP/FDP values that are written by by the
+ * guest.
+ */
+ uint8_t x87_fip_width;
} __cacheline_aligned;
#define has_vlapic(d) (!!((d)->arch.emulation_flags & XEN_X86_EMU_LAPIC))
--
2.1.4
next prev parent reply other threads:[~2016-02-18 18:52 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-18 18:52 [RFC PATCH 0/5] x86: workaround inability to fully restore FPU state David Vrabel
2016-02-18 18:52 ` [PATCHv1 1/5] domctl: Add op to get/set generic numeric parameters David Vrabel
2016-02-18 19:02 ` Andrew Cooper
2016-02-19 13:59 ` Jan Beulich
2016-02-18 18:52 ` [PATCHv1 2/5] tools/libxc: add xc_domain_get_param() and xc_domain_set_param() David Vrabel
2016-02-18 19:03 ` Andrew Cooper
2016-02-18 18:52 ` David Vrabel [this message]
2016-02-18 19:13 ` [PATCHv1 3/5] x86/fpu: Add a per-domain field to set the width of FIP/FDP Andrew Cooper
2016-02-19 10:03 ` David Vrabel
2016-02-19 14:08 ` Jan Beulich
2016-02-19 14:16 ` David Vrabel
2016-02-19 14:36 ` Jan Beulich
2016-02-19 14:49 ` David Vrabel
2016-02-19 15:14 ` Jan Beulich
2016-02-19 15:43 ` David Vrabel
2016-02-19 16:38 ` David Vrabel
2016-02-19 17:20 ` Jan Beulich
2016-02-18 18:52 ` [PATCHv1 4/5] x86/viridian: set x87 FIP width to 4 for Windows guests David Vrabel
2016-02-18 19:19 ` Andrew Cooper
2016-02-19 14:11 ` Jan Beulich
2016-02-18 18:52 ` [PATCHv1 5/5] x86/domctl: Add XEN_DOMCTL_PARAM_ARCH_X86_FIP_WIDTH parameter David Vrabel
2016-02-19 10:05 ` David Vrabel
2016-02-19 14:13 ` Jan Beulich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1455821530-4263-4-git-send-email-david.vrabel@citrix.com \
--to=david.vrabel@citrix.com \
--cc=andrew.cooper3@citrix.com \
--cc=jbeulich@suse.com \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).