1 #include "x86/msr.h" 2 #include "x86/processor.h" 3 #include "x86/desc.h" 4 5 #define N 1000000 6 #define MAX_NUM_LBR_ENTRY 32 7 #define DEBUGCTLMSR_LBR (1UL << 0) 8 #define PMU_CAP_LBR_FMT 0x3f 9 10 #define MSR_LBR_NHM_FROM 0x00000680 11 #define MSR_LBR_NHM_TO 0x000006c0 12 #define MSR_LBR_CORE_FROM 0x00000040 13 #define MSR_LBR_CORE_TO 0x00000060 14 #define MSR_LBR_TOS 0x000001c9 15 #define MSR_LBR_SELECT 0x000001c8 16 17 volatile int count; 18 19 static noinline int compute_flag(int i) 20 { 21 if (i % 10 < 4) 22 return i + 1; 23 return 0; 24 } 25 26 static noinline int lbr_test(void) 27 { 28 int i; 29 int flag; 30 volatile double x = 1212121212, y = 121212; 31 32 for (i = 0; i < 200000000; i++) { 33 flag = compute_flag(i); 34 count++; 35 if (flag) 36 x += x / y + y / x; 37 } 38 return 0; 39 } 40 41 union cpuid10_eax { 42 struct { 43 unsigned int version_id:8; 44 unsigned int num_counters:8; 45 unsigned int bit_width:8; 46 unsigned int mask_length:8; 47 } split; 48 unsigned int full; 49 } eax; 50 51 u32 lbr_from, lbr_to; 52 53 static void init_lbr(void *index) 54 { 55 wrmsr(lbr_from + *(int *) index, 0); 56 wrmsr(lbr_to + *(int *)index, 0); 57 } 58 59 static bool test_init_lbr_from_exception(u64 index) 60 { 61 return test_for_exception(GP_VECTOR, init_lbr, &index); 62 } 63 64 int main(int ac, char **av) 65 { 66 struct cpuid id = cpuid(10); 67 u64 perf_cap; 68 int max, i; 69 70 setup_vm(); 71 72 if (!is_intel()) { 73 report_skip("PMU_LBR test is for intel CPU's only"); 74 return 0; 75 } 76 77 perf_cap = rdmsr(MSR_IA32_PERF_CAPABILITIES); 78 eax.full = id.a; 79 80 if (!eax.split.version_id) { 81 printf("No pmu is detected!\n"); 82 return report_summary(); 83 } 84 if (!(perf_cap & PMU_CAP_LBR_FMT)) { 85 printf("No LBR is detected!\n"); 86 return report_summary(); 87 } 88 89 printf("PMU version: %d\n", eax.split.version_id); 90 printf("LBR version: %ld\n", perf_cap & PMU_CAP_LBR_FMT); 91 92 /* Look for LBR from and to MSRs */ 93 lbr_from = MSR_LBR_CORE_FROM; 94 lbr_to = MSR_LBR_CORE_TO; 95 if (test_init_lbr_from_exception(0)) { 96 lbr_from = MSR_LBR_NHM_FROM; 97 lbr_to = MSR_LBR_NHM_TO; 98 } 99 100 if (test_init_lbr_from_exception(0)) { 101 printf("LBR on this platform is not supported!\n"); 102 return report_summary(); 103 } 104 105 wrmsr(MSR_LBR_SELECT, 0); 106 wrmsr(MSR_LBR_TOS, 0); 107 for (max = 0; max < MAX_NUM_LBR_ENTRY; max++) { 108 if (test_init_lbr_from_exception(max)) 109 break; 110 } 111 112 report(max > 0, "The number of guest LBR entries is good."); 113 114 /* Do some branch instructions. */ 115 wrmsr(MSR_IA32_DEBUGCTLMSR, DEBUGCTLMSR_LBR); 116 lbr_test(); 117 wrmsr(MSR_IA32_DEBUGCTLMSR, 0); 118 119 report(rdmsr(MSR_LBR_TOS) != 0, "The guest LBR MSR_LBR_TOS value is good."); 120 for (i = 0; i < max; ++i) { 121 if (!rdmsr(lbr_to + i) || !rdmsr(lbr_from + i)) 122 break; 123 } 124 report(i == max, "The guest LBR FROM_IP/TO_IP values are good."); 125 126 return report_summary(); 127 } 128