All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] Add xsave/xrstor support to Xen
@ 2009-04-04  0:22 yuhong
  0 siblings, 0 replies; 9+ messages in thread
From: yuhong @ 2009-04-04  0:22 UTC (permalink / raw)
  To: xen-devel



Keir Fraser-3 wrote:
> 
> I must say I am happy to wait until there are some actual extended state
> vectors to be saved. It's not clear that the XSAVE format is the right way
> to extend the HVM save/restore format. The right direction may depend on
> what types of new state are introduced, whether these are achitectural or
> vendor-specific, etc. It doesn't sound like there's a downside to sitting
> on
> the fence and doing nothing for now.
> 
Fortunately, the additional state that will be saved by future processors
is already documented in the Intel AVX programming reference.
Basically, AVX is extending the XMM registers to 256-bit.
These extended registers are called the YMM registers.
-- 
View this message in context: http://www.nabble.com/-PATCH--Add-xsave-xrstor-support-to-Xen-tp17511107p22878390.html
Sent from the Xen - Dev mailing list archive at Nabble.com.

^ permalink raw reply	[flat|nested] 9+ messages in thread
* [PATCH] Add XSAVE/XRSTOR support to Xen
@ 2008-11-26  9:43 Cui, Dexuan
  2008-11-26 10:25 ` Keir Fraser
  2008-11-26 11:22 ` Jan Beulich
  0 siblings, 2 replies; 9+ messages in thread
From: Cui, Dexuan @ 2008-11-26  9:43 UTC (permalink / raw)
  To: 'Keir Fraser', xen-devel@lists.xensource.com

