diff options
author | Keir Fraser <keir@xen.org> | 2010-12-24 08:39:42 +0000 |
---|---|---|
committer | Keir Fraser <keir@xen.org> | 2010-12-24 08:39:42 +0000 |
commit | 25121ee23d3fef8cead4e56ece10f8e1ce7cbf09 (patch) | |
tree | 68f115d9e7f4c2ed018031b8e364363026fb8499 /tools/libxc/xc_cpuid_x86.c | |
parent | 96727f714845b5c2ea034860f3773e46612adc39 (diff) | |
download | xen-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.c | 112 |
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; |