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 *pte; 51 uint64_t *hva; 52 uint64_t gpa; 53 int rc; 54 55 TEST_REQUIRE(kvm_has_cap(KVM_CAP_SMALLER_MAXPHYADDR)); 56 57 vm = vm_create_with_one_vcpu(&vcpu, guest_code); 58 vcpu_args_set(vcpu, 1, kvm_is_tdp_enabled()); 59 60 vcpu_set_cpuid_property(vcpu, X86_PROPERTY_MAX_PHY_ADDR, MAXPHYADDR); 61 62 rc = kvm_check_cap(KVM_CAP_EXIT_ON_EMULATION_FAILURE); 63 TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable"); 64 vm_enable_cap(vm, KVM_CAP_EXIT_ON_EMULATION_FAILURE, 1); 65 66 vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 67 MEM_REGION_GPA, MEM_REGION_SLOT, 68 MEM_REGION_SIZE / PAGE_SIZE, 0); 69 gpa = vm_phy_pages_alloc(vm, MEM_REGION_SIZE / PAGE_SIZE, 70 MEM_REGION_GPA, MEM_REGION_SLOT); 71 TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc"); 72 virt_map(vm, MEM_REGION_GVA, MEM_REGION_GPA, 1); 73 hva = addr_gpa2hva(vm, MEM_REGION_GPA); 74 memset(hva, 0, PAGE_SIZE); 75 76 pte = vm_get_page_table_entry(vm, MEM_REGION_GVA); 77 *pte |= BIT_ULL(MAXPHYADDR); 78 79 vcpu_run(vcpu); 80 81 /* 82 * When TDP is enabled, KVM must emulate in response the guest physical 83 * address that is illegal from the guest's perspective, but is legal 84 * from hardware's perspeective. This should result in an emulation 85 * failure exit to userspace since KVM doesn't support emulating flds. 86 */ 87 if (kvm_is_tdp_enabled()) { 88 handle_flds_emulation_failure_exit(vcpu); 89 vcpu_run(vcpu); 90 } 91 92 switch (get_ucall(vcpu, &uc)) { 93 case UCALL_ABORT: 94 REPORT_GUEST_ASSERT(uc); 95 break; 96 case UCALL_DONE: 97 break; 98 default: 99 TEST_FAIL("Unrecognized ucall: %lu", uc.cmd); 100 } 101 102 kvm_vm_free(vm); 103 104 return 0; 105 } 106