1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2021, Red Hat, Inc.
7 * Nested SVM testing: test simultaneous use of V_IRQ from L1 and L0.
10 #include "test_util.h"
12 #include "processor.h"
16 bool vintr_irq_called
;
19 #define VINTR_IRQ_NUMBER 0x20
20 #define INTR_IRQ_NUMBER 0x30
22 static void vintr_irq_handler(struct ex_regs
*regs
)
24 vintr_irq_called
= true;
27 static void intr_irq_handler(struct ex_regs
*regs
)
29 x2apic_write_reg(APIC_EOI
, 0x00);
30 intr_irq_called
= true;
33 static void l2_guest_code(struct svm_test_data
*svm
)
35 /* This code raises interrupt INTR_IRQ_NUMBER in the L1's LAPIC,
36 * and since L1 didn't enable virtual interrupt masking,
37 * L2 should receive it and not L1.
39 * L2 also has virtual interrupt 'VINTR_IRQ_NUMBER' pending in V_IRQ
40 * so it should also receive it after the following 'sti'.
42 x2apic_write_reg(APIC_ICR
,
43 APIC_DEST_SELF
| APIC_INT_ASSERT
| INTR_IRQ_NUMBER
);
50 GUEST_ASSERT(vintr_irq_called
);
51 GUEST_ASSERT(intr_irq_called
);
58 static void l1_guest_code(struct svm_test_data
*svm
)
60 #define L2_GUEST_STACK_SIZE 64
61 unsigned long l2_guest_stack
[L2_GUEST_STACK_SIZE
];
62 struct vmcb
*vmcb
= svm
->vmcb
;
66 /* Prepare for L2 execution. */
67 generic_svm_setup(svm
, l2_guest_code
,
68 &l2_guest_stack
[L2_GUEST_STACK_SIZE
]);
70 /* No virtual interrupt masking */
71 vmcb
->control
.int_ctl
&= ~V_INTR_MASKING_MASK
;
73 /* No intercepts for real and virtual interrupts */
74 vmcb
->control
.intercept
&= ~(BIT(INTERCEPT_INTR
) | BIT(INTERCEPT_VINTR
));
76 /* Make a virtual interrupt VINTR_IRQ_NUMBER pending */
77 vmcb
->control
.int_ctl
|= V_IRQ_MASK
| (0x1 << V_INTR_PRIO_SHIFT
);
78 vmcb
->control
.int_vector
= VINTR_IRQ_NUMBER
;
80 run_guest(vmcb
, svm
->vmcb_gpa
);
81 GUEST_ASSERT(vmcb
->control
.exit_code
== SVM_EXIT_VMMCALL
);
85 int main(int argc
, char *argv
[])
87 struct kvm_vcpu
*vcpu
;
92 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM
));
94 vm
= vm_create_with_one_vcpu(&vcpu
, l1_guest_code
);
96 vm_install_exception_handler(vm
, VINTR_IRQ_NUMBER
, vintr_irq_handler
);
97 vm_install_exception_handler(vm
, INTR_IRQ_NUMBER
, intr_irq_handler
);
99 vcpu_alloc_svm(vm
, &svm_gva
);
100 vcpu_args_set(vcpu
, 1, svm_gva
);
103 TEST_ASSERT_KVM_EXIT_REASON(vcpu
, KVM_EXIT_IO
);
105 switch (get_ucall(vcpu
, &uc
)) {
107 REPORT_GUEST_ASSERT(uc
);
113 TEST_FAIL("Unknown ucall 0x%lx.", uc
.cmd
);