aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxc/xc_cpuid_x86.c
diff options
context:
space:
mode:
authorKeir Fraser <keir@xen.org>2010-12-24 08:39:42 +0000
committerKeir Fraser <keir@xen.org>2010-12-24 08:39:42 +0000
commit25121ee23d3fef8cead4e56ece10f8e1ce7cbf09 (patch)
tree68f115d9e7f4c2ed018031b8e364363026fb8499 /tools/libxc/xc_cpuid_x86.c
parent96727f714845b5c2ea034860f3773e46612adc39 (diff)
downloadxen-25121ee23d3fef8cead4e56ece10f8e1ce7cbf09.tar.gz
xen-25121ee23d3fef8cead4e56ece10f8e1ce7cbf09.tar.bz2
xen-25121ee23d3fef8cead4e56ece10f8e1ce7cbf09.zip
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>
Diffstat (limited to 'tools/libxc/xc_cpuid_x86.c')
-rw-r--r--tools/libxc/xc_cpuid_x86.c112
1 files changed, 64 insertions, 48 deletions
diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c
index 6b5a915b0a..c94a816184 100644
--- a/tools/libxc/xc_cpuid_x86.c
+++ b/tools/libxc/xc_cpuid_x86.c
@@ -164,6 +164,58 @@ static void intel_xc_cpuid_policy(
}
}
+#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;
+ }
+}
+
static void xc_cpuid_hvm_policy(
xc_interface *xch, domid_t domid,
const unsigned int *input, unsigned int *regs)
@@ -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,21 +517,21 @@ int xc_cpuid_apply_policy(xc_interface *xch, domid_t domid)
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 ) )
input[0] = 0x80000000u;