[-- Attachment #1: Type: text/plain, Size: 491 bytes --]

The attached patch adds the support of XSAVE/XRSTOR infrastructure for x86.
XSAVE/XRSTOR manages the existing and future processor extended states on x86 architecture.

XSAVE/XRSTOR related stuff is defined in Intel SDMs (The latest version is Nov. 2008):
http://www.intel.com/products/processor/manuals/ 

The patch uses the classical CR0.TS based lazy algorithm.
For now only FPU/SSE states (The bit 0 and 1 of XCR0) is supported.

Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>

[-- Attachment #2: xsave_in_xen.patch --]
[-- Type: application/octet-stream, Size: 12958 bytes --]

diff -r e7c421510be9 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c	Mon Nov 24 13:57:48 2008 +0000
+++ b/xen/arch/x86/domain.c	Tue Nov 25 15:02:29 2008 +0800
@@ -289,6 +289,18 @@ int vcpu_initialise(struct vcpu *v)
 
     paging_vcpu_init(v);
 
+    if ( cpu_has_xsave && !is_idle_vcpu(v) )
+    {
+        /* XSAVE/XRSTOR requires the save area be 64-byte aligned. */
+        v->arch.xsave_area = _xmalloc(xsave_cntxt_max_size, 64);
+        if ( v->arch.xsave_area == NULL )
+            return -ENOMEM; 
+
+        /* For now we only know about FPU/SSE. */
+        v->arch.xfeature_mask = XSTATE_FPU_SSE;
+        xsave_init_save_area(v->arch.xsave_area);
+    }
+
     if ( is_hvm_domain(d) )
     {
         if ( (rc = hvm_vcpu_initialise(v)) != 0 )
@@ -331,6 +343,9 @@ void vcpu_destroy(struct vcpu *v)
 
     if ( is_hvm_vcpu(v) )
         hvm_vcpu_destroy(v);
+
+    if ( v->arch.xsave_area != NULL )
+        xfree(v->arch.xsave_area);
 }
 
 int arch_domain_create(struct domain *d, unsigned int domcr_flags)
diff -r e7c421510be9 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c	Mon Nov 24 13:57:48 2008 +0000
+++ b/xen/arch/x86/hvm/hvm.c	Tue Nov 25 15:47:03 2008 +0800
@@ -41,6 +41,7 @@
 #include <asm/processor.h>
 #include <asm/types.h>
 #include <asm/msr.h>
+#include <asm/i387.h>
 #include <asm/mc146818rtc.h>
 #include <asm/spinlock.h>
 #include <asm/hvm/hvm.h>
@@ -1634,6 +1635,7 @@ void hvm_cpuid(unsigned int input, unsig
                                    unsigned int *ecx, unsigned int *edx)
 {
     struct vcpu *v = current;
+    unsigned int count = *ecx;
 
     if ( cpuid_viridian_leaves(input, eax, ebx, ecx, edx) )
         return;
@@ -1650,6 +1652,34 @@ void hvm_cpuid(unsigned int input, unsig
         *ebx |= (v->vcpu_id * 2) << 24;
         if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
             __clear_bit(X86_FEATURE_APIC & 31, edx);
+
+        /* Fix up XSAVE and OSXSAVE. */
+        *ecx &= ~(bitmaskof(X86_FEATURE_XSAVE) |
+                  bitmaskof(X86_FEATURE_OSXSAVE));
+        if ( cpu_has_xsave )
+        {
+            *ecx |= bitmaskof(X86_FEATURE_XSAVE);
+            *ecx |= (v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_OSXSAVE) ?
+                     bitmaskof(X86_FEATURE_OSXSAVE) : 0;
+        }
+    }
+    else if ( (input == 0x0000000D) && cpu_has_xsave )
+    { 
+        /*
+         *  Fix up "Processor Extended State Enumeration". We only present
+         *  FPU(bit0) and SSE(bit1) to HVM guest for now.
+         */
+        switch ( count )
+        {
+        case 0:
+            *eax = XSTATE_FPU_SSE;
+            *ebx = *ecx = 512 + 64;
+            *edx = 0;
+            break;
+        default:
+            *eax = *ebx = *ecx = *edx = 0;
+            break;
+        }
     }
 }
 
diff -r e7c421510be9 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c	Mon Nov 24 13:57:48 2008 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c	Tue Nov 25 19:06:40 2008 +0800
@@ -1242,6 +1242,9 @@ void start_vmx(void)
 {
     static int bootstrapped;
 
+    if ( cpu_has_xsave )
+        xsave_init();
+
     vmx_save_host_msrs();
 
     if ( bootstrapped )
@@ -2356,6 +2359,37 @@ asmlinkage void vmx_vmexit_handler(struc
         break;
     }
 
+    case EXIT_REASON_XSETBV:
+    {
+        int err = 0;
+        u64 new_bv  =  (((u64)regs->edx) << 32) | regs->eax;
+        u64 xfeature = (((u64)xfeature_high) << 32) | xfeature_low;
+        struct segment_register sreg;
+
+        hvm_get_segment_register(v, x86_seg_ss, &sreg);
+        if ( sreg.attr.fields.dpl != 0 )
+            err = 1;
+        else if ( ((new_bv ^ xfeature) & ~xfeature) || !(new_bv & 1) )
+            err = 1;
+
+        /* For now we only know about FPU/SSE. */
+        if ( !err && (new_bv & ~XSTATE_FPU_SSE) )
+            err = 1;
+
+        if ( err )
+        {
+            vmx_inject_hw_exception(TRAP_gp_fault, 0); 
+            break;
+        }
+
+        inst_len = __get_instruction_length();
+        __update_guest_eip(inst_len);
+
+        v->arch.xfeature_mask = new_bv | XSTATE_FPU_SSE;
+        xsetbv(XCR_XFEATURE_ENABLED_MASK, new_bv);
+        break;
+    }
+
     default:
     exit_and_crash:
         gdprintk(XENLOG_ERR, "Bad vmexit (reason %x)\n", exit_reason);
diff -r e7c421510be9 xen/arch/x86/i387.c
--- a/xen/arch/x86/i387.c	Mon Nov 24 13:57:48 2008 +0000
+++ b/xen/arch/x86/i387.c	Tue Nov 25 19:08:36 2008 +0800
@@ -33,7 +33,11 @@ void save_init_fpu(struct vcpu *v)
     if ( cr0 & X86_CR0_TS )
         clts();
 
-    if ( cpu_has_fxsr )
+    if ( cpu_has_xsave )
+    {
+        xsave(v->arch.xsave_area, v->arch.xfeature_mask);
+    }
+    else if ( cpu_has_fxsr )
     {
 #ifdef __i386__
         asm volatile (
@@ -82,6 +86,9 @@ void restore_fpu(struct vcpu *v)
 void restore_fpu(struct vcpu *v)
 {
     char *fpu_ctxt = v->arch.guest_context.fpu_ctxt.x;
+
+    /* We don't use restore_fpu() if cpu_has_xsave is true. */
+    ASSERT(!cpu_has_xsave);
 
     /*
      * FXRSTOR can fault if passed a corrupted data block. We handle this
@@ -129,6 +136,67 @@ void restore_fpu(struct vcpu *v)
 }
 
 /*
+ * Maximum size (bytes) of the XSAVE/XRSTOR save area required by all supported
+ * features in the processor, i.e all the valid bit fields in
+ * XFEATURE_ENABLED_MASK. This includes the size needed for the XSAVE.HEADER.
+ */
+u32 xsave_cntxt_max_size;
+
+/* A 64-bit bitmask of the XSAVE/XRSTOR features supported in processor. */
+u32 xfeature_low, xfeature_high;
+
+void xsave_init(void)
+{
+    u32 eax, ebx, ecx, edx;
+    int cpu = smp_processor_id();
+
+    /* Processor Extended State Enumeration Main Leaf (EAX=0DH, ECX=0). */
+    cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
+
+    if ( cpu == 0 )
+    {
+        xsave_cntxt_max_size = ecx;
+        xfeature_low = eax;
+        xfeature_high = edx;
+
+        printk("%s: cntxt_max_size = 0x%x, available states: %08x:%08x\n",
+            __func__, xsave_cntxt_max_size, xfeature_high, xfeature_low);
+
+        if ( (xfeature_low & XSTATE_FPU_SSE) != XSTATE_FPU_SSE )
+        {
+            printk("%s: %s\n", __func__,
+                "FP/SSE not shown under xsave features");
+            BUG();
+        }
+
+        BUG_ON(xsave_cntxt_max_size < (512 + 64) );
+    }
+    else
+    {
+        BUG_ON(xsave_cntxt_max_size != ecx);
+        BUG_ON(xfeature_low != eax);
+        BUG_ON(xfeature_high != edx);
+    }
+
+    set_in_cr4(X86_CR4_OSXSAVE);
+    xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FPU_SSE);
+
+    printk("%s: done on cpu%d.\n", __func__, cpu);
+}
+
+void xsave_init_save_area(void *save_area)
+{
+    memset(save_area, 0, xsave_cntxt_max_size);
+
+    
+    ((u16 *)save_area)[0] = 0x37f;   /* FCW   */
+    ((u16 *)save_area)[2] = 0xffff;  /* FTW   */
+    ((u32 *)save_area)[6] = 0x1f80;  /* MXCSR */
+
+    ((struct xsave_struct *)save_area)->xsave_hdr.xstate_bv = XSTATE_FPU_SSE;
+}
+
+/*
  * Local variables:
  * mode: C
  * c-set-style: "BSD"
diff -r e7c421510be9 xen/include/asm-x86/cpufeature.h
--- a/xen/include/asm-x86/cpufeature.h	Mon Nov 24 13:57:48 2008 +0000
+++ b/xen/include/asm-x86/cpufeature.h	Tue Nov 25 14:39:39 2008 +0800
@@ -94,6 +94,8 @@
 #define X86_FEATURE_SSE4_2	(4*32+20) /* Streaming SIMD Extensions 4.2 */
 #define X86_FEATURE_X2APIC	(4*32+21) /* Extended xAPIC */
 #define X86_FEATURE_POPCNT	(4*32+23) /* POPCNT instruction */
+#define X86_FEATURE_XSAVE	(4*32+26) /* XSAVE */
+#define X86_FEATURE_OSXSAVE	(4*32+27) /* OSXSAVE */
 #define X86_FEATURE_HYPERVISOR	(4*32+31) /* Running under some hypervisor */
 
 /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
@@ -185,6 +187,9 @@
                                  && boot_cpu_has(X86_FEATURE_FFXSR))
 
 #define cpu_has_x2apic          boot_cpu_has(X86_FEATURE_X2APIC)
+
+#define cpu_has_xsave           boot_cpu_has(X86_FEATURE_XSAVE)
+
 #endif /* __ASM_I386_CPUFEATURE_H */
 
 /* 
diff -r e7c421510be9 xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h	Mon Nov 24 13:57:48 2008 +0000
+++ b/xen/include/asm-x86/domain.h	Tue Nov 25 19:17:06 2008 +0800
@@ -294,6 +294,15 @@ struct arch_vcpu
     struct vcpu_guest_context guest_context
     __attribute__((__aligned__(16)));
 
+    /*
+     * The save area for Processor Extended States and the bitmask of the
+     * XSAVE/XRSTOR features. They are used by: 1) when a vcpu (which has
+     * dirtied FPU/SSE) is scheduled out we XSAVE the states here; 2) in
+     * #NM handler, we XRSTOR the states we XSAVE-ed;
+     */
+    void *xsave_area;
+    uint64_t xfeature_mask;
+
     struct pae_l3_cache pae_l3_cache;
 
     unsigned long      flags; /* TF_ */
diff -r e7c421510be9 xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h	Mon Nov 24 13:57:48 2008 +0000
+++ b/xen/include/asm-x86/hvm/hvm.h	Tue Nov 25 14:39:39 2008 +0800
@@ -262,7 +262,8 @@ static inline int hvm_do_pmu_interrupt(s
        (X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD |       \
         X86_CR4_DE  | X86_CR4_PSE | X86_CR4_PAE |       \
         X86_CR4_MCE | X86_CR4_PGE | X86_CR4_PCE |       \
-        X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT)))
+        X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT |           \
+        (cpu_has_xsave ? X86_CR4_OSXSAVE : 0))))
 
 /* These exceptions must always be intercepted. */
 #define HVM_TRAP_MASK (1U << TRAP_machine_check)
