|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 7/8] x86emul: support RDPRU
While the PM doesn't say so, this assumes that the MPERF value read this
way gets scaled similarly to its reading through RDMSR.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
v3: New.
--- a/tools/libxl/libxl_cpuid.c
+++ b/tools/libxl/libxl_cpuid.c
@@ -257,6 +257,7 @@ int libxl_cpuid_parse_config(libxl_cpuid
{"invtsc", 0x80000007, NA, CPUID_REG_EDX, 8, 1},
+ {"rdpru", 0x80000008, NA, CPUID_REG_EBX, 4, 1},
{"wbnoinvd", 0x80000008, NA, CPUID_REG_EBX, 9, 1},
{"ibpb", 0x80000008, NA, CPUID_REG_EBX, 12, 1},
{"nc", 0x80000008, NA, CPUID_REG_ECX, 0, 8},
--- a/tools/misc/xen-cpuid.c
+++ b/tools/misc/xen-cpuid.c
@@ -146,6 +146,8 @@ static const char *const str_e8b[32] =
{
[ 0] = "clzero",
+ [ 4] = "rdpru",
+
/* [ 8] */ [ 9] = "wbnoinvd",
[12] = "ibpb",
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -671,6 +671,13 @@ static int read_msr(
{
switch ( reg )
{
+ case 0x000000e8: /* APERF */
+ case 0xc00000e8: /* APERF_RD_ONLY */
+#define APERF_LO_VALUE 0xAEAEAEAE
+#define APERF_HI_VALUE 0xEAEAEAEA
+ *val = ((uint64_t)APERF_HI_VALUE << 32) | APERF_LO_VALUE;
+ return X86EMUL_OKAY;
+
case 0xc0000080: /* EFER */
*val = ctxt->addr_size > 32 ? 0x500 /* LME|LMA */ : 0;
return X86EMUL_OKAY;
@@ -2226,6 +2233,30 @@ int main(int argc, char **argv)
goto fail;
printf("okay\n");
+ printf("%-40s", "Testing rdpru...");
+ instr[0] = 0x0f; instr[1] = 0x01; instr[2] = 0xfd;
+ regs.eip = (unsigned long)&instr[0];
+ regs.ecx = 1;
+ regs.eflags = EFLAGS_ALWAYS_SET;
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) ||
+ (regs.eax != APERF_LO_VALUE) || (regs.edx != APERF_HI_VALUE) ||
+ !(regs.eflags & X86_EFLAGS_CF) ||
+ (regs.eip != (unsigned long)&instr[3]) )
+ goto fail;
+ if ( ctxt.cpuid->extd.rdpru_max < 0xffff )
+ {
+ regs.eip = (unsigned long)&instr[0];
+ regs.ecx = ctxt.cpuid->extd.rdpru_max + 1;
+ regs.eflags = EFLAGS_ALWAYS_SET | X86_EFLAGS_CF;
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) || regs.eax || regs.edx ||
+ (regs.eflags & X86_EFLAGS_CF) ||
+ (regs.eip != (unsigned long)&instr[3]) )
+ goto fail;
+ }
+ printf("okay\n");
+
printf("%-40s", "Testing movq %mm3,(%ecx)...");
if ( stack_exec && cpu_has_mmx )
{
--- a/tools/tests/x86_emulator/x86-emulate.c
+++ b/tools/tests/x86_emulator/x86-emulate.c
@@ -79,6 +79,8 @@ bool emul_test_init(void)
cp.feat.movdiri = true;
cp.feat.movdir64b = true;
cp.extd.clzero = true;
+ cp.extd.rdpru = true;
+ cp.extd.rdpru_max = 1;
if ( cpu_has_xsave )
{
@@ -151,11 +153,11 @@ int emul_test_cpuid(
}
/*
- * The emulator doesn't itself use CLZERO, so we can always run the
+ * The emulator doesn't itself use CLZERO/RDPRU, so we can always run the
* respective test(s).
*/
if ( leaf == 0x80000008 )
- res->b |= 1U << 0;
+ res->b |= (1U << 0) | (1U << 4);
return X86EMUL_OKAY;
}
--- a/xen/arch/x86/cpuid.c
+++ b/xen/arch/x86/cpuid.c
@@ -545,6 +545,11 @@ void recalculate_cpuid_policy(struct dom
p->extd.maxlinaddr = p->extd.lm ? 48 : 32;
+ if ( p->extd.rdpru )
+ p->extd.rdpru_max = min(p->extd.rdpru_max, max->extd.rdpru_max);
+ else
+ p->extd.rdpru_max = 0;
+
recalculate_xstate(p);
recalculate_misc(p);
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -1872,6 +1872,7 @@ in_protmode(
#define vcpu_has_fma4() (ctxt->cpuid->extd.fma4)
#define vcpu_has_tbm() (ctxt->cpuid->extd.tbm)
#define vcpu_has_clzero() (ctxt->cpuid->extd.clzero)
+#define vcpu_has_rdpru() (ctxt->cpuid->extd.rdpru)
#define vcpu_has_wbnoinvd() (ctxt->cpuid->extd.wbnoinvd)
#define vcpu_has_bmi1() (ctxt->cpuid->feat.bmi1)
@@ -5670,6 +5671,52 @@ x86_emulate(
limit -= sizeof(zero);
}
break;
+
+ case 0xfd: /* rdpru */
+ vcpu_must_have(rdpru);
+
+ if ( !mode_ring0() )
+ {
+ fail_if(!ops->read_cr);
+ if ( (rc = ops->read_cr(4, &cr4, ctxt)) != X86EMUL_OKAY )
+ goto done;
+ generate_exception_if(cr4 & X86_CR4_TSD, EXC_UD);
+ }
+
+ switch ( _regs.ecx )
+ {
+ case 0: n = MSR_IA32_MPERF; break;
+ case 1: n = MSR_IA32_APERF; break;
+ default: n = 0; break;
+ }
+ if ( _regs.ecx > ctxt->cpuid->extd.rdpru_max )
+ n = 0;
+
+ _regs.eflags &= ~EFLAGS_MASK;
+ if ( n )
+ {
+ fail_if(!ops->read_msr);
+ switch ( rc = ops->read_msr(n, &msr_val, ctxt) )
+ {
+ case X86EMUL_OKAY:
+ _regs.eflags |= X86_EFLAGS_CF;
+ break;
+
+ case X86EMUL_EXCEPTION:
+ x86_emul_reset_event(ctxt);
+ rc = X86EMUL_OKAY;
+ break;
+
+ default:
+ goto done;
+ }
+ }
+
+ if ( !(_regs.eflags & X86_EFLAGS_CF) )
+ msr_val = 0;
+ _regs.r(dx) = msr_val >> 32;
+ _regs.r(ax) = (uint32_t)msr_val;
+ break;
}
#define _GRP7(mod, reg) \
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -246,6 +246,7 @@ XEN_CPUFEATURE(EFRO, 7*32+10) /
/* AMD-defined CPU features, CPUID level 0x80000008.ebx, word 8 */
XEN_CPUFEATURE(CLZERO, 8*32+ 0) /*A CLZERO instruction */
+XEN_CPUFEATURE(RDPRU, 8*32+ 4) /*A RDPRU instruction */
XEN_CPUFEATURE(WBNOINVD, 8*32+ 9) /* WBNOINVD instruction */
XEN_CPUFEATURE(IBPB, 8*32+12) /*A IBPB support only (no IBRS, used
by AMD) */
--- a/xen/include/xen/lib/x86/cpuid.h
+++ b/xen/include/xen/lib/x86/cpuid.h
@@ -259,7 +259,8 @@ struct cpuid_policy
uint32_t e8b;
struct { DECL_BITFIELD(e8b); };
};
- uint32_t /* c */:32, /* d */:32;
+ uint32_t /* c */:32;
+ uint16_t :16, rdpru_max;
};
} extd;
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |