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>
This commit is contained in:
Keir Fraser committed 2010-12-24 08:39:42 +00:00
1 parent 96727f7148
commit 25121ee23d
2 files changed
+82 -48

No files matched your search

+64 -48
View File
@@ -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;
+18
View File
@@ -2144,6 +2144,24 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
/* 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 */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.