diff -r e7c421510be9 xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h	Mon Nov 24 13:57:48 2008 +0000
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h	Tue Nov 25 14:39:39 2008 +0800
@@ -104,6 +104,7 @@ void vmx_realmode(struct cpu_user_regs *
 #define EXIT_REASON_EPT_VIOLATION       48
 #define EXIT_REASON_EPT_MISCONFIG       49
 #define EXIT_REASON_WBINVD              54
+#define EXIT_REASON_XSETBV              55
 
 /*
  * Interruption-information format
diff -r e7c421510be9 xen/include/asm-x86/i387.h
--- a/xen/include/asm-x86/i387.h	Mon Nov 24 13:57:48 2008 +0000
+++ b/xen/include/asm-x86/i387.h	Tue Nov 25 14:39:39 2008 +0800
@@ -13,6 +13,69 @@
 
 #include <xen/sched.h>
 #include <asm/processor.h>
+
+struct xsave_hdr_struct
+{
+   u64 xstate_bv;
+   u64 reserved[7];
+} __attribute__((packed));
+
+struct xsave_struct
+{
+    struct { char x[512]; } fpu_ctxt; /* FPU/MMX, SSE */
+    struct xsave_hdr_struct xsave_hdr;
+    char   data[];
+} __attribute__ ((packed, aligned (64)));
+
+#define XSTATE_FPU      (1 << 0)
+#define XSTATE_SSE      (1 << 1)
+#define XSTATE_FPU_SSE  (XSTATE_FPU | XSTATE_SSE)
+
+#ifdef CONFIG_X86_64
+#define REX_PREFIX "0x48, "
+#else
+#define REX_PREFIX
+#endif
+
+extern unsigned int xsave_cntxt_max_size;
+extern u32 xfeature_low, xfeature_high;
+
+extern void xsave_init(void);
+extern void xsave_init_save_area(void *save_area);
+
+#define XCR_XFEATURE_ENABLED_MASK   0
+
+static inline void xsetbv(u32 index, u64 xfeature_mask)
+{
+    u32 xfeature_hi = xfeature_mask >> 32;
+    u32 xfeature_lo = (u32)xfeature_mask;
+
+    __asm__ __volatile__ (".byte 0x0f, 0x01, 0xd1" :: "c" (index),
+            "a" (xfeature_lo), "d" (xfeature_hi));
+}
+
+static inline void xsave(void *save_area, u64 xfeature_mask)
+{
+    u32 xfeature_hi = xfeature_mask >> 32;
+    u32 xfeature_lo = (u32)xfeature_mask;
+    struct xsave_struct *ptr = (struct xsave_struct *)save_area;
+
+    __asm__ __volatile__ (".byte " REX_PREFIX "0x0f, 0xae, 0x27"
+        : "=m"(*ptr)
+        : "a" (xfeature_lo), "d" (xfeature_hi), "D"(ptr)
+        : "memory");
+}
+
+static inline void xrstor(void *save_area, u64 xfeature_mask)
+{
+    u32 xfeature_hi = xfeature_mask >> 32;
+    u32 xfeature_lo = (u32)xfeature_mask;
+    struct xsave_struct *ptr = (struct xsave_struct *)save_area;
+
+    __asm__ __volatile__ (".byte " REX_PREFIX "0x0f, 0xae, 0x2f"
+        :
+        : "m" (*ptr), "a" (xfeature_lo), "d" (xfeature_hi), "D"(ptr));
+}
 
 extern void init_fpu(void);
 extern void save_init_fpu(struct vcpu *v);
