Mailing List Archive

[xen-unstable] x86 xsave: supports xsave (CPUID:0xD) enumeration for all sub-leaves.
# HG changeset patch
# User Keir Fraser <keir@xen.org>
# Date 1293179982 0
# Node ID 920826e80bee78d725fc3758bc7e378734d85bb8
# Parent 26e7e6c6ff7f9775fb77f58ddc0454ef08a1a908
x86 xsave: supports xsave (CPUID:0xD) enumeration for all sub-leaves.

In specific, it fixes the following issues:

1. The sub-leaves of CPUID:0x0000000D aren't contiguous. Hypervisor
shouldn't use register values to stop the enumeration. This patch
moves checking on XSAVE sub-leaves out of if-else statement. It also
bumps up sub-leaves to 63.
2. It creates a common function for xsave.
3. The main leaf 0 of CPUID:0x0000000D in current Xen is broken,
especially ECX and EBX registers. This patch cleans it up.
4. It adds support to detects EBX value of CPUID:0x0000000D main leaf
0 on-the-fly.

Signed-off-by: Wei Huang2 <wei.huang2@amd.com>
---
tools/libxc/xc_cpuid_x86.c | 114 +++++++++++++++++++++++++--------------------
xen/arch/x86/hvm/hvm.c | 18 +++++++
2 files changed, 83 insertions(+), 49 deletions(-)

