blob: 3bd9e9fd396f05fef9f3208c7fd2d9f492c06859 [file] [log] [blame] [edit]
#include "x86/msr.h"
#include "x86/processor.h"
#include "x86/desc.h"
#define N 1000000
#define MAX_NUM_LBR_ENTRY 32
#define DEBUGCTLMSR_LBR (1UL << 0)
#define PMU_CAP_LBR_FMT 0x3f
#define MSR_LBR_NHM_FROM 0x00000680
#define MSR_LBR_NHM_TO 0x000006c0
#define MSR_LBR_CORE_FROM 0x00000040
#define MSR_LBR_CORE_TO 0x00000060
#define MSR_LBR_TOS 0x000001c9
#define MSR_LBR_SELECT 0x000001c8
volatile int count;
static __attribute__((noinline)) int compute_flag(int i)
{
if (i % 10 < 4)
return i + 1;
return 0;
}
static __attribute__((noinline)) int lbr_test(void)
{
int i;
int flag;
volatile double x = 1212121212, y = 121212;
for (i = 0; i < 200000000; i++) {
flag = compute_flag(i);
count++;
if (flag)
x += x / y + y / x;
}
return 0;
}
union cpuid10_eax {
struct {
unsigned int version_id:8;
unsigned int num_counters:8;
unsigned int bit_width:8;
unsigned int mask_length:8;
} split;
unsigned int full;
} eax;
u32 lbr_from, lbr_to;
static void init_lbr(void *index)
{
wrmsr(lbr_from + *(int *) index, 0);
wrmsr(lbr_to + *(int *)index, 0);
}
static bool test_init_lbr_from_exception(u64 index)
{
return test_for_exception(GP_VECTOR, init_lbr, &index);
}
int main(int ac, char **av)
{
struct cpuid id = cpuid(10);
u64 perf_cap;
int max, i;
setup_vm();
perf_cap = rdmsr(MSR_IA32_PERF_CAPABILITIES);
eax.full = id.a;
if (!eax.split.version_id) {
printf("No pmu is detected!\n");
return report_summary();
}
if (!(perf_cap & PMU_CAP_LBR_FMT)) {
printf("No LBR is detected!\n");
return report_summary();
}
printf("PMU version: %d\n", eax.split.version_id);
printf("LBR version: %ld\n", perf_cap & PMU_CAP_LBR_FMT);
/* Look for LBR from and to MSRs */
lbr_from = MSR_LBR_CORE_FROM;
lbr_to = MSR_LBR_CORE_TO;
if (test_init_lbr_from_exception(0)) {
lbr_from = MSR_LBR_NHM_FROM;
lbr_to = MSR_LBR_NHM_TO;
}
if (test_init_lbr_from_exception(0)) {
printf("LBR on this platform is not supported!\n");
return report_summary();
}
wrmsr(MSR_LBR_SELECT, 0);
wrmsr(MSR_LBR_TOS, 0);
for (max = 0; max < MAX_NUM_LBR_ENTRY; max++) {
if (test_init_lbr_from_exception(max))
break;
}
report(max > 0, "The number of guest LBR entries is good.");
/* Do some branch instructions. */
wrmsr(MSR_IA32_DEBUGCTLMSR, DEBUGCTLMSR_LBR);
lbr_test();
wrmsr(MSR_IA32_DEBUGCTLMSR, 0);
report(rdmsr(MSR_LBR_TOS) != 0, "The guest LBR MSR_LBR_TOS value is good.");
for (i = 0; i < max; ++i) {
if (!rdmsr(lbr_to + i) || !rdmsr(lbr_from + i))
break;
}
report(i == max, "The guest LBR FROM_IP/TO_IP values are good.");
return report_summary();
}