@@ -36,10 +99,20 @@ static inline void setup_fpu(struct vcpu
     if ( !v->fpu_dirtied )
     {
         v->fpu_dirtied = 1;
-        if ( v->fpu_initialised )
-            restore_fpu(v);
+        if ( cpu_has_xsave)
+        {
+            if ( !current->fpu_initialised )
+                current->fpu_initialised = 1;
+            xsetbv(XCR_XFEATURE_ENABLED_MASK, v->arch.xfeature_mask);
+            xrstor(v->arch.xsave_area, v->arch.xfeature_mask);
+        }
         else
-            init_fpu();
+        {
+            if ( v->fpu_initialised )
+                restore_fpu(v);
+            else
+                init_fpu();
+        }
     }
 }
 
diff -r e7c421510be9 xen/include/asm-x86/processor.h
--- a/xen/include/asm-x86/processor.h	Mon Nov 24 13:57:48 2008 +0000
+++ b/xen/include/asm-x86/processor.h	Tue Nov 25 14:39:39 2008 +0800
@@ -83,6 +83,7 @@
 #define X86_CR4_OSXMMEXCPT	0x0400	/* enable unmasked SSE exceptions */
 #define X86_CR4_VMXE		0x2000  /* enable VMX */
 #define X86_CR4_SMXE		0x4000  /* enable SMX */