diff -r 26e7e6c6ff7f -r 920826e80bee tools/libxc/xc_cpuid_x86.c
--- a/tools/libxc/xc_cpuid_x86.c Fri Dec 24 08:38:22 2010 +0000
+++ b/tools/libxc/xc_cpuid_x86.c Fri Dec 24 08:39:42 2010 +0000
@@ -160,6 +160,58 @@ static void intel_xc_cpuid_policy(
case 0x80000008:
/* Mask AMD Number of Cores information. */
regs[2] = 0;
+ break;
+ }
+}
+
+#define XSAVEOPT (1 << 0)
+/* Configure extended state enumeration leaves (0x0000000D for xsave) */
+static void xc_cpuid_config_xsave(
+ xc_interface *xch, domid_t domid, uint64_t xfeature_mask,
+ const unsigned int *input, unsigned int *regs)
+{
+ if ( xfeature_mask == 0 )
+ {
+ regs[0] = regs[1] = regs[2] = regs[3] = 0;
+ return;
+ }
+
+ switch ( input[1] )
+ {
+ case 0:
+ /* EAX: low 32bits of xfeature_enabled_mask */
+ regs[0] = xfeature_mask & 0xFFFFFFFF;
+ /* EDX: high 32bits of xfeature_enabled_mask */
+ regs[3] = (xfeature_mask >> 32) & 0xFFFFFFFF;
+ /* ECX: max size required by all HW features */
+ {
+ unsigned int _input[2] = {0xd, 0x0}, _regs[4];
+ regs[2] = 0;
+ for ( _input[1] = 2; _input[1] < 64; _input[1]++ )
+ {
+ cpuid(_input, _regs);
+ if ( (_regs[0] + _regs[1]) > regs[2] )
+ regs[2] = _regs[0] + _regs[1];
+ }
+ }
+ /* EBX: max size required by enabled features.
+ * This register contains a dynamic value, which varies when a guest
+ * enables or disables XSTATE features (via xsetbv). The default size
+ * after reset is 576. */
+ regs[1] = 512 + 64; /* FP/SSE + XSAVE.HEADER */
+ break;
+ case 1: /* leaf 1 */
+ regs[0] &= XSAVEOPT;
+ regs[1] = regs[2] = regs[3] = 0;
+ break;
+ case 2 ... 63: /* sub-leaves */
+ if ( !(xfeature_mask & (1ULL << input[1])) )
+ {
+ regs[0] = regs[1] = regs[2] = regs[3] = 0;
+ break;
+ }
+ /* Don't touch EAX, EBX. Also cleanup ECX and EDX */
+ regs[2] = regs[3] = 0;
break;
}
}
@@ -244,43 +296,7 @@ static void xc_cpuid_hvm_policy(
break;

case 0x0000000d:
-#define XSTATE_FP (1 << 0)
-#define XSTATE_SSE (1 << 1)
-#define XSTATE_YMM (1 << 2)
-#define XSAVEOPT (1 << 0)
-#define XSTATE_YMM_SIZE 256
- if ( xfeature_mask == 0 )
- {
- regs[0] = regs[1] = regs[2] = regs[3] = 0;
- break;
- }
- switch ( input[1] )
- {
- case 0:
- /* We only enable the features we know. */
- regs[0] = xfeature_mask;
- /* FP/SSE + XSAVE.HEADER + YMM. */
- regs[2] = 512 + 64;
- if ( regs[0] & XSTATE_YMM )
- regs[2] += XSTATE_YMM_SIZE;
- regs[1] = regs[2];
- regs[3] = 0;
- break;
- case 1:
- regs[0] &= XSAVEOPT;
- regs[1] = regs[2] = regs[3] = 0;
- break;
- case 2:
- if ( !(xfeature_mask & XSTATE_YMM) )
- break;
- regs[0] = XSTATE_YMM_SIZE;
- regs[1] = 512 + 64; /* FP/SSE + XSAVE.HEADER */
- regs[2] = regs[3] = 0;
- break;
- default:
- regs[0] = regs[1] = regs[2] = regs[3] = 0;
- break;
- }
+ xc_cpuid_config_xsave(xch, domid, xfeature_mask, input, regs);
break;

case 0x80000000:
@@ -501,20 +517,20 @@ int xc_cpuid_apply_policy(xc_interface *
rc = xc_cpuid_do_domctl(xch, domid, input, regs);
if ( rc )
return rc;
-
- /* Intel cache descriptor leaves. */
- if ( input[0] == 4 )
- {
- input[1]++;
- /* More to do? Then loop keeping %%eax==0x00000004. */
- if ( (regs[0] & 0x1f) != 0 )
- continue;
- }
-
- /* XSAVE information, subleaves 0-2. */
- if ( (input[0] == 0xd) && (input[1]++ < 2) )
+ }
+
+ /* Intel cache descriptor leaves. */
+ if ( input[0] == 4 )
+ {
+ input[1]++;
+ /* More to do? Then loop keeping %%eax==0x00000004. */
+ if ( (regs[0] & 0x1f) != 0 )
continue;
}
+
+ /* XSAVE information, subleaves 0-63. */
+ if ( (input[0] == 0xd) && (input[1]++ < 63) )
+ continue;

input[0]++;
if ( !(input[0] & 0x80000000u) && (input[0] > base_max ) )
diff -r 26e7e6c6ff7f -r 920826e80bee xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c Fri Dec 24 08:38:22 2010 +0000
+++ b/xen/arch/x86/hvm/hvm.c Fri Dec 24 08:39:42 2010 +0000
@@ -2144,6 +2144,24 @@ void hvm_cpuid(unsigned int input, unsig
/* Fix the x2APIC identifier. */
*edx = v->vcpu_id * 2;
break;
+ case 0xd:
+ {
+ unsigned int sub_leaf, _eax, _ebx, _ecx, _edx;
+ /* EBX value of main leaf 0 depends on enabled xsave features */
+ if ( count == 0 && v->arch.xcr0 )
+ {
+ for ( sub_leaf = 2;
+ (sub_leaf < 64) && (v->arch.xcr0 & (1ULL << sub_leaf));
+ sub_leaf++ )
+ {
+ domain_cpuid(v->domain, input, sub_leaf, &_eax, &_ebx, &_ecx,
+ &_edx);
+ if ( (_eax + _ebx) > *ebx )
+ *ebx = _eax + _ebx;
+ }
+ }
+ break;
+ }
case 0x80000001:
/* We expose RDTSCP feature to guest only when
tsc_mode == TSC_MODE_DEFAULT and host_tsc_is_safe() returns 1 */

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