14
14
15
15
#define N 1000000
16
16
17
- // These values match the number of instructions and branches in the
18
- // assembly block in check_emulated_instr().
19
- #define EXPECTED_INSTR 17
20
- #define EXPECTED_BRNCH 5
21
-
22
17
#define IBPB_JMP_INSNS 9
23
18
#define IBPB_JMP_BRANCHES 2
24
19
@@ -71,6 +66,40 @@ do { \
71
66
: "edi"); \
72
67
} while (0)
73
68
69
+ /* the number of instructions and branches of the kvm_fep_asm() blob */
70
+ #define KVM_FEP_INSNS 22
71
+ #define KVM_FEP_BRANCHES 5
72
+
73
+ /*
74
+ * KVM_FEP is a magic prefix that forces emulation so
75
+ * 'KVM_FEP "jne label\n"' just counts as a single instruction.
76
+ */
77
+ #define kvm_fep_asm (_wrmsr ) \
78
+ do { \
79
+ asm volatile( \
80
+ _wrmsr "\n\t" \
81
+ "mov %%ecx, %%edi;\n\t" \
82
+ "mov $0x0, %%eax;\n\t" \
83
+ "cmp $0x0, %%eax;\n\t" \
84
+ KVM_FEP "jne 1f\n\t" \
85
+ KVM_FEP "jne 1f\n\t" \
86
+ KVM_FEP "jne 1f\n\t" \
87
+ KVM_FEP "jne 1f\n\t" \
88
+ KVM_FEP "jne 1f\n\t" \
89
+ "mov $0xa, %%eax; cpuid;\n\t" \
90
+ "mov $0xa, %%eax; cpuid;\n\t" \
91
+ "mov $0xa, %%eax; cpuid;\n\t" \
92
+ "mov $0xa, %%eax; cpuid;\n\t" \
93
+ "mov $0xa, %%eax; cpuid;\n\t" \
94
+ "1: mov %%edi, %%ecx; \n\t" \
95
+ "xor %%eax, %%eax; \n\t" \
96
+ "xor %%edx, %%edx;\n\t" \
97
+ _wrmsr "\n\t" \
98
+ : \
99
+ : "a"(eax), "d"(edx), "c"(ecx) \
100
+ : "ebx", "edi"); \
101
+ } while (0)
102
+
74
103
typedef struct {
75
104
uint32_t ctr ;
76
105
uint32_t idx ;
@@ -668,13 +697,15 @@ static void check_running_counter_wrmsr(void)
668
697
669
698
static void check_emulated_instr (void )
670
699
{
700
+ u32 eax , edx , ecx ;
671
701
uint64_t status , instr_start , brnch_start ;
672
702
uint64_t gp_counter_width = (1ull << pmu .gp_counter_width ) - 1 ;
673
703
unsigned int branch_idx = pmu .is_intel ?
674
704
INTEL_BRANCHES_IDX : AMD_BRANCHES_IDX ;
675
705
unsigned int instruction_idx = pmu .is_intel ?
676
706
INTEL_INSTRUCTIONS_IDX :
677
707
AMD_INSTRUCTIONS_IDX ;
708
+
678
709
pmu_counter_t brnch_cnt = {
679
710
.ctr = MSR_GP_COUNTERx (0 ),
680
711
/* branch instructions */
@@ -690,55 +721,46 @@ static void check_emulated_instr(void)
690
721
if (this_cpu_has_perf_global_status ())
691
722
pmu_clear_global_status ();
692
723
693
- start_event (& brnch_cnt );
694
- start_event (& instr_cnt );
724
+ __start_event (& brnch_cnt , 0 );
725
+ __start_event (& instr_cnt , 0 );
695
726
696
- brnch_start = - EXPECTED_BRNCH ;
697
- instr_start = - EXPECTED_INSTR ;
727
+ brnch_start = - KVM_FEP_BRANCHES ;
728
+ instr_start = - KVM_FEP_INSNS ;
698
729
wrmsr (MSR_GP_COUNTERx (0 ), brnch_start & gp_counter_width );
699
730
wrmsr (MSR_GP_COUNTERx (1 ), instr_start & gp_counter_width );
700
- // KVM_FEP is a magic prefix that forces emulation so
701
- // 'KVM_FEP "jne label\n"' just counts as a single instruction.
702
- asm volatile (
703
- "mov $0x0, %%eax\n"
704
- "cmp $0x0, %%eax\n"
705
- KVM_FEP "jne label\n"
706
- KVM_FEP "jne label\n"
707
- KVM_FEP "jne label\n"
708
- KVM_FEP "jne label\n"
709
- KVM_FEP "jne label\n"
710
- "mov $0xa, %%eax\n"
711
- "cpuid\n"
712
- "mov $0xa, %%eax\n"
713
- "cpuid\n"
714
- "mov $0xa, %%eax\n"
715
- "cpuid\n"
716
- "mov $0xa, %%eax\n"
717
- "cpuid\n"
718
- "mov $0xa, %%eax\n"
719
- "cpuid\n"
720
- "label:\n"
721
- :
722
- :
723
- : "eax" , "ebx" , "ecx" , "edx" );
724
731
725
- if (this_cpu_has_perf_global_ctrl ())
726
- wrmsr (pmu .msr_global_ctl , 0 );
732
+ if (this_cpu_has_perf_global_ctrl ()) {
733
+ eax = BIT (0 ) | BIT (1 );
734
+ ecx = pmu .msr_global_ctl ;
735
+ edx = 0 ;
736
+ kvm_fep_asm ("wrmsr" );
737
+ } else {
738
+ eax = ecx = edx = 0 ;
739
+ kvm_fep_asm ("nop" );
740
+ }
727
741
728
- stop_event (& brnch_cnt );
729
- stop_event (& instr_cnt );
742
+ __stop_event (& brnch_cnt );
743
+ __stop_event (& instr_cnt );
730
744
731
745
// Check that the end count - start count is at least the expected
732
746
// number of instructions and branches.
733
- report (instr_cnt .count - instr_start >= EXPECTED_INSTR ,
734
- "instruction count" );
735
- report (brnch_cnt .count - brnch_start >= EXPECTED_BRNCH ,
736
- "branch count" );
747
+ if (this_cpu_has_perf_global_ctrl ()) {
748
+ report (instr_cnt .count - instr_start == KVM_FEP_INSNS ,
749
+ "instruction count" );
750
+ report (brnch_cnt .count - brnch_start == KVM_FEP_BRANCHES ,
751
+ "branch count" );
752
+ } else {
753
+ report (instr_cnt .count - instr_start >= KVM_FEP_INSNS ,
754
+ "instruction count" );
755
+ report (brnch_cnt .count - brnch_start >= KVM_FEP_BRANCHES ,
756
+ "branch count" );
757
+ }
758
+
737
759
if (this_cpu_has_perf_global_status ()) {
738
760
// Additionally check that those counters overflowed properly.
739
761
status = rdmsr (pmu .msr_global_status );
740
- report (status & 1 , "branch counter overflow" );
741
- report (status & 2 , "instruction counter overflow" );
762
+ report (status & BIT_ULL ( 0 ) , "branch counter overflow" );
763
+ report (status & BIT_ULL ( 1 ) , "instruction counter overflow" );
742
764
}
743
765
744
766
report_prefix_pop ();
0 commit comments