+#define X86_CR4_OSXSAVE	0x40000 /* enable XSAVE/XRSTOR */
 
 /*
  * Trap/fault mnemonics.

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 9+ messages in thread
* [PATCH] Add xsave/xrstor support to Xen
@ 2008-05-28 12:02 Cui, Dexuan
  2008-05-28 12:06 ` Cui, Dexuan
  0 siblings, 1 reply; 9+ messages in thread
From: Cui, Dexuan @ 2008-05-28 12:02 UTC (permalink / raw)
  To: Keir Fraser, xen-devel

[-- Attachment #1: Type: text/plain, Size: 800 bytes --]

The attached patch adds the support of xsave/xrstor infrastructure for
x86.
xsave/xrstor manages the existing and future processor extended states
in x86 architecture.

The XSAVE/XRSTOR/XGETBV/XSETBV instructions and the Processor Extended
State are defined in the Intel SDMs:
http://www.intel.com/products/processor/manuals/

The basic ideas of the patch are:
1) enable the xsave/xrstor feature when Xen boots;
2) xsave/xrstor the related processor states (i.e., FPU/MMX, SSE) on
vcpu context switch;
3) with the xsave/xrstor feature enabled, Xen doesn't intercept HVM
vcpu's #NM at all, and Xen still intercepts PV vcpu's #NM and forwards
it into PV vcpu if necessary;
4) xsave/xrstor-aware HVM guest is supported in the patch. 

Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>

[-- Attachment #2: xsave-b.patch --]
[-- Type: application/octet-stream, Size: 14380 bytes --]

diff -r 542897539045 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c	Wed May 28 10:05:57 2008 +0100
+++ b/xen/arch/x86/domain.c	Wed May 28 18:01:38 2008 +0800
@@ -394,6 +394,19 @@ int vcpu_initialise(struct vcpu *v)
 
     paging_vcpu_init(v);
 
+    if ( cpu_has_xsave && !is_idle_vcpu(v) )
+    {
+        /* XSAVE/XRSTOR require the save area be 64-byte aligned. */
+        v->arch.xsave_area = _xmalloc(xsave_cntxt_max_size, 64);
+        if ( v->arch.xsave_area == NULL )
+            return -ENOMEM; 
+        ASSERT((63 & (long)v->arch.xsave_area) == 0);
+
+        /* By default, we always xsave/xrstor FPU/MMX and SSE. */
+        v->arch.xfeature_mask = XSTATE_FPU_SSE;
+        xsave_init_save_area(v->arch.xsave_area);
+    }
+
     if ( is_hvm_domain(d) )
     {
         if ( (rc = hvm_vcpu_initialise(v)) != 0 )
@@ -437,6 +450,9 @@ void vcpu_destroy(struct vcpu *v)
 
     if ( is_hvm_vcpu(v) )
         hvm_vcpu_destroy(v);
+
+    if ( v->arch.xsave_area != NULL )
+        xfree(v->arch.xsave_area);
 }
 
 int arch_domain_create(struct domain *d, unsigned int domcr_flags)
@@ -1307,12 +1323,38 @@ static void __context_switch(void)
         memcpy(&p->arch.guest_context.user_regs,
                stack_regs,
                CTXT_SWITCH_STACK_BYTES);
