@@ -3006,34 +3006,17 @@ static void svm_no_nm_test(void)
30063006 "fnop with CR0.TS and CR0.EM unset no #NM exception" );
30073007}
30083008
3009- static u64 amd_get_lbr_rip (u32 msr )
3009+ /* These functions have to be inlined to avoid affecting LBR registers */
3010+ static __always_inline u64 amd_get_lbr_rip (u32 msr )
30103011{
30113012 return rdmsr (msr ) & AMD_LBR_RECORD_IP_MASK ;
30123013}
30133014
3014- #define HOST_CHECK_LBR (from_expected , to_expected ) \
3015- do { \
3016- TEST_EXPECT_EQ((u64)from_expected, amd_get_lbr_rip(MSR_IA32_LASTBRANCHFROMIP)); \
3017- TEST_EXPECT_EQ((u64)to_expected, amd_get_lbr_rip(MSR_IA32_LASTBRANCHTOIP)); \
3018- } while (0)
3019-
3020- /*
3021- * FIXME: Do something other than generate an exception to communicate failure.
3022- * Debugging without expected vs. actual is an absolute nightmare.
3023- */
3024- #define GUEST_CHECK_LBR (from_expected , to_expected ) \
3025- do { \
3026- if ((u64)(from_expected) != amd_get_lbr_rip(MSR_IA32_LASTBRANCHFROMIP)) \
3027- asm volatile("ud2"); \
3028- if ((u64)(to_expected) != amd_get_lbr_rip(MSR_IA32_LASTBRANCHTOIP)) \
3029- asm volatile("ud2"); \
3030- } while (0)
3031-
3032- #define REPORT_GUEST_LBR_ERROR (vmcb ) \
3033- report(false, "LBR guest test failed. Exit reason 0x%x, RIP = %lx, from = %lx, to = %lx, ex from = %lx, ex to = %lx", \
3034- vmcb->control.exit_code, vmcb->save.rip, \
3035- vmcb->save.br_from, vmcb->save.br_to, \
3036- vmcb->save.last_excp_from, vmcb->save.last_excp_to)
3015+ static __always_inline void get_lbr_ips (u64 * from , u64 * to )
3016+ {
3017+ * from = amd_get_lbr_rip (MSR_IA32_LASTBRANCHFROMIP );
3018+ * to = amd_get_lbr_rip (MSR_IA32_LASTBRANCHTOIP );
3019+ }
30373020
30383021#define DO_BRANCH (branch_name ) \
30393022 asm volatile ( \
@@ -3058,55 +3041,64 @@ u64 dbgctl;
30583041
30593042static void svm_lbrv_test_guest1 (void )
30603043{
3044+ u64 from_ip , to_ip ;
3045+
30613046 /*
30623047 * This guest expects the LBR to be already enabled when it starts,
30633048 * it does a branch, and then disables the LBR and then checks.
30643049 */
3050+ dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
3051+ TEST_EXPECT_EQ (dbgctl , DEBUGCTLMSR_LBR );
30653052
30663053 DO_BRANCH (guest_branch0 );
30673054
3068- dbgctl = rdmsr ( MSR_IA32_DEBUGCTLMSR );
3055+ /* Disable LBR before the checks to avoid changing the last branch */
30693056 wrmsr (MSR_IA32_DEBUGCTLMSR , 0 );
3057+ dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
3058+ TEST_EXPECT_EQ (dbgctl , 0 );
30703059
3071- if (dbgctl != DEBUGCTLMSR_LBR )
3072- asm volatile ("ud2\n" );
3073- if (rdmsr (MSR_IA32_DEBUGCTLMSR ) != 0 )
3074- asm volatile ("ud2\n" );
3060+ get_lbr_ips (& from_ip , & to_ip );
3061+ TEST_EXPECT_EQ ((u64 )& guest_branch0_from , from_ip );
3062+ TEST_EXPECT_EQ ((u64 )& guest_branch0_to , to_ip );
30753063
3076- GUEST_CHECK_LBR (& guest_branch0_from , & guest_branch0_to );
30773064 asm volatile ("vmmcall\n" );
30783065}
30793066
30803067static void svm_lbrv_test_guest2 (void )
30813068{
3069+ u64 from_ip , to_ip ;
3070+
30823071 /*
30833072 * This guest expects the LBR to be disabled when it starts,
30843073 * enables it, does a branch, disables it and then checks.
30853074 */
3086-
3087- DO_BRANCH (guest_branch1 );
30883075 dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
3076+ TEST_EXPECT_EQ (dbgctl , 0 );
30893077
3090- if (dbgctl != 0 )
3091- asm volatile ("ud2\n" );
3078+ DO_BRANCH (guest_branch1 );
30923079
3093- GUEST_CHECK_LBR (& host_branch2_from , & host_branch2_to );
3080+ get_lbr_ips (& from_ip , & to_ip );
3081+ TEST_EXPECT_EQ ((u64 )& host_branch2_from , from_ip );
3082+ TEST_EXPECT_EQ ((u64 )& host_branch2_to , to_ip );
30943083
30953084 wrmsr (MSR_IA32_DEBUGCTLMSR , DEBUGCTLMSR_LBR );
30963085 dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
3086+ TEST_EXPECT_EQ (dbgctl , DEBUGCTLMSR_LBR );
3087+
30973088 DO_BRANCH (guest_branch2 );
30983089 wrmsr (MSR_IA32_DEBUGCTLMSR , 0 );
30993090
3100- if ( dbgctl != DEBUGCTLMSR_LBR )
3101- asm volatile ( "ud2\n" );
3102- GUEST_CHECK_LBR ( & guest_branch2_from , & guest_branch2_to );
3091+ get_lbr_ips ( & from_ip , & to_ip );
3092+ TEST_EXPECT_EQ (( u64 ) & guest_branch2_from , from_ip );
3093+ TEST_EXPECT_EQ (( u64 ) & guest_branch2_to , to_ip );
31033094
31043095 asm volatile ("vmmcall\n" );
31053096}
31063097
31073098static void svm_lbrv_test0 (void )
31083099{
3109- report (true, "Basic LBR test" );
3100+ u64 from_ip , to_ip ;
3101+
31103102 wrmsr (MSR_IA32_DEBUGCTLMSR , DEBUGCTLMSR_LBR );
31113103 DO_BRANCH (host_branch0 );
31123104 dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
@@ -3116,12 +3108,15 @@ static void svm_lbrv_test0(void)
31163108 dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
31173109 TEST_EXPECT_EQ (dbgctl , 0 );
31183110
3119- HOST_CHECK_LBR (& host_branch0_from , & host_branch0_to );
3111+ get_lbr_ips (& from_ip , & to_ip );
3112+ TEST_EXPECT_EQ ((u64 )& host_branch0_from , from_ip );
3113+ TEST_EXPECT_EQ ((u64 )& host_branch0_to , to_ip );
31203114}
31213115
3116+ /* Test that without LBRV enabled, guest LBR state does 'leak' to the host(1) */
31223117static void svm_lbrv_test1 (void )
31233118{
3124- report (true, "Test that without LBRV enabled, guest LBR state does 'leak' to the host(1)" ) ;
3119+ u64 from_ip , to_ip ;
31253120
31263121 svm_setup_vmrun ((u64 )svm_lbrv_test_guest1 );
31273122 vmcb -> control .virt_ext = 0 ;
@@ -3130,19 +3125,19 @@ static void svm_lbrv_test1(void)
31303125 DO_BRANCH (host_branch1 );
31313126 SVM_BARE_VMRUN ;
31323127 dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
3128+ TEST_EXPECT_EQ (dbgctl , 0 );
31333129
3134- if (vmcb -> control .exit_code != SVM_EXIT_VMMCALL ) {
3135- REPORT_GUEST_LBR_ERROR (vmcb );
3136- return ;
3137- }
3130+ TEST_EXPECT_EQ (vmcb -> control .exit_code , SVM_EXIT_VMMCALL );
31383131
3139- TEST_EXPECT_EQ (dbgctl , 0 );
3140- HOST_CHECK_LBR (& guest_branch0_from , & guest_branch0_to );
3132+ get_lbr_ips (& from_ip , & to_ip );
3133+ TEST_EXPECT_EQ ((u64 )& guest_branch0_from , from_ip );
3134+ TEST_EXPECT_EQ ((u64 )& guest_branch0_to , to_ip );
31413135}
31423136
3137+ /* Test that without LBRV enabled, guest LBR state does 'leak' to the host(2) */
31433138static void svm_lbrv_test2 (void )
31443139{
3145- report (true, "Test that without LBRV enabled, guest LBR state does 'leak' to the host(2)" ) ;
3140+ u64 from_ip , to_ip ;
31463141
31473142 svm_setup_vmrun ((u64 )svm_lbrv_test_guest2 );
31483143 vmcb -> control .virt_ext = 0 ;
@@ -3152,25 +3147,25 @@ static void svm_lbrv_test2(void)
31523147 wrmsr (MSR_IA32_DEBUGCTLMSR , 0 );
31533148 SVM_BARE_VMRUN ;
31543149 dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
3155- wrmsr ( MSR_IA32_DEBUGCTLMSR , 0 );
3150+ TEST_EXPECT_EQ ( dbgctl , 0 );
31563151
3157- if (vmcb -> control .exit_code != SVM_EXIT_VMMCALL ) {
3158- REPORT_GUEST_LBR_ERROR (vmcb );
3159- return ;
3160- }
3152+ TEST_EXPECT_EQ (vmcb -> control .exit_code , SVM_EXIT_VMMCALL );
31613153
3162- TEST_EXPECT_EQ (dbgctl , 0 );
3163- HOST_CHECK_LBR (& guest_branch2_from , & guest_branch2_to );
3154+ get_lbr_ips (& from_ip , & to_ip );
3155+ TEST_EXPECT_EQ ((u64 )& guest_branch2_from , from_ip );
3156+ TEST_EXPECT_EQ ((u64 )& guest_branch2_to , to_ip );
31643157}
31653158
3159+ /* Test that with LBRV enabled, guest LBR state doesn't leak (1) */
31663160static void svm_lbrv_nested_test1 (void )
31673161{
3162+ u64 from_ip , to_ip ;
3163+
31683164 if (!lbrv_supported ()) {
31693165 report_skip ("LBRV not supported in the guest" );
31703166 return ;
31713167 }
31723168
3173- report (true, "Test that with LBRV enabled, guest LBR state doesn't leak (1)" );
31743169 svm_setup_vmrun ((u64 )svm_lbrv_test_guest1 );
31753170 vmcb -> control .virt_ext = LBR_CTL_ENABLE_MASK ;
31763171 vmcb -> save .dbgctl = DEBUGCTLMSR_LBR ;
@@ -3181,28 +3176,26 @@ static void svm_lbrv_nested_test1(void)
31813176 dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
31823177 wrmsr (MSR_IA32_DEBUGCTLMSR , 0 );
31833178
3184- if (vmcb -> control .exit_code != SVM_EXIT_VMMCALL ) {
3185- REPORT_GUEST_LBR_ERROR (vmcb );
3186- return ;
3187- }
3188-
3189- if (vmcb -> save .dbgctl != 0 ) {
3190- report (false, "unexpected virtual guest MSR_IA32_DEBUGCTLMSR value 0x%lx" , vmcb -> save .dbgctl );
3191- return ;
3192- }
3179+ TEST_EXPECT_EQ (vmcb -> control .exit_code , SVM_EXIT_VMMCALL );
31933180
31943181 TEST_EXPECT_EQ (dbgctl , DEBUGCTLMSR_LBR );
3195- HOST_CHECK_LBR (& host_branch3_from , & host_branch3_to );
3182+ TEST_EXPECT_EQ (vmcb -> save .dbgctl , 0 );
3183+
3184+ get_lbr_ips (& from_ip , & to_ip );
3185+ TEST_EXPECT_EQ ((u64 )& host_branch3_from , from_ip );
3186+ TEST_EXPECT_EQ ((u64 )& host_branch3_to , to_ip );
31963187}
31973188
3189+ /* Test that with LBRV enabled, guest LBR state doesn't leak (2) */
31983190static void svm_lbrv_nested_test2 (void )
31993191{
3192+ u64 from_ip , to_ip ;
3193+
32003194 if (!lbrv_supported ()) {
32013195 report_skip ("LBRV not supported in the guest" );
32023196 return ;
32033197 }
32043198
3205- report (true, "Test that with LBRV enabled, guest LBR state doesn't leak (2)" );
32063199 svm_setup_vmrun ((u64 )svm_lbrv_test_guest2 );
32073200 vmcb -> control .virt_ext = LBR_CTL_ENABLE_MASK ;
32083201
@@ -3215,14 +3208,13 @@ static void svm_lbrv_nested_test2(void)
32153208 SVM_BARE_VMRUN ;
32163209 dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
32173210 wrmsr (MSR_IA32_DEBUGCTLMSR , 0 );
3211+ TEST_EXPECT_EQ (dbgctl , DEBUGCTLMSR_LBR );
32183212
3219- if (vmcb -> control .exit_code != SVM_EXIT_VMMCALL ) {
3220- REPORT_GUEST_LBR_ERROR (vmcb );
3221- return ;
3222- }
3213+ TEST_EXPECT_EQ (vmcb -> control .exit_code , SVM_EXIT_VMMCALL );
32233214
3224- TEST_EXPECT_EQ (dbgctl , DEBUGCTLMSR_LBR );
3225- HOST_CHECK_LBR (& host_branch4_from , & host_branch4_to );
3215+ get_lbr_ips (& from_ip , & to_ip );
3216+ TEST_EXPECT_EQ ((u64 )& host_branch4_from , from_ip );
3217+ TEST_EXPECT_EQ ((u64 )& host_branch4_to , to_ip );
32263218}
32273219
32283220
0 commit comments