diff mbox

[kvm-unit-tests,1/2] x86: SVM: Add tests for SVM msr bit settings combinations in MSR_EFER and MSR_VM_CR

Message ID 20180307212824.16557-1-Swapnil.Paratey@amd.com (mailing list archive)
State New, archived
Headers show

Commit Message

Swapnil Paratey March 7, 2018, 9:28 p.m. UTC
From: Swapnil Paratey <swapnil.paratey@amd.com>

1) Exercise the SVM rules for the various bit settings of the controlling SVM MSRs
2) Spelling correction of "available"
---
 x86/svm.c         | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 x86/unittests.cfg |   5 +++
 2 files changed, 128 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/x86/svm.c b/x86/svm.c
index 162632c..b71178a 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -40,6 +40,8 @@  u64 runs;
 u8 *io_bitmap;
 u8 io_bitmap_area[16384];
 
+static int matched;
+
 static bool npt_supported(void)
 {
    return cpuid(0x8000000A).d & 1;
@@ -1008,6 +1010,85 @@  static bool lat_svm_insn_check(struct test *test)
             latclgi_min, clgi_sum / LATENCY_RUNS);
     return true;
 }
+
+static void set_msr_vm_cr(void *data)
+{
+    u64 msr_value;
+    msr_value = *((u64 *)(data));
+    wrmsr(MSR_VM_CR, msr_value);
+}
+
+static void set_msr_efer(void *data)
+{
+    u64 msr_value;
+    msr_value = *((u64 *)(data));
+    wrmsr(MSR_EFER, msr_value);
+}
+
+static void test_svm_virtual_machine_control()
+{
+    bool svm_enabled, svme_disabled;
+    u64 msr_value;
+
+    svm_enabled = ((rdmsr(MSR_EFER) & 0x1000) == 0x1000);
+    svme_disabled = ((rdmsr(MSR_VM_CR) & 0x10) == 0x10);
+
+    if(svm_enabled == false) {
+        wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SVME);
+        report("test enable SVM if EFER_SVME bit is disabled",
+                ((rdmsr(MSR_EFER) & EFER_SVME) == EFER_SVME));
+    }
+
+    if(svme_disabled == true) {
+        report("test MSR_VM_CR SVMe Disable bit is set", svme_disabled);
+        return ;
+    }
+
+    /* Test MSR_VM_CR bit-sets when EFER_SVME bit is set */
+    msr_value = 0x00;
+    report("test MSR_VM_CR reset when EFER_SVME bit is set - no #GP",
+        !test_for_exception(GP_VECTOR, &set_msr_vm_cr, (void*)(&msr_value)));
+    msr_value = 0x10;
+    report("test MSR_VM_CR SVMeDisable bit set when EFER_SVME bit is set - #GP",
+        test_for_exception(GP_VECTOR, &set_msr_vm_cr, (void*)(&msr_value)));
+    msr_value = 0x08;
+    report("test MSR_VM_CR control lock bit set when EFER_SVME set - #GP",
+        test_for_exception(GP_VECTOR, &set_msr_vm_cr, (void*)(&msr_value)));
+    msr_value = 0x00;
+    report("test MSR_VM_CR reset when EFER_SVME bit is set - #GP",
+        test_for_exception(GP_VECTOR, &set_msr_vm_cr, (void*)(&msr_value)));
+
+    /* MSR_VM_CR SVMe Disable bit once set does not unset - cannot be cleared on KVM
+     * Host behavior is different than KVM behavior - host allows setting VM_CR_SVMEDIS  on EFER_SVME being unset
+     * If there's no BIOS lock bit set, and no SVM Key, the VMCR can be cleared on the host
+     * KVM implements a soft-lock without implementing the SVM Key though
+     * KVM/SVM does not implement lock bits and gives #GP for reset instead */
+
+    /* Clear the EFER_SVME and test for #GP on VM_CR_SVMEDIS bit sets */
+    msr_value = rdmsr(MSR_EFER);
+    msr_value &= ~EFER_SVME;
+    wrmsr(MSR_EFER, msr_value);
+
+    msr_value = 0x00;
+    report("test MSR_VM_CR reset when EFER_SVME bit is clear - no #GP",
+        !test_for_exception(GP_VECTOR, &set_msr_vm_cr, (void*)(&msr_value)));
+    msr_value = 0x10;
+    report("test MSR_VM_CR SVMeDis bit set when EFER_SVME bit clear - no #GP",
+        !test_for_exception(GP_VECTOR, &set_msr_vm_cr, (void*)(&msr_value)));
+    msr_value = 0x08;
+    report("test MSR_VM_CR control lock bit set when EFER_SVME clear - no #GP",
+        !test_for_exception(GP_VECTOR, &set_msr_vm_cr, (void*)(&msr_value)));
+    msr_value = 0x00;
+    report("test MSR_VM_CR reset when EFER_SVME bit is clear - no #GP",
+        !test_for_exception(GP_VECTOR, &set_msr_vm_cr, (void*)(&msr_value)));
+
+    /* VM_CR_SVMEDIS is set at this point, test EFER #GP behaviors */
+    msr_value = 0x1000;
+    report("test Setting EFER_SVME bit when VM_CR_SVMEDIS is set - #GP",
+        test_for_exception(GP_VECTOR, &set_msr_efer, (void*)(&msr_value)));
+}
+
+
 static struct test tests[] = {
     { "null", default_supported, default_prepare, null_test,
       default_finished, null_check },
@@ -1054,7 +1135,42 @@  static struct test tests[] = {
       lat_svm_insn_finished, lat_svm_insn_check },
 };
 
-int main(int ac, char **av)
+static bool test_wanted(const char *name, const char *filters[], int filter_count)
+{
+    int i;
+    bool positive = false;
+    bool match = false;
+    char clean_name[strlen(name) + 1];
+    char *c;
+    const char *n;
+
+    /* Replace spaces with underscores. */
+    n = name;
+    c = &clean_name[0];
+    do *c++ = (*n == ' ') ? '_' : *n;
+    while (*n++);
+
+    for (i = 0; i < filter_count; i++) {
+        const char *filter = filters[i];
+
+        if (filter[0] == '-') {
+            if (simple_glob(clean_name, filter + 1))
+                return false;
+        } else {
+            positive = true;
+            match |= simple_glob(clean_name, filter);
+        }
+    }
+
+    if (!positive || match) {
+        matched++;
+        return true;
+    } else {
+        return false;
+    }
+}
+
+int main(int ac, const char **av)
 {
     int i, nr;
     struct vmcb *vmcb;
@@ -1063,12 +1179,17 @@  int main(int ac, char **av)
     smp_init();
 
     if (!(cpuid(0x80000001).c & 4)) {
-        printf("SVM not availble\n");
+        printf("SVM not available\n");
         return report_summary();
     }
 
     setup_svm();
 
+    if(test_wanted("test_svm_virtual_machine_control", av, ac)) {
+        test_svm_virtual_machine_control();
+        return report_summary();
+    }
+
     vmcb = alloc_page();
 
     nr = ARRAY_SIZE(tests);
diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index 22c62d5..19407af 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -194,6 +194,11 @@  smp = 2
 extra_params = -cpu qemu64,+svm
 arch = x86_64
 
+[svm_test_virtual_machine_control]
+file = svm.flat
+extra_params = -cpu host,+svm -append test_svm_virtual_machine_control
+arch = x86_64
+
 [taskswitch]
 file = taskswitch.flat
 arch = i386