-        unlazy_fpu(p);
+
+        if ( !cpu_has_xsave )
+            unlazy_fpu(p);
+        else
+        {
+            /* XSAVE would #NM if CR0.TS = 1. We clear TS to avoid #NM. */
+            if ( read_cr0() & X86_CR0_TS )
+                clts();
+            xsave(p->arch.xsave_area, p->arch.xfeature_mask);
+        }
+
         p->arch.ctxt_switch_from(p);
     }
 
     if ( !is_idle_vcpu(n) )
     {
+        if ( cpu_has_xsave )
+        {
+            /* XRSTOR would #NM if CR0.TS = 1. We clear TS to avoid #NM. */
+            if ( read_cr0() & X86_CR0_TS )
+                clts();
+            xsetbv(n->arch.xfeature_mask);
+            xrstor(n->arch.xsave_area, n->arch.xfeature_mask);
+
+            /*
+             * PV guest OS may need a #NM injected to setup fpu for a
+             * process inside it.
+             */
+            if ( !is_hvm_vcpu(n) )
+                stts();
+        }
+
         memcpy(stack_regs,
                &n->arch.guest_context.user_regs,
                CTXT_SWITCH_STACK_BYTES);
diff -r 542897539045 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c	Wed May 28 10:05:57 2008 +0100
+++ b/xen/arch/x86/hvm/hvm.c	Wed May 28 18:01:38 2008 +0800
@@ -40,6 +40,7 @@
 #include <asm/processor.h>
 #include <asm/types.h>
 #include <asm/msr.h>
+#include <asm/i387.h>
 #include <asm/mc146818rtc.h>
 #include <asm/spinlock.h>
 #include <asm/hvm/hvm.h>
@@ -1600,6 +1601,7 @@ void hvm_cpuid(unsigned int input, unsig
                                    unsigned int *ecx, unsigned int *edx)
 {
     struct vcpu *v = current;
+    unsigned int count = *ecx;
 
     if ( cpuid_hypervisor_leaves(input, eax, ebx, ecx, edx) )
         return;
@@ -1613,6 +1615,21 @@ void hvm_cpuid(unsigned int input, unsig
         *ebx |= (v->vcpu_id * 2) << 24;
         if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
             __clear_bit(X86_FEATURE_APIC & 31, edx);
+
+        /* Fix up XSAVE and OSXSAVE. */
+        *ecx &= ~(bitmaskof(X86_FEATURE_XSAVE) |
+                  bitmaskof(X86_FEATURE_OSXSAVE));
+        if ( cpu_has_xsave )
+        {
+            *ecx |= bitmaskof(X86_FEATURE_XSAVE);
+            *ecx |= (current->arch.hvm_vcpu.guest_cr[4] & X86_CR4_OSXSAVE) ?
+                     bitmaskof(X86_FEATURE_OSXSAVE) : 0;
+        }
+    }
+    else if ( (input == 0x0000000D) && cpu_has_xsave )
+    /* Fix up "Processor Extended State Enumeration". */
+    { 
+        cpuid_count(0x0D, count, eax, ebx, ecx, edx);
     }
 }
 
diff -r 542897539045 xen/arch/x86/hvm/vmx/vmcs.c
--- a/xen/arch/x86/hvm/vmx/vmcs.c	Wed May 28 10:05:57 2008 +0100
+++ b/xen/arch/x86/hvm/vmx/vmcs.c	Wed May 28 18:01:38 2008 +0800
@@ -618,7 +618,7 @@ static int construct_vmcs(struct vcpu *v
     __vmwrite(EXCEPTION_BITMAP,
               HVM_TRAP_MASK
               | (paging_mode_hap(d) ? 0 : (1U << TRAP_page_fault))
-              | (1U << TRAP_no_device));
+              | (cpu_has_xsave ? 0 : (1U << TRAP_no_device)));
 
     v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_PE | X86_CR0_ET;
     hvm_update_guest_cr(v, 0);
diff -r 542897539045 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c	Wed May 28 10:05:57 2008 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c	Wed May 28 18:01:38 2008 +0800
@@ -651,8 +651,14 @@ static int vmx_load_vmcs_ctxt(struct vcp
 
 static void vmx_fpu_enter(struct vcpu *v)
 {
-    setup_fpu(v);
-    __vm_clear_bit(EXCEPTION_BITMAP, TRAP_no_device);
+    if ( cpu_has_xsave )
+        clts();
+    else
+    {
+        setup_fpu(v);
+        __vm_clear_bit(EXCEPTION_BITMAP, TRAP_no_device);
+    }
+
     v->arch.hvm_vmx.host_cr0 &= ~X86_CR0_TS;
     __vmwrite(HOST_CR0, v->arch.hvm_vmx.host_cr0);
 }
@@ -660,13 +666,18 @@ static void vmx_fpu_leave(struct vcpu *v
 static void vmx_fpu_leave(struct vcpu *v)
 {
     ASSERT(!v->fpu_dirtied);
-    ASSERT(read_cr0() & X86_CR0_TS);
+
+    if ( !cpu_has_xsave )
+        ASSERT((read_cr0() & X86_CR0_TS));
 
     if ( !(v->arch.hvm_vmx.host_cr0 & X86_CR0_TS) )
     {
         v->arch.hvm_vmx.host_cr0 |= X86_CR0_TS;
         __vmwrite(HOST_CR0, v->arch.hvm_vmx.host_cr0);
     }
+
+    if ( cpu_has_xsave )
+        return;
 
     /*
      * If the guest does not have TS enabled then we must cause and handle an
@@ -984,7 +995,7 @@ static void vmx_update_guest_cr(struct v
             vmx_update_guest_cr(v, 4);
         }
 
-        if ( !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
+        if ( !cpu_has_xsave && !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
         {
             if ( v != current )
                 hw_cr0_mask |= X86_CR0_TS;
@@ -1207,6 +1218,9 @@ void start_vmx(void)
 {
     static int bootstrapped;
 
+    if ( cpu_has_xsave )
+        xsave_init();
+
     vmx_save_host_msrs();
 
     if ( bootstrapped )
@@ -2095,6 +2109,7 @@ asmlinkage void vmx_vmexit_handler(struc
             domain_pause_for_debugger();
             break;
         case TRAP_no_device:
+            BUG_ON(cpu_has_xsave);
             vmx_fpu_dirty_intercept();
             break;
         case TRAP_page_fault:
@@ -2261,6 +2276,23 @@ asmlinkage void vmx_vmexit_handler(struc
         break;
     }
 
+    case EXIT_REASON_XSETBV:
+    {
+        if ( ((regs->eax ^ xfeature_low) & ~xfeature_low) ||
+             ((regs->edx ^ xfeature_high) & ~xfeature_high) )
+        {
+            vmx_inject_hw_exception(v, TRAP_gp_fault, 0); 
+            break;
+        }
+
+        inst_len = __get_instruction_length();
+        __update_guest_eip(inst_len);
+
+        v->arch.xfeature_mask = regs->eax | (((uint64_t)regs->edx) << 32);
+        xsetbv(v->arch.xfeature_mask);
+        break;
+    }
+
     default:
     exit_and_crash:
         gdprintk(XENLOG_ERR, "Bad vmexit (reason %x)\n", exit_reason);
diff -r 542897539045 xen/arch/x86/i387.c
--- a/xen/arch/x86/i387.c	Wed May 28 10:05:57 2008 +0100
+++ b/xen/arch/x86/i387.c	Wed May 28 18:01:38 2008 +0800
@@ -129,6 +129,56 @@ void restore_fpu(struct vcpu *v)
 }
 
 /*
+ * Maximum size (bytes) of the XSAVE/XRSTOR save area required by all
+ * supported features in processor. This includes the size needed for the
+ * 64-byte XSAVE.HRADER.
+ */
+u32 xsave_cntxt_max_size;
+
+/* A 64-bit bitmask of the XSAVE/XRSTOR features supported in processor. */
+u32 xfeature_low, xfeature_high;
+
+void xsave_init(void)
+{
+    u32 eax, ebx, ecx, edx;
+    int cpu = smp_processor_id();
+
+    /* Processor Extended State Enumeration Main Leaf (EAX=0DH, ECX=0). */
+    cpuid_count(0x0D, 0, &eax, &ebx, &ecx, &edx);
+
+    if ( cpu == 0 )
+    {
+        xsave_cntxt_max_size = ecx;
+        xfeature_low = eax;
+        xfeature_high = edx;
+
+        BUG_ON((xfeature_low & 3) != 3); /* We require FPU/MMX, SSE. */
+        BUG_ON(xsave_cntxt_max_size < 512+64);
+    }
+    else
+    {
+        BUG_ON(xsave_cntxt_max_size != ecx);
+        BUG_ON(xfeature_low != eax);
+        BUG_ON(xfeature_high != edx);
+    }
+
+    set_in_cr4(X86_CR4_OSXSAVE);
+
+    printk("xsave: xsave_init() done on cpu%d.\n", cpu);
+}
+
+void xsave_init_save_area(void *save_area)
+{
+    memset(save_area, 0, xsave_cntxt_max_size);
+
+    
+    ((u16 *)save_area)[0] = 0x37f;   /* FCW   */
+    ((u32 *)save_area)[6] = 0x1f80;  /* MXCSR */
+
+    ((struct xsave_struct *)save_area)->xsave_hdr.xstate_bv = XSTATE_FPU_SSE;
+}
+
+/*
  * Local variables:
  * mode: C
  * c-set-style: "BSD"
diff -r 542897539045 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c	Wed May 28 10:05:57 2008 +0100
+++ b/xen/arch/x86/traps.c	Wed May 28 18:01:38 2008 +0800
@@ -1234,7 +1234,7 @@ long do_fpu_taskswitch(int set)
     else
     {
         v->arch.guest_context.ctrlreg[0] &= ~X86_CR0_TS;
-        if ( v->fpu_dirtied )
+        if ( cpu_has_xsave || v->fpu_dirtied )
             clts();
     }
 
@@ -2770,7 +2770,10 @@ asmlinkage void do_device_not_available(
 
     BUG_ON(!guest_mode(regs));
 
-    setup_fpu(curr);
+    if ( cpu_has_xsave )
+        clts();
+    else
+        setup_fpu(curr);
 
     if ( curr->arch.guest_context.ctrlreg[0] & X86_CR0_TS )
     {
diff -r 542897539045 xen/include/asm-x86/cpufeature.h
--- a/xen/include/asm-x86/cpufeature.h	Wed May 28 10:05:57 2008 +0100
+++ b/xen/include/asm-x86/cpufeature.h	Wed May 28 18:01:38 2008 +0800
@@ -94,6 +94,8 @@
 #define X86_FEATURE_SSE4_2	(4*32+20) /* Streaming SIMD Extensions 4.2 */
 #define X86_FEATURE_X2APIC	(4*32+21) /* Extended xAPIC */
 #define X86_FEATURE_POPCNT	(4*32+23) /* POPCNT instruction */
+#define X86_FEATURE_XSAVE   (4*32+26) /* XSAVE */
+#define X86_FEATURE_OSXSAVE (4*32+27) /* OSXSAVE */
 
 /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
 #define X86_FEATURE_XSTORE	(5*32+ 2) /* on-CPU RNG present (xstore insn) */
@@ -184,6 +186,9 @@
                                  && boot_cpu_has(X86_FEATURE_FFXSR))
 
 #define cpu_has_x2apic          boot_cpu_has(X86_FEATURE_X2APIC)
+
+#define cpu_has_xsave           boot_cpu_has(X86_FEATURE_XSAVE)
+
 #endif /* __ASM_I386_CPUFEATURE_H */
 
 /* 
diff -r 542897539045 xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h	Wed May 28 10:05:57 2008 +0100
+++ b/xen/include/asm-x86/domain.h	Wed May 28 18:01:38 2008 +0800
@@ -280,6 +280,9 @@ struct arch_vcpu
     struct vcpu_guest_context guest_context
     __attribute__((__aligned__(16)));
 
+    void *xsave_area;       /* The Save area of Processor Extended State. */
+    uint64_t xfeature_mask; /* The bitmask of the XSAVE/XRSTOR features.  */
+
     struct pae_l3_cache pae_l3_cache;
 
     unsigned long      flags; /* TF_ */
diff -r 542897539045 xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h	Wed May 28 10:05:57 2008 +0100
+++ b/xen/include/asm-x86/hvm/hvm.h	Wed May 28 18:01:38 2008 +0800
@@ -257,7 +257,8 @@ static inline int hvm_do_pmu_interrupt(s
        (X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD |       \
         X86_CR4_DE  | X86_CR4_PSE | X86_CR4_PAE |       \
         X86_CR4_MCE | X86_CR4_PGE | X86_CR4_PCE |       \
-        X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT)))
+        X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT |           \
+        (cpu_has_xsave ? X86_CR4_OSXSAVE : 0))))
 
 /* These exceptions must always be intercepted. */
 #define HVM_TRAP_MASK (1U << TRAP_machine_check)
