From: Avi Kivity <avi@redhat.com>
To: Joerg Roedel <joerg.roedel@amd.com>,
Marcelo Tosatti <mtosatti@redhat.com>,
kvm@vger.kernel.org
Subject: [PATCH 8/8] test: add svm tests
Date: Wed, 28 Jul 2010 13:18:27 +0300 [thread overview]
Message-ID: <1280312307-16686-9-git-send-email-avi@redhat.com> (raw)
In-Reply-To: <1280312307-16686-1-git-send-email-avi@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
kvm/test/config-x86-common.mak | 2 +
kvm/test/config-x86_64.mak | 1 +
kvm/test/x86/svm.c | 180 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 183 insertions(+), 0 deletions(-)
create mode 100644 kvm/test/x86/svm.c
diff --git a/kvm/test/config-x86-common.mak b/kvm/test/config-x86-common.mak
index 00817dc..19bffd4 100644
--- a/kvm/test/config-x86-common.mak
+++ b/kvm/test/config-x86-common.mak
@@ -68,6 +68,8 @@ $(TEST_DIR)/xsave.flat: $(cstart.o) $(TEST_DIR)/idt.o $(TEST_DIR)/xsave.o
$(TEST_DIR)/rmap_chain.flat: $(cstart.o) $(TEST_DIR)/rmap_chain.o \
$(TEST_DIR)/print.o $(TEST_DIR)/vm.o
+$(TEST_DIR)/svm.flat: $(cstart.o) $(TEST_DIR)/vm.o
+
arch_clean:
$(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat \
$(TEST_DIR)/.*.d $(TEST_DIR)/lib/.*.d $(TEST_DIR)/lib/*.o
diff --git a/kvm/test/config-x86_64.mak b/kvm/test/config-x86_64.mak
index 3ffbcc1..b99cf85 100644
--- a/kvm/test/config-x86_64.mak
+++ b/kvm/test/config-x86_64.mak
@@ -7,5 +7,6 @@ CFLAGS += -D__x86_64__
tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \
$(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat \
$(TEST_DIR)/xsave.flat $(TEST_DIR)/rmap_chain.flat
+tests += $(TEST_DIR)/svm.flat
include config-x86-common.mak
diff --git a/kvm/test/x86/svm.c b/kvm/test/x86/svm.c
new file mode 100644
index 0000000..af0e60c
--- /dev/null
+++ b/kvm/test/x86/svm.c
@@ -0,0 +1,180 @@
+#include "svm.h"
+#include "libcflat.h"
+#include "processor.h"
+#include "msr.h"
+#include "vm.h"
+
+static void setup_svm(void)
+{
+ void *hsave = alloc_page();
+
+ wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave));
+ wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SVME);
+}
+
+static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector,
+ u64 base, u32 limit, u32 attr)
+{
+ seg->selector = selector;
+ seg->attrib = attr;
+ seg->limit = limit;
+ seg->base = base;
+}
+
+static void vmcb_ident(struct vmcb *vmcb)
+{
+ u64 vmcb_phys = virt_to_phys(vmcb);
+ struct vmcb_save_area *save = &vmcb->save;
+ struct vmcb_control_area *ctrl = &vmcb->control;
+ u32 data_seg_attr = 3 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK
+ | SVM_SELECTOR_DB_MASK | SVM_SELECTOR_G_MASK;
+ u32 code_seg_attr = 9 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK
+ | SVM_SELECTOR_L_MASK | SVM_SELECTOR_G_MASK;
+ struct descriptor_table_ptr desc_table_ptr;
+
+ memset(vmcb, 0, sizeof(*vmcb));
+ asm volatile ("vmsave" : : "a"(vmcb_phys) : "memory");
+ vmcb_set_seg(&save->es, read_es(), 0, -1U, data_seg_attr);
+ vmcb_set_seg(&save->cs, read_cs(), 0, -1U, code_seg_attr);
+ vmcb_set_seg(&save->ss, read_ss(), 0, -1U, data_seg_attr);
+ vmcb_set_seg(&save->ds, read_ds(), 0, -1U, data_seg_attr);
+ sgdt(&desc_table_ptr);
+ vmcb_set_seg(&save->gdtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0);
+ sidt(&desc_table_ptr);
+ vmcb_set_seg(&save->idtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0);
+ save->cpl = 0;
+ save->efer = rdmsr(MSR_EFER);
+ save->cr4 = read_cr4();
+ save->cr3 = read_cr3();
+ save->cr0 = read_cr0();
+ save->dr7 = read_dr7();
+ save->dr6 = read_dr6();
+ save->cr2 = read_cr2();
+ save->g_pat = rdmsr(MSR_IA32_CR_PAT);
+ save->dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR);
+ ctrl->intercept = (1ULL << INTERCEPT_VMRUN) | (1ULL << INTERCEPT_VMMCALL);
+}
+
+struct test {
+ const char *name;
+ void (*prepare)(struct test *test);
+ void (*guest_func)(struct test *test);
+ bool (*finished)(struct test *test);
+ bool (*succeeded)(struct test *test);
+ struct vmcb *vmcb;
+ int exits;
+};
+
+static void test_thunk(struct test *test)
+{
+ test->guest_func(test);
+ asm volatile ("vmmcall" : : : "memory");
+}
+
+static bool test_run(struct test *test, struct vmcb *vmcb)
+{
+ u64 vmcb_phys = virt_to_phys(vmcb);
+ u64 guest_stack[10000];
+ bool success;
+
+ test->vmcb = vmcb;
+ test->prepare(test);
+ vmcb->save.rip = (ulong)test_thunk;
+ vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack));
+ do {
+ asm volatile (
+ "clgi \n\t"
+ "vmload \n\t"
+ "push %%rbp \n\t"
+ "push %1 \n\t"
+ "vmrun \n\t"
+ "pop %1 \n\t"
+ "pop %%rbp \n\t"
+ "vmsave \n\t"
+ "stgi"
+ : : "a"(vmcb_phys), "D"(test)
+ : "rbx", "rcx", "rdx", "rsi",
+ "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15",
+ "memory");
+ ++test->exits;
+ } while (!test->finished(test));
+
+ success = test->succeeded(test);
+
+ printf("%s: %s\n", test->name, success ? "PASS" : "FAIL");
+
+ return success;
+}
+
+static void default_prepare(struct test *test)
+{
+ vmcb_ident(test->vmcb);
+}
+
+static bool default_finished(struct test *test)
+{
+ return true; /* one vmexit */
+}
+
+static void null_test(struct test *test)
+{
+}
+
+static bool null_check(struct test *test)
+{
+ return test->vmcb->control.exit_code == SVM_EXIT_VMMCALL;
+}
+
+static void prepare_no_vmrun_int(struct test *test)
+{
+ test->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VMRUN);
+}
+
+static bool check_no_vmrun_int(struct test *test)
+{
+ return test->vmcb->control.exit_code == SVM_EXIT_ERR;
+}
+
+static void test_vmrun(struct test *test)
+{
+ asm volatile ("vmrun" : : "a"(virt_to_phys(test->vmcb)));
+}
+
+static bool check_vmrun(struct test *test)
+{
+ return test->vmcb->control.exit_code == SVM_EXIT_VMRUN;
+}
+
+static struct test tests[] = {
+ { "null", default_prepare, null_test, default_finished, null_check },
+ { "vmrun", default_prepare, test_vmrun, default_finished, check_vmrun },
+ { "vmrun intercept check", prepare_no_vmrun_int, null_test,
+ default_finished, check_no_vmrun_int },
+
+};
+
+int main(int ac, char **av)
+{
+ int i, nr, passed;
+ struct vmcb *vmcb;
+
+ setup_vm();
+
+ if (!(cpuid(0x80000001).c & 4)) {
+ printf("SVM not availble\n");
+ return 0;
+ }
+
+ setup_svm();
+
+ vmcb = alloc_page();
+
+ nr = ARRAY_SIZE(tests);
+ passed = 0;
+ for (i = 0; i < nr; ++i) {
+ passed += test_run(&tests[i], vmcb);
+ }
+
+ printf("\nSUMMARY: %d TESTS, %d FAILURES\n", nr, (nr - passed));
+ return passed == nr ? 0 : 1;
+}
--
1.7.1
next prev parent reply other threads:[~2010-07-28 10:18 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-07-28 10:18 [PATCH 0/8] Nested SVM unit tests Avi Kivity
2010-07-28 10:18 ` [PATCH 1/8] test: move ARRAY_SIZE() to libcflat.h Avi Kivity
2010-07-28 10:18 ` [PATCH 2/8] test: move memset() to libcflat Avi Kivity
2010-07-28 10:18 ` [PATCH 3/8] test: add type bool Avi Kivity
2010-07-28 10:18 ` [PATCH 4/8] test: add processor register access functions Avi Kivity
2010-07-28 10:18 ` [PATCH 5/8] test: make use of new processor.h header Avi Kivity
2010-07-28 10:18 ` [PATCH 6/8] test: add svm definitions header Avi Kivity
2010-07-28 10:18 ` [PATCH 7/8] test: add msr " Avi Kivity
2010-07-28 10:18 ` Avi Kivity [this message]
2010-07-28 11:40 ` [PATCH 0/8] Nested SVM unit tests Roedel, Joerg
2010-07-28 11:53 ` Avi Kivity
2010-07-28 12:39 ` Roedel, Joerg
2010-07-28 12:46 ` Avi Kivity
2010-07-29 16:55 ` Marcelo Tosatti
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1280312307-16686-9-git-send-email-avi@redhat.com \
--to=avi@redhat.com \
--cc=joerg.roedel@amd.com \
--cc=kvm@vger.kernel.org \
--cc=mtosatti@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox