Skip to content

Commit 114a564

Browse files
yosrym93sean-jc
authored andcommitted
x86/svm: Cleanup LBRV tests
In LBRV tests, failures in the guest trigger a #UD and do not convey useful debugging info (i.e. expected and actual values of MSRs). Also, a lot of macros are used to perform branch checks, obscuring the tests to an extent. Instead, add a helper to read the branch IPs, and remove the check macros. Consistently use TEST_EXPECT_EQ() in both virtual host and guest code, instead of a mix of report(), TEST_EXPECT_EQ(), and #UD. Opportunisitcally slightly reorder test checks to improve semantics, and replace the report(true, ..) calls that document the test with comments. Signed-off-by: Yosry Ahmed <yosry.ahmed@linux.dev> Link: https://patch.msgid.link/20251110232642.633672-13-yosry.ahmed@linux.dev Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 9a7a0e1 commit 114a564

File tree

1 file changed

+65
-73
lines changed

1 file changed

+65
-73
lines changed

x86/svm_tests.c

Lines changed: 65 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -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

30593042
static 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

30803067
static 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

31073098
static 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) */
31223117
static 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) */
31433138
static 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) */
31663160
static 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) */
31983190
static 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

Comments
 (0)