@@ -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);
@@ -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
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(-)