Skip to content

Commit ffd01c5

Browse files
yosrym93sean-jc
authored andcommitted
x86/svm: Add more LBRV test cases
Add tests exercising using LBR, disabling it, then running a guest which enables and uses LBR but does not disable it. Make sure that when LBRV is disabled by virtual host, the guest state correctly leaks into virtual host, but not when LBRV is enabled. This also exercises KVM disabling intercepts for LBRs in L2 but re-enabling them when exiting to L1. Signed-off-by: Yosry Ahmed <yosry.ahmed@linux.dev> Link: https://patch.msgid.link/20251110232642.633672-14-yosry.ahmed@linux.dev Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 114a564 commit ffd01c5

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

x86/svm_tests.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,11 +3031,14 @@ static __always_inline void get_lbr_ips(u64 *from, u64 *to)
30313031

30323032
extern u64 guest_branch0_from, guest_branch0_to;
30333033
extern u64 guest_branch2_from, guest_branch2_to;
3034+
extern u64 guest_branch3_from, guest_branch3_to;
30343035

30353036
extern u64 host_branch0_from, host_branch0_to;
30363037
extern u64 host_branch2_from, host_branch2_to;
30373038
extern u64 host_branch3_from, host_branch3_to;
30383039
extern 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

30403043
u64 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+
30983118
static 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) */
31603207
static 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

Comments
 (0)