diff mbox series

[kvm-unit-tests] svm: add a test for exception injection

Message ID 20200409094303.949992-1-pbonzini@redhat.com (mailing list archive)
State New, archived
Headers show
Series [kvm-unit-tests] svm: add a test for exception injection | expand

Commit Message

Paolo Bonzini April 9, 2020, 9:43 a.m. UTC
Cover VMRUN's testing whether EVENTINJ.TYPE = 3 (exception) has been specified with
a vector that does not correspond to an exception.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 x86/svm.h       |  7 +++++
 x86/svm_tests.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)

Comments

Krish Sadhukhan April 11, 2020, 12:24 a.m. UTC | #1
On 4/9/20 2:43 AM, Paolo Bonzini wrote:
> Cover VMRUN's testing whether EVENTINJ.TYPE = 3 (exception) has been specified with
> a vector that does not correspond to an exception.
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>   x86/svm.h       |  7 +++++
>   x86/svm_tests.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 77 insertions(+)
>
> diff --git a/x86/svm.h b/x86/svm.h
> index 645deb7..bb5c552 100644
> --- a/x86/svm.h
> +++ b/x86/svm.h
> @@ -324,6 +324,13 @@ struct __attribute__ ((__packed__)) vmcb {
>   
>   #define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP)
>   
> +#define SVM_EVENT_INJ_HWINT	(0 << 8)
> +#define SVM_EVENT_INJ_NMI	(2 << 8)
> +#define SVM_EVENT_INJ_EXC	(3 << 8)
> +#define SVM_EVENT_INJ_SWINT	(4 << 8)
> +#define SVM_EVENT_INJ_ERRCODE	(1 << 11)
> +#define SVM_EVENT_INJ_VALID	(1 << 31)


I see existing #defines in svm.h:

     #define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT)
     #define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT)
     #define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT)
     #define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT)
     #define SVM_EVTINJ_VALID (1 << 31)
     #define SVM_EVTINJ_VALID_ERR (1 << 11)

> +
>   #define MSR_BITMAP_SIZE 8192
>   
>   struct svm_test {
> diff --git a/x86/svm_tests.c b/x86/svm_tests.c
> index 16b9dfd..6292e68 100644
> --- a/x86/svm_tests.c
> +++ b/x86/svm_tests.c
> @@ -1340,6 +1340,73 @@ static bool interrupt_check(struct svm_test *test)
>       return get_test_stage(test) == 5;
>   }
>   
> +static volatile int count_exc = 0;
> +
> +static void my_isr(struct ex_regs *r)
> +{
> +        count_exc++;
> +}
> +
> +static void exc_inject_prepare(struct svm_test *test)
> +{
> +	handle_exception(DE_VECTOR, my_isr);
> +	handle_exception(NMI_VECTOR, my_isr);
> +}
> +
> +
> +static void exc_inject_test(struct svm_test *test)
> +{
> +    asm volatile ("vmmcall\n\tvmmcall\n\t");
> +}
> +
> +static bool exc_inject_finished(struct svm_test *test)
> +{
> +    vmcb->save.rip += 3;
> +
> +    switch (get_test_stage(test)) {
> +    case 0:
> +        if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) {
> +            report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x",
> +                   vmcb->control.exit_code);
> +            return true;
> +        }
> +        vmcb->control.event_inj = NMI_VECTOR | SVM_EVENT_INJ_EXC | SVM_EVENT_INJ_VALID;
> +        break;
> +
> +    case 1:
> +        if (vmcb->control.exit_code != SVM_EXIT_ERR) {
> +            report(false, "VMEXIT not due to error. Exit reason 0x%x",
> +                   vmcb->control.exit_code);
> +            return true;
> +        }
> +        report(count_exc == 0, "exception with vector 2 not injected");
> +        vmcb->control.event_inj = DE_VECTOR | SVM_EVENT_INJ_EXC | SVM_EVENT_INJ_VALID;
> +	break;
> +
> +    case 2:
> +        if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) {
> +            report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x",
> +                   vmcb->control.exit_code);
> +            return true;
> +        }
> +        report(count_exc == 1, "divide overflow exception injected");
> +	report(!(vmcb->control.event_inj & SVM_EVENT_INJ_VALID), "eventinj.VALID cleared");
> +        break;
> +
> +    default:
> +        return true;
> +    }
> +
> +    inc_test_stage(test);
> +
> +    return get_test_stage(test) == 3;
> +}
> +
> +static bool exc_inject_check(struct svm_test *test)
> +{
> +    return count_exc == 1 && get_test_stage(test) == 3;
> +}
> +
>   #define TEST(name) { #name, .v2 = name }
>   
>   /*
> @@ -1446,6 +1513,9 @@ struct svm_test svm_tests[] = {
>       { "interrupt", default_supported, interrupt_prepare,
>         default_prepare_gif_clear, interrupt_test,
>         interrupt_finished, interrupt_check },
> +    { "exc_inject", default_supported, exc_inject_prepare,
> +      default_prepare_gif_clear, exc_inject_test,
> +      exc_inject_finished, exc_inject_check },
>       TEST(svm_guest_state_test),
>       { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
>   };
Paolo Bonzini April 15, 2020, 2:56 p.m. UTC | #2
On 11/04/20 02:24, Krish Sadhukhan wrote:
> 
> On 4/9/20 2:43 AM, Paolo Bonzini wrote:
>> Cover VMRUN's testing whether EVENTINJ.TYPE = 3 (exception) has been
>> specified with
>> a vector that does not correspond to an exception.
>>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>>   x86/svm.h       |  7 +++++
>>   x86/svm_tests.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 77 insertions(+)
>>
>> diff --git a/x86/svm.h b/x86/svm.h
>> index 645deb7..bb5c552 100644
>> --- a/x86/svm.h
>> +++ b/x86/svm.h
>> @@ -324,6 +324,13 @@ struct __attribute__ ((__packed__)) vmcb {
>>     #define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP)
>>   +#define SVM_EVENT_INJ_HWINT    (0 << 8)
>> +#define SVM_EVENT_INJ_NMI    (2 << 8)
>> +#define SVM_EVENT_INJ_EXC    (3 << 8)
>> +#define SVM_EVENT_INJ_SWINT    (4 << 8)
>> +#define SVM_EVENT_INJ_ERRCODE    (1 << 11)
>> +#define SVM_EVENT_INJ_VALID    (1 << 31)
> 
> 
> I see existing #defines in svm.h:
> 
>     #define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT)
>     #define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT)
>     #define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT)
>     #define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT)
>     #define SVM_EVTINJ_VALID (1 << 31)
>     #define SVM_EVTINJ_VALID_ERR (1 << 11)

Indeed.  I queued the patch with these defines instead.

Paolo

>> +
>>   #define MSR_BITMAP_SIZE 8192
>>     struct svm_test {
>> diff --git a/x86/svm_tests.c b/x86/svm_tests.c
>> index 16b9dfd..6292e68 100644
>> --- a/x86/svm_tests.c
>> +++ b/x86/svm_tests.c
>> @@ -1340,6 +1340,73 @@ static bool interrupt_check(struct svm_test *test)
>>       return get_test_stage(test) == 5;
>>   }
>>   +static volatile int count_exc = 0;
>> +
>> +static void my_isr(struct ex_regs *r)
>> +{
>> +        count_exc++;
>> +}
>> +
>> +static void exc_inject_prepare(struct svm_test *test)
>> +{
>> +    handle_exception(DE_VECTOR, my_isr);
>> +    handle_exception(NMI_VECTOR, my_isr);
>> +}
>> +
>> +
>> +static void exc_inject_test(struct svm_test *test)
>> +{
>> +    asm volatile ("vmmcall\n\tvmmcall\n\t");
>> +}
>> +
>> +static bool exc_inject_finished(struct svm_test *test)
>> +{
>> +    vmcb->save.rip += 3;
>> +
>> +    switch (get_test_stage(test)) {
>> +    case 0:
>> +        if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) {
>> +            report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x",
>> +                   vmcb->control.exit_code);
>> +            return true;
>> +        }
>> +        vmcb->control.event_inj = NMI_VECTOR | SVM_EVENT_INJ_EXC |
>> SVM_EVENT_INJ_VALID;
>> +        break;
>> +
>> +    case 1:
>> +        if (vmcb->control.exit_code != SVM_EXIT_ERR) {
>> +            report(false, "VMEXIT not due to error. Exit reason 0x%x",
>> +                   vmcb->control.exit_code);
>> +            return true;
>> +        }
>> +        report(count_exc == 0, "exception with vector 2 not injected");
>> +        vmcb->control.event_inj = DE_VECTOR | SVM_EVENT_INJ_EXC |
>> SVM_EVENT_INJ_VALID;
>> +    break;
>> +
>> +    case 2:
>> +        if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) {
>> +            report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x",
>> +                   vmcb->control.exit_code);
>> +            return true;
>> +        }
>> +        report(count_exc == 1, "divide overflow exception injected");
>> +    report(!(vmcb->control.event_inj & SVM_EVENT_INJ_VALID),
>> "eventinj.VALID cleared");
>> +        break;
>> +
>> +    default:
>> +        return true;
>> +    }
>> +
>> +    inc_test_stage(test);
>> +
>> +    return get_test_stage(test) == 3;
>> +}
>> +
>> +static bool exc_inject_check(struct svm_test *test)
>> +{
>> +    return count_exc == 1 && get_test_stage(test) == 3;
>> +}
>> +
>>   #define TEST(name) { #name, .v2 = name }
>>     /*
>> @@ -1446,6 +1513,9 @@ struct svm_test svm_tests[] = {
>>       { "interrupt", default_supported, interrupt_prepare,
>>         default_prepare_gif_clear, interrupt_test,
>>         interrupt_finished, interrupt_check },
>> +    { "exc_inject", default_supported, exc_inject_prepare,
>> +      default_prepare_gif_clear, exc_inject_test,
>> +      exc_inject_finished, exc_inject_check },
>>       TEST(svm_guest_state_test),
>>       { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
>>   };
>
diff mbox series

Patch

diff --git a/x86/svm.h b/x86/svm.h
index 645deb7..bb5c552 100644
--- a/x86/svm.h
+++ b/x86/svm.h
@@ -324,6 +324,13 @@  struct __attribute__ ((__packed__)) vmcb {
 
 #define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP)
 
+#define SVM_EVENT_INJ_HWINT	(0 << 8)
+#define SVM_EVENT_INJ_NMI	(2 << 8)
+#define SVM_EVENT_INJ_EXC	(3 << 8)
+#define SVM_EVENT_INJ_SWINT	(4 << 8)
+#define SVM_EVENT_INJ_ERRCODE	(1 << 11)
+#define SVM_EVENT_INJ_VALID	(1 << 31)
+
 #define MSR_BITMAP_SIZE 8192
 
 struct svm_test {
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 16b9dfd..6292e68 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -1340,6 +1340,73 @@  static bool interrupt_check(struct svm_test *test)
     return get_test_stage(test) == 5;
 }
 
+static volatile int count_exc = 0;
+
+static void my_isr(struct ex_regs *r)
+{
+        count_exc++;
+}
+
+static void exc_inject_prepare(struct svm_test *test)
+{
+	handle_exception(DE_VECTOR, my_isr);
+	handle_exception(NMI_VECTOR, my_isr);
+}
+
+
+static void exc_inject_test(struct svm_test *test)
+{
+    asm volatile ("vmmcall\n\tvmmcall\n\t");
+}
+
+static bool exc_inject_finished(struct svm_test *test)
+{
+    vmcb->save.rip += 3;
+
+    switch (get_test_stage(test)) {
+    case 0:
+        if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) {
+            report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x",
+                   vmcb->control.exit_code);
+            return true;
+        }
+        vmcb->control.event_inj = NMI_VECTOR | SVM_EVENT_INJ_EXC | SVM_EVENT_INJ_VALID;
+        break;
+
+    case 1:
+        if (vmcb->control.exit_code != SVM_EXIT_ERR) {
+            report(false, "VMEXIT not due to error. Exit reason 0x%x",
+                   vmcb->control.exit_code);
+            return true;
+        }
+        report(count_exc == 0, "exception with vector 2 not injected");
+        vmcb->control.event_inj = DE_VECTOR | SVM_EVENT_INJ_EXC | SVM_EVENT_INJ_VALID;
+	break;
+
+    case 2:
+        if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) {
+            report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x",
+                   vmcb->control.exit_code);
+            return true;
+        }
+        report(count_exc == 1, "divide overflow exception injected");
+	report(!(vmcb->control.event_inj & SVM_EVENT_INJ_VALID), "eventinj.VALID cleared");
+        break;
+
+    default:
+        return true;
+    }
+
+    inc_test_stage(test);
+
+    return get_test_stage(test) == 3;
+}
+
+static bool exc_inject_check(struct svm_test *test)
+{
+    return count_exc == 1 && get_test_stage(test) == 3;
+}
+
 #define TEST(name) { #name, .v2 = name }
 
 /*
@@ -1446,6 +1513,9 @@  struct svm_test svm_tests[] = {
     { "interrupt", default_supported, interrupt_prepare,
       default_prepare_gif_clear, interrupt_test,
       interrupt_finished, interrupt_check },
+    { "exc_inject", default_supported, exc_inject_prepare,
+      default_prepare_gif_clear, exc_inject_test,
+      exc_inject_finished, exc_inject_check },
     TEST(svm_guest_state_test),
     { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 };