From: Like Xu <likexu@xxxxxxxxxxx> Specifying an unsupported PMC encoding will cause a #GP(0). There are multiple reasons RDPMC can #GP, the one that is being relied on to guarantee #GP is specifically that the PMC is invalid. The most extensible solution is to provide a safe variant. Suggested-by: Sean Christopherson <seanjc@xxxxxxxxxx> Signed-off-by: Like Xu <likexu@xxxxxxxxxxx> --- lib/x86/processor.h | 21 ++++++++++++++++++--- x86/pmu.c | 10 ++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/x86/processor.h b/lib/x86/processor.h index f85abe3..cb396ed 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -438,11 +438,26 @@ static inline int wrmsr_safe(u32 index, u64 val) return exception_vector(); } -static inline uint64_t rdpmc(uint32_t index) +static inline int rdpmc_safe(u32 index, uint64_t *val) { uint32_t a, d; - asm volatile ("rdpmc" : "=a"(a), "=d"(d) : "c"(index)); - return a | ((uint64_t)d << 32); + + asm volatile (ASM_TRY("1f") + "rdpmc\n\t" + "1:" + : "=a"(a), "=d"(d) : "c"(index) : "memory"); + *val = (uint64_t)a | ((uint64_t)d << 32); + return exception_vector(); +} + +static inline uint64_t rdpmc(uint32_t index) +{ + uint64_t val; + int vector = rdpmc_safe(index, &val); + + assert_msg(!vector, "Unexpected %s on RDPMC(%d)", + exception_mnemonic(vector), index); + return val; } static inline int write_cr0_safe(ulong val) diff --git a/x86/pmu.c b/x86/pmu.c index 15572e3..d0de196 100644 --- a/x86/pmu.c +++ b/x86/pmu.c @@ -651,12 +651,22 @@ static void set_ref_cycle_expectations(void) gp_events[2].max = (gp_events[2].max * cnt.count) / tsc_delta; } +static void check_invalid_rdpmc_gp(void) +{ + uint64_t val; + + report(rdpmc_safe(64, &val) == GP_VECTOR, + "Expected #GP on RDPMC(64)"); +} + int main(int ac, char **av) { setup_vm(); handle_irq(PC_VECTOR, cnt_overflow); buf = malloc(N*64); + check_invalid_rdpmc_gp(); + if (!pmu_version()) { report_skip("No Intel Arch PMU is detected!"); return report_summary(); -- 2.38.1