0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "test_util.h"
0012 #include "kvm_util.h"
0013 #include "processor.h"
0014 #include "vmx.h"
0015
0016 #include <string.h>
0017 #include <sys/ioctl.h>
0018
0019 #include "kselftest.h"
0020
0021 enum {
0022 PORT_L0_EXIT = 0x2000,
0023 };
0024
0025 static void l2_guest_code(void)
0026 {
0027
0028 asm volatile("inb %%dx, %%al"
0029 : : [port] "d" (PORT_L0_EXIT) : "rax");
0030 }
0031
0032 static void l1_guest_code(struct vmx_pages *vmx_pages)
0033 {
0034 #define L2_GUEST_STACK_SIZE 64
0035 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
0036
0037 GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages));
0038 GUEST_ASSERT(load_vmcs(vmx_pages));
0039
0040
0041 prepare_vmcs(vmx_pages, l2_guest_code,
0042 &l2_guest_stack[L2_GUEST_STACK_SIZE]);
0043
0044 GUEST_ASSERT(!vmlaunch());
0045 GUEST_ASSERT(0);
0046 }
0047
0048 int main(int argc, char *argv[])
0049 {
0050 vm_vaddr_t vmx_pages_gva;
0051 struct kvm_vcpu *vcpu;
0052 struct kvm_vm *vm;
0053
0054 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
0055
0056 vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
0057
0058
0059 vcpu_alloc_vmx(vm, &vmx_pages_gva);
0060 vcpu_args_set(vcpu, 1, vmx_pages_gva);
0061
0062 for (;;) {
0063 volatile struct kvm_run *run = vcpu->run;
0064 struct ucall uc;
0065
0066 vcpu_run(vcpu);
0067 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0068 "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n",
0069 run->exit_reason,
0070 exit_reason_str(run->exit_reason));
0071
0072 if (run->io.port == PORT_L0_EXIT)
0073 break;
0074
0075 switch (get_ucall(vcpu, &uc)) {
0076 case UCALL_ABORT:
0077 REPORT_GUEST_ASSERT(uc);
0078
0079 default:
0080 TEST_FAIL("Unknown ucall %lu", uc.cmd);
0081 }
0082 }
0083 }