diff -r 542897539045 xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h	Wed May 28 10:05:57 2008 +0100
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h	Wed May 28 18:01:38 2008 +0800
@@ -101,6 +101,8 @@ void vmx_realmode(struct cpu_user_regs *
 #define EXIT_REASON_EPT_MISCONFIG       49
 #define EXIT_REASON_WBINVD              54
 
+#define EXIT_REASON_XSETBV              55
+
 /*
  * Interruption-information format
  */
diff -r 542897539045 xen/include/asm-x86/i387.h
--- a/xen/include/asm-x86/i387.h	Wed May 28 10:05:57 2008 +0100
+++ b/xen/include/asm-x86/i387.h	Wed May 28 18:01:38 2008 +0800
@@ -43,4 +43,69 @@ static inline void setup_fpu(struct vcpu
     }
 }
 
+struct xsave_hdr_struct
+{
+   u64 xstate_bv;
+   u64 reserved1;
+   u16 rev_id;
+   u8  reserved2[14];
+   u64 reserved3[4];
+} __attribute__((packed));
+
+struct xsave_struct
+{
+    struct { char x[512]; } fpu_ctxt; /* FPU/MMX, SSE */
+    struct xsave_hdr_struct xsave_hdr;
+    char   data[];
+} __attribute__ ((packed, aligned (64)));
+
+#define XSTATE_FPU      (1 << 0)
+#define XSTATE_SSE      (1 << 1)
+#define XSTATE_FPU_SSE  (XSTATE_FPU | XSTATE_SSE)
+
+#ifdef CONFIG_X86_64
+#define REX_PREFIX "0x48, "
+#else
+#define REX_PREFIX
+#endif
+
+extern unsigned int xsave_cntxt_max_size;
+extern u32 xfeature_low, xfeature_high;
+
+extern void xsave_init(void);
+extern void xsave_init_save_area(void *save_area);
+
+static inline void xsetbv(u64 xfeature_mask)
+{
+    u32 xfeature_hi = xfeature_mask >> 32;
+    u32 xfeature_lo = (u32)xfeature_mask;
+
+    __asm__ __volatile__ (".byte 0x0f, 0x01, 0xd1" :: "c" (0),
+            "a" (xfeature_lo), "d" (xfeature_hi));
+}
+
+static inline void xsave(void *save_area, u64 xfeature_mask)
+{
+    u32 xfeature_hi = xfeature_mask >> 32;
+    u32 xfeature_lo = (u32)xfeature_mask;
+    struct xsave_struct *ptr = (struct xsave_struct *)save_area;
+
+    __asm__ __volatile__ (".byte " REX_PREFIX "0x0f, 0xae, 0x27"
+        : "=m"(*ptr)
+        : "a" (xfeature_lo), "d" (xfeature_hi), "D"(ptr)
+        : "memory");
+}
+
+static inline void xrstor(void *save_area, u64 xfeature_mask)
+{
+    u32 xfeature_hi = xfeature_mask >> 32;
+    u32 xfeature_lo = (u32)xfeature_mask;
+    struct xsave_struct *ptr = (struct xsave_struct *)save_area;
+
+    __asm__ __volatile__ (".byte " REX_PREFIX "0x0f, 0xae, 0x2f"
+        :
+        : "m" (*ptr), "a" (xfeature_lo), "d" (xfeature_hi), "D"(ptr));
+}
+
+
 #endif /* __ASM_I386_I387_H */
