* [kvm-unit-tests PATCH v5 0/4] Add additional testing for routing L2 exceptions @ 2022-01-25 20:31 Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 1/4] x86: Make exception_mnemonic() visible to the tests Aaron Lewis ` (3 more replies) 0 siblings, 4 replies; 5+ messages in thread From: Aaron Lewis @ 2022-01-25 20:31 UTC (permalink / raw) To: kvm; +Cc: pbonzini, jmattson, seanjc, Aaron Lewis In a previous series testing was added to verify that when a #PF occured in L2 the exception was routed to the correct place. In this series other exceptions are tested (ie: #GP, #UD, #DE, #DB, #BP, #AC). v4 -> v5: - Removed vmx_exception_test from being able to be run on its own. It can only be run as a part of vmx now. - Removed vmx_exception_test from vmx in unittests.cfg. Having it in that list filters the test from running. With it removed it now runs as a part of vmx. - Split the commit for test_override_guest() and test_set_guest_finished() into two commits. - Fixed up vmx_l2_ac_test() and usermode_callback() based on feedback. v3 -> v4: - Add vmx_exception_test to vmx. v2 -> v3: - Commits 1 and 2 from v2 were accepted upstream (bug fixes). - Moved exception_mnemonic() into a separate commit. - Moved support for running a nested guest multiple times in one test into a separate commit. - Moved the test framework into the same commit as the test itself. - Simplified the test framework and test code based on Sean's recommendations. v1 -> v2: - Add guest_stack_top and guest_syscall_stack_top for aligning L2's stacks. - Refactor test to make it more extensible (ie: Added vmx_exception_tests array and framework around it). - Split test into 2 commits: 1. Test infrustructure. 2. Test cases. Aaron Lewis (4): x86: Make exception_mnemonic() visible to the tests x86: Add support for running a nested guest multiple times in one test x86: Add a helper to allow tests to signal completion without a vmcall() x86: Add test coverage for nested_vmx_reflect_vmexit() testing lib/x86/desc.c | 2 +- lib/x86/desc.h | 1 + x86/vmx.c | 24 ++++++++- x86/vmx.h | 2 + x86/vmx_tests.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+), 3 deletions(-) -- 2.35.0.rc0.227.g00780c9af4-goog ^ permalink raw reply [flat|nested] 5+ messages in thread
* [kvm-unit-tests PATCH v5 1/4] x86: Make exception_mnemonic() visible to the tests 2022-01-25 20:31 [kvm-unit-tests PATCH v5 0/4] Add additional testing for routing L2 exceptions Aaron Lewis @ 2022-01-25 20:31 ` Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 2/4] x86: Add support for running a nested guest multiple times in one test Aaron Lewis ` (2 subsequent siblings) 3 siblings, 0 replies; 5+ messages in thread From: Aaron Lewis @ 2022-01-25 20:31 UTC (permalink / raw) To: kvm; +Cc: pbonzini, jmattson, seanjc, Aaron Lewis exception_mnemonic() is a useful function for more than just desc.c. Make it global, so it can be used in other KUT tests. Signed-off-by: Aaron Lewis <aaronlewis@google.com> Reviewed-by: Sean Christopherson <seanjc@google.com> --- lib/x86/desc.c | 2 +- lib/x86/desc.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/x86/desc.c b/lib/x86/desc.c index 16b7256..c2eb16e 100644 --- a/lib/x86/desc.c +++ b/lib/x86/desc.c @@ -91,7 +91,7 @@ struct ex_record { extern struct ex_record exception_table_start, exception_table_end; -static const char* exception_mnemonic(int vector) +const char* exception_mnemonic(int vector) { switch(vector) { case 0: return "#DE"; diff --git a/lib/x86/desc.h b/lib/x86/desc.h index 9b81da0..ad6277b 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -224,6 +224,7 @@ void set_intr_alt_stack(int e, void *fn); void print_current_tss_info(void); handler handle_exception(u8 v, handler fn); void unhandled_exception(struct ex_regs *regs, bool cpu); +const char* exception_mnemonic(int vector); bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data), void *data); -- 2.35.0.rc0.227.g00780c9af4-goog ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [kvm-unit-tests PATCH v5 2/4] x86: Add support for running a nested guest multiple times in one test 2022-01-25 20:31 [kvm-unit-tests PATCH v5 0/4] Add additional testing for routing L2 exceptions Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 1/4] x86: Make exception_mnemonic() visible to the tests Aaron Lewis @ 2022-01-25 20:31 ` Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 3/4] x86: Add a helper to allow tests to signal completion without a vmcall() Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 4/4] x86: Add test coverage for nested_vmx_reflect_vmexit() testing Aaron Lewis 3 siblings, 0 replies; 5+ messages in thread From: Aaron Lewis @ 2022-01-25 20:31 UTC (permalink / raw) To: kvm; +Cc: pbonzini, jmattson, seanjc, Aaron Lewis KUT has a limit of only being able to run one nested guest per vmx test. This is limiting and not necessary. Add support for allowing a test to run guest code multiple times. Signed-off-by: Aaron Lewis <aaronlewis@google.com> --- x86/vmx.c | 19 +++++++++++++++++-- x86/vmx.h | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/x86/vmx.c b/x86/vmx.c index f4fbb94..b2d8393 100644 --- a/x86/vmx.c +++ b/x86/vmx.c @@ -1884,15 +1884,30 @@ void test_add_teardown(test_teardown_func func, void *data) step->data = data; } +static void __test_set_guest(test_guest_func func) +{ + assert(current->v2); + v2_guest_main = func; +} + /* * Set the target of the first enter_guest call. Can only be called once per * test. Must be called before first enter_guest call. */ void test_set_guest(test_guest_func func) { - assert(current->v2); TEST_ASSERT_MSG(!v2_guest_main, "Already set guest func."); - v2_guest_main = func; + __test_set_guest(func); +} + +/* + * Set the target of the enter_guest call and reset the RIP so 'func' will + * start from the beginning. This can be called multiple times per test. + */ +void test_override_guest(test_guest_func func) +{ + __test_set_guest(func); + init_vmcs_guest(); } static void check_for_guest_termination(union exit_reason exit_reason) diff --git a/x86/vmx.h b/x86/vmx.h index 4423986..dabd5da 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -1055,6 +1055,7 @@ void hypercall(u32 hypercall_no); typedef void (*test_guest_func)(void); typedef void (*test_teardown_func)(void *data); void test_set_guest(test_guest_func func); +void test_override_guest(test_guest_func func); void test_add_teardown(test_teardown_func func, void *data); void test_skip(const char *msg); -- 2.35.0.rc0.227.g00780c9af4-goog ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [kvm-unit-tests PATCH v5 3/4] x86: Add a helper to allow tests to signal completion without a vmcall() 2022-01-25 20:31 [kvm-unit-tests PATCH v5 0/4] Add additional testing for routing L2 exceptions Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 1/4] x86: Make exception_mnemonic() visible to the tests Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 2/4] x86: Add support for running a nested guest multiple times in one test Aaron Lewis @ 2022-01-25 20:31 ` Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 4/4] x86: Add test coverage for nested_vmx_reflect_vmexit() testing Aaron Lewis 3 siblings, 0 replies; 5+ messages in thread From: Aaron Lewis @ 2022-01-25 20:31 UTC (permalink / raw) To: kvm; +Cc: pbonzini, jmattson, seanjc, Aaron Lewis Putting a vmcall() at the end of a nested test isn't always convenient to do, and isn't necessary. Add a helper to allow the nested test to make it possible to skip this requirement. Signed-off-by: Aaron Lewis <aaronlewis@google.com> --- x86/vmx.c | 5 +++++ x86/vmx.h | 1 + 2 files changed, 6 insertions(+) diff --git a/x86/vmx.c b/x86/vmx.c index b2d8393..51eed8c 100644 --- a/x86/vmx.c +++ b/x86/vmx.c @@ -1910,6 +1910,11 @@ void test_override_guest(test_guest_func func) init_vmcs_guest(); } +void test_set_guest_finished(void) +{ + guest_finished = 1; +} + static void check_for_guest_termination(union exit_reason exit_reason) { if (is_hypercall(exit_reason)) { diff --git a/x86/vmx.h b/x86/vmx.h index dabd5da..11cb665 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -1058,5 +1058,6 @@ void test_set_guest(test_guest_func func); void test_override_guest(test_guest_func func); void test_add_teardown(test_teardown_func func, void *data); void test_skip(const char *msg); +void test_set_guest_finished(void); #endif -- 2.35.0.rc0.227.g00780c9af4-goog ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [kvm-unit-tests PATCH v5 4/4] x86: Add test coverage for nested_vmx_reflect_vmexit() testing 2022-01-25 20:31 [kvm-unit-tests PATCH v5 0/4] Add additional testing for routing L2 exceptions Aaron Lewis ` (2 preceding siblings ...) 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 3/4] x86: Add a helper to allow tests to signal completion without a vmcall() Aaron Lewis @ 2022-01-25 20:31 ` Aaron Lewis 3 siblings, 0 replies; 5+ messages in thread From: Aaron Lewis @ 2022-01-25 20:31 UTC (permalink / raw) To: kvm; +Cc: pbonzini, jmattson, seanjc, Aaron Lewis Add a framework and test cases to ensure exceptions that occur in L2 are forwarded to the correct place by nested_vmx_reflect_vmexit(). Add testing for exceptions: #GP, #UD, #DE, #DB, #BP, and #AC. Signed-off-by: Aaron Lewis <aaronlewis@google.com> --- x86/vmx_tests.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 3d57ed6..796fd7b 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -21,6 +21,7 @@ #include "smp.h" #include "delay.h" #include "access.h" +#include "x86/usermode.h" #define VPID_CAP_INVVPID_TYPES_SHIFT 40 @@ -10701,6 +10702,134 @@ static void vmx_pf_vpid_test(void) __vmx_pf_vpid_test(invalidate_tlb_new_vpid, 1); } +static void vmx_l2_gp_test(void) +{ + *(volatile u64 *)NONCANONICAL = 0; +} + +static void vmx_l2_ud_test(void) +{ + asm volatile ("ud2"); +} + +static void vmx_l2_de_test(void) +{ + asm volatile ( + "xor %%eax, %%eax\n\t" + "xor %%ebx, %%ebx\n\t" + "xor %%edx, %%edx\n\t" + "idiv %%ebx\n\t" + ::: "eax", "ebx", "edx"); +} + +static void vmx_l2_bp_test(void) +{ + asm volatile ("int3"); +} + +static void vmx_l2_db_test(void) +{ + write_rflags(read_rflags() | X86_EFLAGS_TF); +} + +static uint64_t usermode_callback(void) +{ + /* + * Trigger an #AC by writing 8 bytes to a 4-byte aligned address. + * Disclaimer: It is assumed that the stack pointer is aligned + * on a 16-byte boundary as x86_64 stacks should be. + */ + asm volatile("movq $0, -0x4(%rsp)"); + + return 0; +} + +static void vmx_l2_ac_test(void) +{ + bool hit_ac = false; + + write_cr0(read_cr0() | X86_CR0_AM); + write_rflags(read_rflags() | X86_EFLAGS_AC); + + run_in_user(usermode_callback, AC_VECTOR, 0, 0, 0, 0, &hit_ac); + report(hit_ac, "Usermode #AC handled in L2"); + vmcall(); +} + +struct vmx_exception_test { + u8 vector; + void (*guest_code)(void); +}; + +struct vmx_exception_test vmx_exception_tests[] = { + { GP_VECTOR, vmx_l2_gp_test }, + { UD_VECTOR, vmx_l2_ud_test }, + { DE_VECTOR, vmx_l2_de_test }, + { DB_VECTOR, vmx_l2_db_test }, + { BP_VECTOR, vmx_l2_bp_test }, + { AC_VECTOR, vmx_l2_ac_test }, +}; + +static u8 vmx_exception_test_vector; + +static void vmx_exception_handler(struct ex_regs *regs) +{ + report(regs->vector == vmx_exception_test_vector, + "Handling %s in L2's exception handler", + exception_mnemonic(vmx_exception_test_vector)); + vmcall(); +} + +static void handle_exception_in_l2(u8 vector) +{ + handler old_handler = handle_exception(vector, vmx_exception_handler); + + vmx_exception_test_vector = vector; + + enter_guest(); + report(vmcs_read(EXI_REASON) == VMX_VMCALL, + "%s handled by L2", exception_mnemonic(vector)); + + handle_exception(vector, old_handler); +} + +static void handle_exception_in_l1(u32 vector) +{ + u32 old_eb = vmcs_read(EXC_BITMAP); + + vmcs_write(EXC_BITMAP, old_eb | (1u << vector)); + + enter_guest(); + + report((vmcs_read(EXI_REASON) == VMX_EXC_NMI) && + ((vmcs_read(EXI_INTR_INFO) & 0xff) == vector), + "%s handled by L1", exception_mnemonic(vector)); + + vmcs_write(EXC_BITMAP, old_eb); +} + +static void vmx_exception_test(void) +{ + struct vmx_exception_test *t; + int i; + + for (i = 0; i < ARRAY_SIZE(vmx_exception_tests); i++) { + t = &vmx_exception_tests[i]; + + /* + * Override the guest code before each run even though it's the + * same code, the VMCS guest state needs to be reinitialized. + */ + test_override_guest(t->guest_code); + handle_exception_in_l2(t->vector); + + test_override_guest(t->guest_code); + handle_exception_in_l1(t->vector); + } + + test_set_guest_finished(); +} + #define TEST(name) { #name, .v2 = name } /* name/init/guest_main/exit_handler/syscall_handler/guest_regs */ @@ -10810,5 +10939,6 @@ struct vmx_test vmx_tests[] = { TEST(vmx_pf_no_vpid_test), TEST(vmx_pf_invvpid_test), TEST(vmx_pf_vpid_test), + TEST(vmx_exception_test), { NULL, NULL, NULL, NULL, NULL, {0} }, }; -- 2.35.0.rc0.227.g00780c9af4-goog ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2022-01-25 20:32 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2022-01-25 20:31 [kvm-unit-tests PATCH v5 0/4] Add additional testing for routing L2 exceptions Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 1/4] x86: Make exception_mnemonic() visible to the tests Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 2/4] x86: Add support for running a nested guest multiple times in one test Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 3/4] x86: Add a helper to allow tests to signal completion without a vmcall() Aaron Lewis 2022-01-25 20:31 ` [kvm-unit-tests PATCH v5 4/4] x86: Add test coverage for nested_vmx_reflect_vmexit() testing Aaron Lewis
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).