mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
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:
1 parent
96727f7148
commit
25121ee23d
2 files changed
+82
-48
No files matched your search
+64
-48
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||