1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2022, Red Hat, Inc. 4 * 5 * Tests for Hyper-V extensions to SVM. 6 */ 7 #include <fcntl.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <sys/ioctl.h> 12 #include <linux/bitmap.h> 13 14 #include "test_util.h" 15 16 #include "kvm_util.h" 17 #include "processor.h" 18 #include "svm_util.h" 19 #include "hyperv.h" 20 21 #define L2_GUEST_STACK_SIZE 256 22 23 /* Exit to L1 from L2 with RDMSR instruction */ 24 static inline void rdmsr_from_l2(uint32_t msr) 25 { 26 /* Currently, L1 doesn't preserve GPRs during vmexits. */ 27 __asm__ __volatile__ ("rdmsr" : : "c"(msr) : 28 "rax", "rbx", "rdx", "rsi", "rdi", "r8", "r9", 29 "r10", "r11", "r12", "r13", "r14", "r15"); 30 } 31 32 void l2_guest_code(void) 33 { 34 u64 unused; 35 36 GUEST_SYNC(3); 37 /* Exit to L1 */ 38 vmmcall(); 39 40 /* MSR-Bitmap tests */ 41 rdmsr_from_l2(MSR_FS_BASE); /* intercepted */ 42 rdmsr_from_l2(MSR_FS_BASE); /* intercepted */ 43 rdmsr_from_l2(MSR_GS_BASE); /* not intercepted */ 44 vmmcall(); 45 rdmsr_from_l2(MSR_GS_BASE); /* intercepted */ 46 47 GUEST_SYNC(5); 48 49 /* L2 TLB flush tests */ 50 hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE | 51 HV_HYPERCALL_FAST_BIT, 0x0, 52 HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES | 53 HV_FLUSH_ALL_PROCESSORS); 54 rdmsr_from_l2(MSR_FS_BASE); 55 /* 56 * Note: hypercall status (RAX) is not preserved correctly by L1 after 57 * synthetic vmexit, use unchecked version. 58 */ 59 __hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE | 60 HV_HYPERCALL_FAST_BIT, 0x0, 61 HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES | 62 HV_FLUSH_ALL_PROCESSORS, &unused); 63 64 /* Done, exit to L1 and never come back. */ 65 vmmcall(); 66 } 67 68 static void __attribute__((__flatten__)) guest_code(struct svm_test_data *svm, 69 struct hyperv_test_pages *hv_pages, 70 vm_vaddr_t pgs_gpa) 71 { 72 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; 73 struct vmcb *vmcb = svm->vmcb; 74 struct hv_vmcb_enlightenments *hve = &vmcb->control.hv_enlightenments; 75 76 GUEST_SYNC(1); 77 78 wrmsr(HV_X64_MSR_GUEST_OS_ID, HYPERV_LINUX_OS_ID); 79 wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa); 80 enable_vp_assist(hv_pages->vp_assist_gpa, hv_pages->vp_assist); 81 82 GUEST_ASSERT(svm->vmcb_gpa); 83 /* Prepare for L2 execution. */ 84 generic_svm_setup(svm, l2_guest_code, 85 &l2_guest_stack[L2_GUEST_STACK_SIZE]); 86 87 /* L2 TLB flush setup */ 88 hve->partition_assist_page = hv_pages->partition_assist_gpa; 89 hve->hv_enlightenments_control.nested_flush_hypercall = 1; 90 hve->hv_vm_id = 1; 91 hve->hv_vp_id = 1; 92 current_vp_assist->nested_control.features.directhypercall = 1; 93 *(u32 *)(hv_pages->partition_assist) = 0; 94 95 GUEST_SYNC(2); 96 run_guest(vmcb, svm->vmcb_gpa); 97 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL); 98 GUEST_SYNC(4); 99 vmcb->save.rip += 3; 100 101 /* Intercept RDMSR 0xc0000100 */ 102 vmcb->control.intercept |= 1ULL << INTERCEPT_MSR_PROT; 103 __set_bit(2 * (MSR_FS_BASE & 0x1fff), svm->msr + 0x800); 104 run_guest(vmcb, svm->vmcb_gpa); 105 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_MSR); 106 vmcb->save.rip += 2; /* rdmsr */ 107 108 /* Enable enlightened MSR bitmap */ 109 hve->hv_enlightenments_control.msr_bitmap = 1; 110 run_guest(vmcb, svm->vmcb_gpa); 111 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_MSR); 112 vmcb->save.rip += 2; /* rdmsr */ 113 114 /* Intercept RDMSR 0xc0000101 without telling KVM about it */ 115 __set_bit(2 * (MSR_GS_BASE & 0x1fff), svm->msr + 0x800); 116 /* Make sure HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP is set */ 117 vmcb->control.clean |= HV_VMCB_NESTED_ENLIGHTENMENTS; 118 run_guest(vmcb, svm->vmcb_gpa); 119 /* Make sure we don't see SVM_EXIT_MSR here so eMSR bitmap works */ 120 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL); 121 vmcb->save.rip += 3; /* vmcall */ 122 123 /* Now tell KVM we've changed MSR-Bitmap */ 124 vmcb->control.clean &= ~HV_VMCB_NESTED_ENLIGHTENMENTS; 125 run_guest(vmcb, svm->vmcb_gpa); 126 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_MSR); 127 vmcb->save.rip += 2; /* rdmsr */ 128 129 130 /* 131 * L2 TLB flush test. First VMCALL should be handled directly by L0, 132 * no VMCALL exit expected. 133 */ 134 run_guest(vmcb, svm->vmcb_gpa); 135 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_MSR); 136 vmcb->save.rip += 2; /* rdmsr */ 137 /* Enable synthetic vmexit */ 138 *(u32 *)(hv_pages->partition_assist) = 1; 139 run_guest(vmcb, svm->vmcb_gpa); 140 GUEST_ASSERT(vmcb->control.exit_code == HV_SVM_EXITCODE_ENL); 141 GUEST_ASSERT(vmcb->control.exit_info_1 == HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH); 142 143 run_guest(vmcb, svm->vmcb_gpa); 144 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL); 145 GUEST_SYNC(6); 146 147 GUEST_DONE(); 148 } 149 150 int main(int argc, char *argv[]) 151 { 152 vm_vaddr_t nested_gva = 0, hv_pages_gva = 0; 153 vm_vaddr_t hcall_page; 154 struct kvm_vcpu *vcpu; 155 struct kvm_vm *vm; 156 struct ucall uc; 157 int stage; 158 159 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM)); 160 TEST_REQUIRE(kvm_hv_cpu_has(HV_X64_NESTED_DIRECT_FLUSH)); 161 162 /* Create VM */ 163 vm = vm_create_with_one_vcpu(&vcpu, guest_code); 164 vcpu_set_hv_cpuid(vcpu); 165 vcpu_alloc_svm(vm, &nested_gva); 166 vcpu_alloc_hyperv_test_pages(vm, &hv_pages_gva); 167 168 hcall_page = vm_vaddr_alloc_pages(vm, 1); 169 memset(addr_gva2hva(vm, hcall_page), 0x0, getpagesize()); 170 171 vcpu_args_set(vcpu, 3, nested_gva, hv_pages_gva, addr_gva2gpa(vm, hcall_page)); 172 vcpu_set_msr(vcpu, HV_X64_MSR_VP_INDEX, vcpu->id); 173 174 for (stage = 1;; stage++) { 175 vcpu_run(vcpu); 176 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); 177 178 switch (get_ucall(vcpu, &uc)) { 179 case UCALL_ABORT: 180 REPORT_GUEST_ASSERT(uc); 181 /* NOT REACHED */ 182 case UCALL_SYNC: 183 break; 184 case UCALL_DONE: 185 goto done; 186 default: 187 TEST_FAIL("Unknown ucall %lu", uc.cmd); 188 } 189 190 /* UCALL_SYNC is handled here. */ 191 TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && 192 uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx", 193 stage, (ulong)uc.args[1]); 194 195 } 196 197 done: 198 kvm_vm_free(vm); 199 } 200