1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020, Google LLC. 4 * 5 * Test that KVM emulates instructions in response to EPT violations when 6 * allow_smaller_maxphyaddr is enabled and guest.MAXPHYADDR < host.MAXPHYADDR. 7 */ 8 #include "flds_emulation.h" 9 10 #include "test_util.h" 11 #include "kvm_util.h" 12 #include "vmx.h" 13 14 #define MAXPHYADDR 36 15 16 #define MEM_REGION_GVA 0x0000123456789000 17 #define MEM_REGION_GPA 0x0000000700000000 18 #define MEM_REGION_SLOT 10 19 #define MEM_REGION_SIZE PAGE_SIZE 20 21 static void guest_code(bool tdp_enabled) 22 { 23 uint64_t error_code; 24 uint64_t vector; 25 26 vector = kvm_asm_safe_ec(FLDS_MEM_EAX, error_code, "a"(MEM_REGION_GVA)); 27 28 /* 29 * When TDP is enabled, flds will trigger an emulation failure, exit to 30 * userspace, and then the selftest host "VMM" skips the instruction. 31 * 32 * When TDP is disabled, no instruction emulation is required so flds 33 * should generate #PF(RSVD). 34 */ 35 if (tdp_enabled) { 36 GUEST_ASSERT(!vector); 37 } else { 38 GUEST_ASSERT_EQ(vector, PF_VECTOR); 39 GUEST_ASSERT(error_code & PFERR_RSVD_MASK); 40 } 41 42 GUEST_DONE(); 43 } 44 45 int main(int argc, char *argv[]) 46 { 47 struct kvm_vcpu *vcpu; 48 struct kvm_vm *vm; 49 struct ucall uc; 50 uint64_t *hva; 51 uint64_t gpa; 52 int rc; 53 54 TEST_REQUIRE(kvm_has_cap(KVM_CAP_SMALLER_MAXPHYADDR)); 55 56 vm = vm_create_with_one_vcpu(&vcpu, guest_code); 57 vcpu_args_set(vcpu, 1, kvm_is_tdp_enabled()); 58 59 vcpu_set_cpuid_property(vcpu, X86_PROPERTY_MAX_PHY_ADDR, MAXPHYADDR); 60 61 rc = kvm_check_cap(KVM_CAP_EXIT_ON_EMULATION_FAILURE); 62 TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable"); 63 vm_enable_cap(vm, KVM_CAP_EXIT_ON_EMULATION_FAILURE, 1); 64 65 vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 66 MEM_REGION_GPA, MEM_REGION_SLOT, 67 MEM_REGION_SIZE / PAGE_SIZE, 0); 68 gpa = vm_phy_pages_alloc(vm, MEM_REGION_SIZE / PAGE_SIZE, 69 MEM_REGION_GPA, MEM_REGION_SLOT); 70 TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc"); 71 virt_map(vm, MEM_REGION_GVA, MEM_REGION_GPA, 1); 72 hva = addr_gpa2hva(vm, MEM_REGION_GPA); 73 memset(hva, 0, PAGE_SIZE); 74 75 *vm_get_pte(vm, MEM_REGION_GVA) |= BIT_ULL(MAXPHYADDR); 76 77 vcpu_run(vcpu); 78 79 /* 80 * When TDP is enabled, KVM must emulate in response the guest physical 81 * address that is illegal from the guest's perspective, but is legal 82 * from hardware's perspeective. This should result in an emulation 83 * failure exit to userspace since KVM doesn't support emulating flds. 84 */ 85 if (kvm_is_tdp_enabled()) { 86 handle_flds_emulation_failure_exit(vcpu); 87 vcpu_run(vcpu); 88 } 89 90 switch (get_ucall(vcpu, &uc)) { 91 case UCALL_ABORT: 92 REPORT_GUEST_ASSERT(uc); 93 break; 94 case UCALL_DONE: 95 break; 96 default: 97 TEST_FAIL("Unrecognized ucall: %lu", uc.cmd); 98 } 99 100 kvm_vm_free(vm); 101 102 return 0; 103 } 104