aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/xstate.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2013-06-04 17:25:41 +0200
committerJan Beulich <jbeulich@suse.com>2013-06-04 17:25:41 +0200
commit10b2b21a241795394637167bd4b076f2de17741f (patch)
tree1c69c4e55a295502a3c6c92e5dd359862a95865c /xen/arch/x86/xstate.c
parent10f969150025498fe27d985f9021a68f8c7acc31 (diff)
downloadxen-10b2b21a241795394637167bd4b076f2de17741f.tar.gz
xen-10b2b21a241795394637167bd4b076f2de17741f.tar.bz2
xen-10b2b21a241795394637167bd4b076f2de17741f.zip
x86: fix XCR0 handling
- both VMX and SVM ignored the ECX input to XSETBV - both SVM and VMX used the full 64-bit RAX when calculating the input mask to XSETBV - faults on XSETBV did not get recovered from Also consolidate the handling for PV and HVM into a single function, and make the per-CPU variable "xcr0" static to xstate.c. Signed-off-by: Jan Beulich <jbeulich@suse.com> Acked-by: Keir Fraser <keir@xen.org> Acked-by: George Dunlap <george.dunlap@eu.citrix.com>
Diffstat (limited to 'xen/arch/x86/xstate.c')
-rw-r--r--xen/arch/x86/xstate.c49
1 files changed, 41 insertions, 8 deletions
diff --git a/xen/arch/x86/xstate.c b/xen/arch/x86/xstate.c
index 3ca856c6a9..d52dbd715c 100644
--- a/xen/arch/x86/xstate.c
+++ b/xen/arch/x86/xstate.c
@@ -5,7 +5,7 @@
*
*/
-#include <xen/config.h>
+#include <xen/percpu.h>
#include <xen/sched.h>
#include <asm/current.h>
#include <asm/processor.h>
@@ -27,24 +27,34 @@ u32 xsave_cntxt_size;
u64 xfeature_mask;
/* Cached xcr0 for fast read */
-DEFINE_PER_CPU(uint64_t, xcr0);
+static DEFINE_PER_CPU(uint64_t, xcr0);
/* Because XCR0 is cached for each CPU, xsetbv() is not exposed. Users should
* use set_xcr0() instead.
*/
-static inline void xsetbv(u32 index, u64 xfeatures)
+static inline bool_t xsetbv(u32 index, u64 xfeatures)
{
u32 hi = xfeatures >> 32;
u32 lo = (u32)xfeatures;
- asm volatile (".byte 0x0f,0x01,0xd1" :: "c" (index),
- "a" (lo), "d" (hi));
+ asm volatile ( "1: .byte 0x0f,0x01,0xd1\n"
+ "3: \n"
+ ".section .fixup,\"ax\" \n"
+ "2: xor %0,%0 \n"
+ " jmp 3b \n"
+ ".previous \n"
+ _ASM_EXTABLE(1b, 2b)
+ : "+a" (lo)
+ : "c" (index), "d" (hi));
+ return lo != 0;
}
-void set_xcr0(u64 xfeatures)
+bool_t set_xcr0(u64 xfeatures)
{
+ if ( !xsetbv(XCR_XFEATURE_ENABLED_MASK, xfeatures) )
+ return 0;
this_cpu(xcr0) = xfeatures;
- xsetbv(XCR_XFEATURE_ENABLED_MASK, xfeatures);
+ return 1;
}
uint64_t get_xcr0(void)
@@ -236,7 +246,8 @@ void xstate_init(void)
* Set CR4_OSXSAVE and run "cpuid" to get xsave_cntxt_size.
*/
set_in_cr4(X86_CR4_OSXSAVE);
- set_xcr0((((u64)edx << 32) | eax) & XCNTXT_MASK);
+ if ( !set_xcr0((((u64)edx << 32) | eax) & XCNTXT_MASK) )
+ BUG();
cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
if ( cpu == 0 )
@@ -262,6 +273,28 @@ void xstate_init(void)
}
}
+int handle_xsetbv(u32 index, u64 new_bv)
+{
+ struct vcpu *curr = current;
+
+ if ( index != XCR_XFEATURE_ENABLED_MASK )
+ return -EOPNOTSUPP;
+
+ if ( (new_bv & ~xfeature_mask) || !(new_bv & XSTATE_FP) )
+ return -EINVAL;
+
+ if ( (new_bv & XSTATE_YMM) && !(new_bv & XSTATE_SSE) )
+ return -EINVAL;
+
+ if ( !set_xcr0(new_bv) )
+ return -EFAULT;
+
+ curr->arch.xcr0 = new_bv;
+ curr->arch.xcr0_accum |= new_bv;
+
+ return 0;
+}
+
/*
* Local variables:
* mode: C