1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Test Hyper-V extended hypercall, HV_EXT_CALL_QUERY_CAPABILITIES (0x8001), 4 * exit to userspace and receive result in guest. 5 * 6 * Negative tests are present in hyperv_features.c 7 * 8 * Copyright 2022 Google LLC 9 * Author: Vipin Sharma <vipinsh@google.com> 10 */ 11 12 #include "kvm_util.h" 13 #include "processor.h" 14 #include "hyperv.h" 15 16 /* Any value is fine */ 17 #define EXT_CAPABILITIES 0xbull 18 19 static void guest_code(vm_paddr_t in_pg_gpa, vm_paddr_t out_pg_gpa, 20 vm_vaddr_t out_pg_gva) 21 { 22 uint64_t *output_gva; 23 24 wrmsr(HV_X64_MSR_GUEST_OS_ID, HYPERV_LINUX_OS_ID); 25 wrmsr(HV_X64_MSR_HYPERCALL, in_pg_gpa); 26 27 output_gva = (uint64_t *)out_pg_gva; 28 29 hyperv_hypercall(HV_EXT_CALL_QUERY_CAPABILITIES, in_pg_gpa, out_pg_gpa); 30 31 /* TLFS states output will be a uint64_t value */ 32 GUEST_ASSERT_EQ(*output_gva, EXT_CAPABILITIES); 33 34 GUEST_DONE(); 35 } 36 37 int main(void) 38 { 39 vm_vaddr_t hcall_out_page; 40 vm_vaddr_t hcall_in_page; 41 struct kvm_vcpu *vcpu; 42 struct kvm_run *run; 43 struct kvm_vm *vm; 44 uint64_t *outval; 45 struct ucall uc; 46 47 /* Verify if extended hypercalls are supported */ 48 if (!kvm_cpuid_has(kvm_get_supported_hv_cpuid(), 49 HV_ENABLE_EXTENDED_HYPERCALLS)) { 50 print_skip("Extended calls not supported by the kernel"); 51 exit(KSFT_SKIP); 52 } 53 54 vm = vm_create_with_one_vcpu(&vcpu, guest_code); 55 run = vcpu->run; 56 vcpu_set_hv_cpuid(vcpu); 57 58 /* Hypercall input */ 59 hcall_in_page = vm_vaddr_alloc_pages(vm, 1); 60 memset(addr_gva2hva(vm, hcall_in_page), 0x0, vm->page_size); 61 62 /* Hypercall output */ 63 hcall_out_page = vm_vaddr_alloc_pages(vm, 1); 64 memset(addr_gva2hva(vm, hcall_out_page), 0x0, vm->page_size); 65 66 vcpu_args_set(vcpu, 3, addr_gva2gpa(vm, hcall_in_page), 67 addr_gva2gpa(vm, hcall_out_page), hcall_out_page); 68 69 vcpu_run(vcpu); 70 71 TEST_ASSERT(run->exit_reason == KVM_EXIT_HYPERV, 72 "Unexpected exit reason: %u (%s)", 73 run->exit_reason, exit_reason_str(run->exit_reason)); 74 75 outval = addr_gpa2hva(vm, run->hyperv.u.hcall.params[1]); 76 *outval = EXT_CAPABILITIES; 77 run->hyperv.u.hcall.result = HV_STATUS_SUCCESS; 78 79 vcpu_run(vcpu); 80 81 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, 82 "Unexpected exit reason: %u (%s)", 83 run->exit_reason, exit_reason_str(run->exit_reason)); 84 85 switch (get_ucall(vcpu, &uc)) { 86 case UCALL_ABORT: 87 REPORT_GUEST_ASSERT_2(uc, "arg1 = %ld, arg2 = %ld"); 88 break; 89 case UCALL_DONE: 90 break; 91 default: 92 TEST_FAIL("Unhandled ucall: %ld", uc.cmd); 93 } 94 95 kvm_vm_free(vm); 96 return 0; 97 } 98