@@ -3031,11 +3031,14 @@ static __always_inline void get_lbr_ips(u64 *from, u64 *to)
30313031
30323032extern u64 guest_branch0_from , guest_branch0_to ;
30333033extern u64 guest_branch2_from , guest_branch2_to ;
3034+ extern u64 guest_branch3_from , guest_branch3_to ;
30343035
30353036extern u64 host_branch0_from , host_branch0_to ;
30363037extern u64 host_branch2_from , host_branch2_to ;
30373038extern u64 host_branch3_from , host_branch3_to ;
30383039extern u64 host_branch4_from , host_branch4_to ;
3040+ extern u64 host_branch5_from , host_branch5_to ;
3041+ extern u64 host_branch6_from , host_branch6_to ;
30393042
30403043u64 dbgctl ;
30413044
@@ -3095,6 +3098,23 @@ static void svm_lbrv_test_guest2(void)
30953098 asm volatile ("vmmcall\n" );
30963099}
30973100
3101+ static void svm_lbrv_test_guest3 (void )
3102+ {
3103+ /*
3104+ * This guest expects LBR to be disabled, it enables LBR and does a
3105+ * branch, then exits to L1 without disabling LBR or doing more
3106+ * branches.
3107+ */
3108+ dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
3109+ TEST_EXPECT_EQ (dbgctl , 0 );
3110+
3111+ wrmsr (MSR_IA32_DEBUGCTLMSR , DEBUGCTLMSR_LBR );
3112+ DO_BRANCH (guest_branch3 );
3113+
3114+ /* Do not call the vmmcall() fn to avoid overriding the last branch */
3115+ asm volatile ("vmmcall\n\t" );
3116+ }
3117+
30983118static void svm_lbrv_test0 (void )
30993119{
31003120 u64 from_ip , to_ip ;
@@ -3156,6 +3176,33 @@ static void svm_lbrv_test2(void)
31563176 TEST_EXPECT_EQ ((u64 )& guest_branch2_to , to_ip );
31573177}
31583178
3179+ /*
3180+ * Test that without LBRV enabled, enabling LBR in the guest then exiting will
3181+ * keep LBR enabled and 'leak' state to the host correctly.
3182+ */
3183+ static void svm_lbrv_test3 (void )
3184+ {
3185+ u64 from_ip , to_ip ;
3186+
3187+ svm_setup_vmrun ((u64 )svm_lbrv_test_guest3 );
3188+ vmcb -> control .virt_ext = 0 ;
3189+
3190+ wrmsr (MSR_IA32_DEBUGCTLMSR , DEBUGCTLMSR_LBR );
3191+ DO_BRANCH (host_branch5 );
3192+ wrmsr (MSR_IA32_DEBUGCTLMSR , 0 );
3193+
3194+ SVM_BARE_VMRUN ;
3195+ dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
3196+ wrmsr (MSR_IA32_DEBUGCTLMSR , 0 );
3197+ TEST_EXPECT_EQ (dbgctl , DEBUGCTLMSR_LBR );
3198+
3199+ TEST_EXPECT_EQ (vmcb -> control .exit_code , SVM_EXIT_VMMCALL );
3200+
3201+ get_lbr_ips (& from_ip , & to_ip );
3202+ TEST_EXPECT_EQ ((u64 )& guest_branch3_from , from_ip );
3203+ TEST_EXPECT_EQ ((u64 )& guest_branch3_to , to_ip );
3204+ }
3205+
31593206/* Test that with LBRV enabled, guest LBR state doesn't leak (1) */
31603207static void svm_lbrv_nested_test1 (void )
31613208{
@@ -3217,6 +3264,37 @@ static void svm_lbrv_nested_test2(void)
32173264 TEST_EXPECT_EQ ((u64 )& host_branch4_to , to_ip );
32183265}
32193266
3267+ /*
3268+ * Test that with LBRV enabled, enabling LBR in the guest then exiting does not
3269+ * 'leak' state to the host.
3270+ */
3271+ static void svm_lbrv_nested_test3 (void )
3272+ {
3273+ u64 from_ip , to_ip ;
3274+
3275+ if (!lbrv_supported ()) {
3276+ report_skip ("LBRV not supported in the guest" );
3277+ return ;
3278+ }
3279+
3280+ svm_setup_vmrun ((u64 )svm_lbrv_test_guest3 );
3281+ vmcb -> control .virt_ext = LBR_CTL_ENABLE_MASK ;
3282+ vmcb -> save .dbgctl = 0 ;
3283+
3284+ wrmsr (MSR_IA32_DEBUGCTLMSR , DEBUGCTLMSR_LBR );
3285+ DO_BRANCH (host_branch6 );
3286+ wrmsr (MSR_IA32_DEBUGCTLMSR , 0 );
3287+
3288+ SVM_BARE_VMRUN ;
3289+ dbgctl = rdmsr (MSR_IA32_DEBUGCTLMSR );
3290+ TEST_EXPECT_EQ (dbgctl , 0 );
3291+
3292+ TEST_EXPECT_EQ (vmcb -> control .exit_code , SVM_EXIT_VMMCALL );
3293+
3294+ get_lbr_ips (& from_ip , & to_ip );
3295+ TEST_EXPECT_EQ ((u64 )& host_branch6_from , from_ip );
3296+ TEST_EXPECT_EQ ((u64 )& host_branch6_to , to_ip );
3297+ }
32203298
32213299// test that a nested guest which does enable INTR interception
32223300// but doesn't enable virtual interrupt masking works
@@ -3622,8 +3700,10 @@ struct svm_test svm_tests[] = {
36223700 TEST (svm_lbrv_test0 ),
36233701 TEST (svm_lbrv_test1 ),
36243702 TEST (svm_lbrv_test2 ),
3703+ TEST (svm_lbrv_test3 ),
36253704 TEST (svm_lbrv_nested_test1 ),
36263705 TEST (svm_lbrv_nested_test2 ),
3706+ TEST (svm_lbrv_nested_test3 ),
36273707 TEST (svm_intr_intercept_mix_if ),
36283708 TEST (svm_intr_intercept_mix_gif ),
36293709 TEST (svm_intr_intercept_mix_gif2 ),
0 commit comments