@@ -66,7 +66,7 @@ static bool_t __read_mostly full_width_write;
#define ARCH_CNTR_PIN_CONTROL (1ULL << 19)
/* Number of general-purpose and fixed performance counters */
-static unsigned int __read_mostly arch_pmc_cnt, fixed_pmc_cnt;
+unsigned int __read_mostly arch_pmc_cnt, fixed_pmc_cnt;
/* Masks used for testing whether and MSR is valid */
#define ARCH_CTRL_MASK (~((1ull << 32) - 1) | (1ull << 21) | ARCH_CNTR_PIN_CONTROL)
@@ -304,9 +304,42 @@ void guest_cpuid(const struct vcpu *v, uint32_t leaf,
*res = EMPTY_LEAF;
else
{
- /* Report at most v3 since that's all we currently emulate. */
- if ( (res->a & 0xff) > 3 )
- res->a = (res->a & ~0xff) | 3;
+ union {
+ uint32_t eax;
+ struct {
+ uint8_t version;
+ uint8_t general_nr;
+ uint8_t general_width;
+ uint8_t arch_nr;
+ };
+ } u;
+ u.eax = res->a;
+
+ /* Report at most VPMU_VERSION_MAX since that's all we currently emulate. */
+ if ( u.version > VPMU_VERSION_MAX ) {
+ gdprintk(XENLOG_WARNING, "Limiting PMU version to %d (actual %d)", VPMU_VERSION_MAX, u.version);
+ u.version = VPMU_VERSION_MAX;
+ }
+
+ if ( u.general_nr > arch_pmc_cnt ) {
+ gdprintk(XENLOG_WARNING, "Limiting general purpose PMU count to %d (actual %d)", arch_pmc_cnt, u.general_nr);
+ u.general_nr = arch_pmc_cnt;
+ }
+
+ if ( vpmu_features & (XENPMU_FEATURE_IPC_ONLY |
+ XENPMU_FEATURE_ARCH_ONLY) ) {
+ unsigned limit = ( vpmu_features & XENPMU_FEATURE_ARCH_ONLY ) ? 7 : 3;
+ if (limit < u.arch_nr) {
+ gdprintk(XENLOG_WARNING, "Limiting architectural PMU events to %d (actual %d)", limit, u.arch_nr);
+ u.arch_nr = limit;
+ }
+ }
+
+ res->a = u.eax;
+
+ /* We only implement 3 fixed function counters */
+ if ( (res->d & 0x1f) > fixed_pmc_cnt )
+ res->d = (res->d & ~0x1f) | fixed_pmc_cnt;
}
break;
@@ -74,6 +74,8 @@ struct vpmu_struct {
#define VPMU_CPU_HAS_DS 0x1000 /* Has Debug Store */
#define VPMU_CPU_HAS_BTS 0x2000 /* Has Branch Trace Store */
+#define VPMU_VERSION_MAX 0x3
+
static inline void vpmu_set(struct vpmu_struct *vpmu, const u32 mask)
{
vpmu->flags |= mask;
@@ -118,6 +120,8 @@ static inline int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
extern unsigned int vpmu_mode;
extern unsigned int vpmu_features;
+extern unsigned int arch_pmc_cnt;
+extern unsigned int fixed_pmc_cnt;
/* Context switch */
static inline void vpmu_switch_from(struct vcpu *prev)