diff -r 542897539045 xen/include/asm-x86/processor.h
--- a/xen/include/asm-x86/processor.h	Wed May 28 10:05:57 2008 +0100
+++ b/xen/include/asm-x86/processor.h	Wed May 28 18:01:38 2008 +0800
@@ -83,6 +83,7 @@
 #define X86_CR4_OSXMMEXCPT	0x0400	/* enable unmasked SSE exceptions */
 #define X86_CR4_VMXE		0x2000  /* enable VMX */
 #define X86_CR4_SMXE		0x4000  /* enable SMX */
+#define X86_CR4_OSXSAVE	0x40000 /* enable XSAVE/XRSTOR */
 
 /*
  * Trap/fault mnemonics.

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2009-04-04  0:22 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-04  0:22 [PATCH] Add xsave/xrstor support to Xen yuhong
  -- strict thread matches above, loose matches on Subject: below --
2008-11-26  9:43 [PATCH] Add XSAVE/XRSTOR " Cui, Dexuan
2008-11-26 10:25 ` Keir Fraser
2008-11-26 11:22 ` Jan Beulich
2008-05-28 12:02 [PATCH] Add xsave/xrstor " Cui, Dexuan
2008-05-28 12:06 ` Cui, Dexuan
2008-05-28 12:42   ` Keir Fraser
2008-05-28 13:11     ` Cui, Dexuan
2008-05-28 13:37       ` Keir Fraser

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.