18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * KVM Microsoft Hyper-V emulation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * derived from arch/x86/kvm/x86.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2006 Qumranet, Inc. 88c2ecf20Sopenharmony_ci * Copyright (C) 2008 Qumranet, Inc. 98c2ecf20Sopenharmony_ci * Copyright IBM Corporation, 2008 108c2ecf20Sopenharmony_ci * Copyright 2010 Red Hat, Inc. and/or its affiliates. 118c2ecf20Sopenharmony_ci * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com> 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Authors: 148c2ecf20Sopenharmony_ci * Avi Kivity <avi@qumranet.com> 158c2ecf20Sopenharmony_ci * Yaniv Kamay <yaniv@qumranet.com> 168c2ecf20Sopenharmony_ci * Amit Shah <amit.shah@qumranet.com> 178c2ecf20Sopenharmony_ci * Ben-Ami Yassour <benami@il.ibm.com> 188c2ecf20Sopenharmony_ci * Andrey Smetanin <asmetanin@virtuozzo.com> 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "x86.h" 228c2ecf20Sopenharmony_ci#include "lapic.h" 238c2ecf20Sopenharmony_ci#include "ioapic.h" 248c2ecf20Sopenharmony_ci#include "cpuid.h" 258c2ecf20Sopenharmony_ci#include "hyperv.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/cpu.h> 288c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 298c2ecf20Sopenharmony_ci#include <linux/highmem.h> 308c2ecf20Sopenharmony_ci#include <linux/sched/cputime.h> 318c2ecf20Sopenharmony_ci#include <linux/eventfd.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <asm/apicdef.h> 348c2ecf20Sopenharmony_ci#include <trace/events/kvm.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "trace.h" 378c2ecf20Sopenharmony_ci#include "irq.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define KVM_HV_MAX_SPARSE_VCPU_SET_BITS DIV_ROUND_UP(KVM_MAX_VCPUS, 64) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void stimer_mark_pending(struct kvm_vcpu_hv_stimer *stimer, 428c2ecf20Sopenharmony_ci bool vcpu_kick); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic inline u64 synic_read_sint(struct kvm_vcpu_hv_synic *synic, int sint) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci return atomic64_read(&synic->sint[sint]); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic inline int synic_get_sint_vector(u64 sint_value) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci if (sint_value & HV_SYNIC_SINT_MASKED) 528c2ecf20Sopenharmony_ci return -1; 538c2ecf20Sopenharmony_ci return sint_value & HV_SYNIC_SINT_VECTOR_MASK; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic bool synic_has_vector_connected(struct kvm_vcpu_hv_synic *synic, 578c2ecf20Sopenharmony_ci int vector) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci int i; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(synic->sint); i++) { 628c2ecf20Sopenharmony_ci if (synic_get_sint_vector(synic_read_sint(synic, i)) == vector) 638c2ecf20Sopenharmony_ci return true; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci return false; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic bool synic_has_vector_auto_eoi(struct kvm_vcpu_hv_synic *synic, 698c2ecf20Sopenharmony_ci int vector) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int i; 728c2ecf20Sopenharmony_ci u64 sint_value; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(synic->sint); i++) { 758c2ecf20Sopenharmony_ci sint_value = synic_read_sint(synic, i); 768c2ecf20Sopenharmony_ci if (synic_get_sint_vector(sint_value) == vector && 778c2ecf20Sopenharmony_ci sint_value & HV_SYNIC_SINT_AUTO_EOI) 788c2ecf20Sopenharmony_ci return true; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci return false; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void synic_update_vector(struct kvm_vcpu_hv_synic *synic, 848c2ecf20Sopenharmony_ci int vector) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci if (vector < HV_SYNIC_FIRST_VALID_VECTOR) 878c2ecf20Sopenharmony_ci return; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (synic_has_vector_connected(synic, vector)) 908c2ecf20Sopenharmony_ci __set_bit(vector, synic->vec_bitmap); 918c2ecf20Sopenharmony_ci else 928c2ecf20Sopenharmony_ci __clear_bit(vector, synic->vec_bitmap); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (synic_has_vector_auto_eoi(synic, vector)) 958c2ecf20Sopenharmony_ci __set_bit(vector, synic->auto_eoi_bitmap); 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci __clear_bit(vector, synic->auto_eoi_bitmap); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int synic_set_sint(struct kvm_vcpu_hv_synic *synic, int sint, 1018c2ecf20Sopenharmony_ci u64 data, bool host) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci int vector, old_vector; 1048c2ecf20Sopenharmony_ci bool masked; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci vector = data & HV_SYNIC_SINT_VECTOR_MASK; 1078c2ecf20Sopenharmony_ci masked = data & HV_SYNIC_SINT_MASKED; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Valid vectors are 16-255, however, nested Hyper-V attempts to write 1118c2ecf20Sopenharmony_ci * default '0x10000' value on boot and this should not #GP. We need to 1128c2ecf20Sopenharmony_ci * allow zero-initing the register from host as well. 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci if (vector < HV_SYNIC_FIRST_VALID_VECTOR && !host && !masked) 1158c2ecf20Sopenharmony_ci return 1; 1168c2ecf20Sopenharmony_ci /* 1178c2ecf20Sopenharmony_ci * Guest may configure multiple SINTs to use the same vector, so 1188c2ecf20Sopenharmony_ci * we maintain a bitmap of vectors handled by synic, and a 1198c2ecf20Sopenharmony_ci * bitmap of vectors with auto-eoi behavior. The bitmaps are 1208c2ecf20Sopenharmony_ci * updated here, and atomically queried on fast paths. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci old_vector = synic_read_sint(synic, sint) & HV_SYNIC_SINT_VECTOR_MASK; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci atomic64_set(&synic->sint[sint], data); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci synic_update_vector(synic, old_vector); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci synic_update_vector(synic, vector); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* Load SynIC vectors into EOI exit bitmap */ 1318c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_SCAN_IOAPIC, synic_to_vcpu(synic)); 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic struct kvm_vcpu *get_vcpu_by_vpidx(struct kvm *kvm, u32 vpidx) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = NULL; 1388c2ecf20Sopenharmony_ci int i; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (vpidx >= KVM_MAX_VCPUS) 1418c2ecf20Sopenharmony_ci return NULL; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci vcpu = kvm_get_vcpu(kvm, vpidx); 1448c2ecf20Sopenharmony_ci if (vcpu && vcpu_to_hv_vcpu(vcpu)->vp_index == vpidx) 1458c2ecf20Sopenharmony_ci return vcpu; 1468c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) 1478c2ecf20Sopenharmony_ci if (vcpu_to_hv_vcpu(vcpu)->vp_index == vpidx) 1488c2ecf20Sopenharmony_ci return vcpu; 1498c2ecf20Sopenharmony_ci return NULL; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vpidx) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 1558c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_synic *synic; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci vcpu = get_vcpu_by_vpidx(kvm, vpidx); 1588c2ecf20Sopenharmony_ci if (!vcpu) 1598c2ecf20Sopenharmony_ci return NULL; 1608c2ecf20Sopenharmony_ci synic = vcpu_to_synic(vcpu); 1618c2ecf20Sopenharmony_ci return (synic->active) ? synic : NULL; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct kvm *kvm = vcpu->kvm; 1678c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); 1688c2ecf20Sopenharmony_ci struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu); 1698c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_stimer *stimer; 1708c2ecf20Sopenharmony_ci int gsi, idx; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci trace_kvm_hv_notify_acked_sint(vcpu->vcpu_id, sint); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* Try to deliver pending Hyper-V SynIC timers messages */ 1758c2ecf20Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(hv_vcpu->stimer); idx++) { 1768c2ecf20Sopenharmony_ci stimer = &hv_vcpu->stimer[idx]; 1778c2ecf20Sopenharmony_ci if (stimer->msg_pending && stimer->config.enable && 1788c2ecf20Sopenharmony_ci !stimer->config.direct_mode && 1798c2ecf20Sopenharmony_ci stimer->config.sintx == sint) 1808c2ecf20Sopenharmony_ci stimer_mark_pending(stimer, false); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci idx = srcu_read_lock(&kvm->irq_srcu); 1848c2ecf20Sopenharmony_ci gsi = atomic_read(&synic->sint_to_gsi[sint]); 1858c2ecf20Sopenharmony_ci if (gsi != -1) 1868c2ecf20Sopenharmony_ci kvm_notify_acked_gsi(kvm, gsi); 1878c2ecf20Sopenharmony_ci srcu_read_unlock(&kvm->irq_srcu, idx); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void synic_exit(struct kvm_vcpu_hv_synic *synic, u32 msr) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = synic_to_vcpu(synic); 1938c2ecf20Sopenharmony_ci struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci hv_vcpu->exit.type = KVM_EXIT_HYPERV_SYNIC; 1968c2ecf20Sopenharmony_ci hv_vcpu->exit.u.synic.msr = msr; 1978c2ecf20Sopenharmony_ci hv_vcpu->exit.u.synic.control = synic->control; 1988c2ecf20Sopenharmony_ci hv_vcpu->exit.u.synic.evt_page = synic->evt_page; 1998c2ecf20Sopenharmony_ci hv_vcpu->exit.u.synic.msg_page = synic->msg_page; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_HV_EXIT, vcpu); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int synic_set_msr(struct kvm_vcpu_hv_synic *synic, 2058c2ecf20Sopenharmony_ci u32 msr, u64 data, bool host) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = synic_to_vcpu(synic); 2088c2ecf20Sopenharmony_ci int ret; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (!synic->active && (!host || data)) 2118c2ecf20Sopenharmony_ci return 1; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci trace_kvm_hv_synic_set_msr(vcpu->vcpu_id, msr, data, host); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci ret = 0; 2168c2ecf20Sopenharmony_ci switch (msr) { 2178c2ecf20Sopenharmony_ci case HV_X64_MSR_SCONTROL: 2188c2ecf20Sopenharmony_ci synic->control = data; 2198c2ecf20Sopenharmony_ci if (!host) 2208c2ecf20Sopenharmony_ci synic_exit(synic, msr); 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci case HV_X64_MSR_SVERSION: 2238c2ecf20Sopenharmony_ci if (!host) { 2248c2ecf20Sopenharmony_ci ret = 1; 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci synic->version = data; 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci case HV_X64_MSR_SIEFP: 2308c2ecf20Sopenharmony_ci if ((data & HV_SYNIC_SIEFP_ENABLE) && !host && 2318c2ecf20Sopenharmony_ci !synic->dont_zero_synic_pages) 2328c2ecf20Sopenharmony_ci if (kvm_clear_guest(vcpu->kvm, 2338c2ecf20Sopenharmony_ci data & PAGE_MASK, PAGE_SIZE)) { 2348c2ecf20Sopenharmony_ci ret = 1; 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci synic->evt_page = data; 2388c2ecf20Sopenharmony_ci if (!host) 2398c2ecf20Sopenharmony_ci synic_exit(synic, msr); 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci case HV_X64_MSR_SIMP: 2428c2ecf20Sopenharmony_ci if ((data & HV_SYNIC_SIMP_ENABLE) && !host && 2438c2ecf20Sopenharmony_ci !synic->dont_zero_synic_pages) 2448c2ecf20Sopenharmony_ci if (kvm_clear_guest(vcpu->kvm, 2458c2ecf20Sopenharmony_ci data & PAGE_MASK, PAGE_SIZE)) { 2468c2ecf20Sopenharmony_ci ret = 1; 2478c2ecf20Sopenharmony_ci break; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci synic->msg_page = data; 2508c2ecf20Sopenharmony_ci if (!host) 2518c2ecf20Sopenharmony_ci synic_exit(synic, msr); 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci case HV_X64_MSR_EOM: { 2548c2ecf20Sopenharmony_ci int i; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!synic->active) 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(synic->sint); i++) 2608c2ecf20Sopenharmony_ci kvm_hv_notify_acked_sint(vcpu, i); 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: 2648c2ecf20Sopenharmony_ci ret = synic_set_sint(synic, msr - HV_X64_MSR_SINT0, data, host); 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci default: 2678c2ecf20Sopenharmony_ci ret = 1; 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci return ret; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic bool kvm_hv_is_syndbg_enabled(struct kvm_vcpu *vcpu) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct kvm_cpuid_entry2 *entry; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci entry = kvm_find_cpuid_entry(vcpu, 2788c2ecf20Sopenharmony_ci HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES, 2798c2ecf20Sopenharmony_ci 0); 2808c2ecf20Sopenharmony_ci if (!entry) 2818c2ecf20Sopenharmony_ci return false; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return entry->eax & HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int kvm_hv_syndbg_complete_userspace(struct kvm_vcpu *vcpu) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct kvm *kvm = vcpu->kvm; 2898c2ecf20Sopenharmony_ci struct kvm_hv *hv = &kvm->arch.hyperv; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (vcpu->run->hyperv.u.syndbg.msr == HV_X64_MSR_SYNDBG_CONTROL) 2928c2ecf20Sopenharmony_ci hv->hv_syndbg.control.status = 2938c2ecf20Sopenharmony_ci vcpu->run->hyperv.u.syndbg.status; 2948c2ecf20Sopenharmony_ci return 1; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic void syndbg_exit(struct kvm_vcpu *vcpu, u32 msr) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct kvm_hv_syndbg *syndbg = vcpu_to_hv_syndbg(vcpu); 3008c2ecf20Sopenharmony_ci struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci hv_vcpu->exit.type = KVM_EXIT_HYPERV_SYNDBG; 3038c2ecf20Sopenharmony_ci hv_vcpu->exit.u.syndbg.msr = msr; 3048c2ecf20Sopenharmony_ci hv_vcpu->exit.u.syndbg.control = syndbg->control.control; 3058c2ecf20Sopenharmony_ci hv_vcpu->exit.u.syndbg.send_page = syndbg->control.send_page; 3068c2ecf20Sopenharmony_ci hv_vcpu->exit.u.syndbg.recv_page = syndbg->control.recv_page; 3078c2ecf20Sopenharmony_ci hv_vcpu->exit.u.syndbg.pending_page = syndbg->control.pending_page; 3088c2ecf20Sopenharmony_ci vcpu->arch.complete_userspace_io = 3098c2ecf20Sopenharmony_ci kvm_hv_syndbg_complete_userspace; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_HV_EXIT, vcpu); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int syndbg_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct kvm_hv_syndbg *syndbg = vcpu_to_hv_syndbg(vcpu); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (!kvm_hv_is_syndbg_enabled(vcpu) && !host) 3198c2ecf20Sopenharmony_ci return 1; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci trace_kvm_hv_syndbg_set_msr(vcpu->vcpu_id, 3228c2ecf20Sopenharmony_ci vcpu_to_hv_vcpu(vcpu)->vp_index, msr, data); 3238c2ecf20Sopenharmony_ci switch (msr) { 3248c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_CONTROL: 3258c2ecf20Sopenharmony_ci syndbg->control.control = data; 3268c2ecf20Sopenharmony_ci if (!host) 3278c2ecf20Sopenharmony_ci syndbg_exit(vcpu, msr); 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_STATUS: 3308c2ecf20Sopenharmony_ci syndbg->control.status = data; 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_SEND_BUFFER: 3338c2ecf20Sopenharmony_ci syndbg->control.send_page = data; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_RECV_BUFFER: 3368c2ecf20Sopenharmony_ci syndbg->control.recv_page = data; 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_PENDING_BUFFER: 3398c2ecf20Sopenharmony_ci syndbg->control.pending_page = data; 3408c2ecf20Sopenharmony_ci if (!host) 3418c2ecf20Sopenharmony_ci syndbg_exit(vcpu, msr); 3428c2ecf20Sopenharmony_ci break; 3438c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_OPTIONS: 3448c2ecf20Sopenharmony_ci syndbg->options = data; 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci default: 3478c2ecf20Sopenharmony_ci break; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic int syndbg_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct kvm_hv_syndbg *syndbg = vcpu_to_hv_syndbg(vcpu); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (!kvm_hv_is_syndbg_enabled(vcpu) && !host) 3588c2ecf20Sopenharmony_ci return 1; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci switch (msr) { 3618c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_CONTROL: 3628c2ecf20Sopenharmony_ci *pdata = syndbg->control.control; 3638c2ecf20Sopenharmony_ci break; 3648c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_STATUS: 3658c2ecf20Sopenharmony_ci *pdata = syndbg->control.status; 3668c2ecf20Sopenharmony_ci break; 3678c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_SEND_BUFFER: 3688c2ecf20Sopenharmony_ci *pdata = syndbg->control.send_page; 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_RECV_BUFFER: 3718c2ecf20Sopenharmony_ci *pdata = syndbg->control.recv_page; 3728c2ecf20Sopenharmony_ci break; 3738c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_PENDING_BUFFER: 3748c2ecf20Sopenharmony_ci *pdata = syndbg->control.pending_page; 3758c2ecf20Sopenharmony_ci break; 3768c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_OPTIONS: 3778c2ecf20Sopenharmony_ci *pdata = syndbg->options; 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci default: 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci trace_kvm_hv_syndbg_get_msr(vcpu->vcpu_id, 3848c2ecf20Sopenharmony_ci vcpu_to_hv_vcpu(vcpu)->vp_index, msr, 3858c2ecf20Sopenharmony_ci *pdata); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return 0; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int synic_get_msr(struct kvm_vcpu_hv_synic *synic, u32 msr, u64 *pdata, 3918c2ecf20Sopenharmony_ci bool host) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci int ret; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (!synic->active && !host) 3968c2ecf20Sopenharmony_ci return 1; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci ret = 0; 3998c2ecf20Sopenharmony_ci switch (msr) { 4008c2ecf20Sopenharmony_ci case HV_X64_MSR_SCONTROL: 4018c2ecf20Sopenharmony_ci *pdata = synic->control; 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci case HV_X64_MSR_SVERSION: 4048c2ecf20Sopenharmony_ci *pdata = synic->version; 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case HV_X64_MSR_SIEFP: 4078c2ecf20Sopenharmony_ci *pdata = synic->evt_page; 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci case HV_X64_MSR_SIMP: 4108c2ecf20Sopenharmony_ci *pdata = synic->msg_page; 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci case HV_X64_MSR_EOM: 4138c2ecf20Sopenharmony_ci *pdata = 0; 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: 4168c2ecf20Sopenharmony_ci *pdata = atomic64_read(&synic->sint[msr - HV_X64_MSR_SINT0]); 4178c2ecf20Sopenharmony_ci break; 4188c2ecf20Sopenharmony_ci default: 4198c2ecf20Sopenharmony_ci ret = 1; 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci return ret; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int synic_set_irq(struct kvm_vcpu_hv_synic *synic, u32 sint) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = synic_to_vcpu(synic); 4288c2ecf20Sopenharmony_ci struct kvm_lapic_irq irq; 4298c2ecf20Sopenharmony_ci int ret, vector; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (KVM_BUG_ON(!lapic_in_kernel(vcpu), vcpu->kvm)) 4328c2ecf20Sopenharmony_ci return -EINVAL; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (sint >= ARRAY_SIZE(synic->sint)) 4358c2ecf20Sopenharmony_ci return -EINVAL; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci vector = synic_get_sint_vector(synic_read_sint(synic, sint)); 4388c2ecf20Sopenharmony_ci if (vector < 0) 4398c2ecf20Sopenharmony_ci return -ENOENT; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci memset(&irq, 0, sizeof(irq)); 4428c2ecf20Sopenharmony_ci irq.shorthand = APIC_DEST_SELF; 4438c2ecf20Sopenharmony_ci irq.dest_mode = APIC_DEST_PHYSICAL; 4448c2ecf20Sopenharmony_ci irq.delivery_mode = APIC_DM_FIXED; 4458c2ecf20Sopenharmony_ci irq.vector = vector; 4468c2ecf20Sopenharmony_ci irq.level = 1; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ret = kvm_irq_delivery_to_apic(vcpu->kvm, vcpu->arch.apic, &irq, NULL); 4498c2ecf20Sopenharmony_ci trace_kvm_hv_synic_set_irq(vcpu->vcpu_id, sint, irq.vector, ret); 4508c2ecf20Sopenharmony_ci return ret; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ciint kvm_hv_synic_set_irq(struct kvm *kvm, u32 vpidx, u32 sint) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_synic *synic; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci synic = synic_get(kvm, vpidx); 4588c2ecf20Sopenharmony_ci if (!synic) 4598c2ecf20Sopenharmony_ci return -EINVAL; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return synic_set_irq(synic, sint); 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_civoid kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); 4678c2ecf20Sopenharmony_ci int i; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci trace_kvm_hv_synic_send_eoi(vcpu->vcpu_id, vector); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(synic->sint); i++) 4728c2ecf20Sopenharmony_ci if (synic_get_sint_vector(synic_read_sint(synic, i)) == vector) 4738c2ecf20Sopenharmony_ci kvm_hv_notify_acked_sint(vcpu, i); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vpidx, u32 sint, int gsi) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_synic *synic; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci synic = synic_get(kvm, vpidx); 4818c2ecf20Sopenharmony_ci if (!synic) 4828c2ecf20Sopenharmony_ci return -EINVAL; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (sint >= ARRAY_SIZE(synic->sint_to_gsi)) 4858c2ecf20Sopenharmony_ci return -EINVAL; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci atomic_set(&synic->sint_to_gsi[sint], gsi); 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_civoid kvm_hv_irq_routing_update(struct kvm *kvm) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci struct kvm_irq_routing_table *irq_rt; 4948c2ecf20Sopenharmony_ci struct kvm_kernel_irq_routing_entry *e; 4958c2ecf20Sopenharmony_ci u32 gsi; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu, 4988c2ecf20Sopenharmony_ci lockdep_is_held(&kvm->irq_lock)); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci for (gsi = 0; gsi < irq_rt->nr_rt_entries; gsi++) { 5018c2ecf20Sopenharmony_ci hlist_for_each_entry(e, &irq_rt->map[gsi], link) { 5028c2ecf20Sopenharmony_ci if (e->type == KVM_IRQ_ROUTING_HV_SINT) 5038c2ecf20Sopenharmony_ci kvm_hv_set_sint_gsi(kvm, e->hv_sint.vcpu, 5048c2ecf20Sopenharmony_ci e->hv_sint.sint, gsi); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic void synic_init(struct kvm_vcpu_hv_synic *synic) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci int i; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci memset(synic, 0, sizeof(*synic)); 5148c2ecf20Sopenharmony_ci synic->version = HV_SYNIC_VERSION_1; 5158c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(synic->sint); i++) { 5168c2ecf20Sopenharmony_ci atomic64_set(&synic->sint[i], HV_SYNIC_SINT_MASKED); 5178c2ecf20Sopenharmony_ci atomic_set(&synic->sint_to_gsi[i], -1); 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic u64 get_time_ref_counter(struct kvm *kvm) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct kvm_hv *hv = &kvm->arch.hyperv; 5248c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 5258c2ecf20Sopenharmony_ci u64 tsc; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* 5288c2ecf20Sopenharmony_ci * The guest has not set up the TSC page or the clock isn't 5298c2ecf20Sopenharmony_ci * stable, fall back to get_kvmclock_ns. 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_ci if (!hv->tsc_ref.tsc_sequence) 5328c2ecf20Sopenharmony_ci return div_u64(get_kvmclock_ns(kvm), 100); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci vcpu = kvm_get_vcpu(kvm, 0); 5358c2ecf20Sopenharmony_ci tsc = kvm_read_l1_tsc(vcpu, rdtsc()); 5368c2ecf20Sopenharmony_ci return mul_u64_u64_shr(tsc, hv->tsc_ref.tsc_scale, 64) 5378c2ecf20Sopenharmony_ci + hv->tsc_ref.tsc_offset; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic void stimer_mark_pending(struct kvm_vcpu_hv_stimer *stimer, 5418c2ecf20Sopenharmony_ci bool vcpu_kick) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci set_bit(stimer->index, 5468c2ecf20Sopenharmony_ci vcpu_to_hv_vcpu(vcpu)->stimer_pending_bitmap); 5478c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_HV_STIMER, vcpu); 5488c2ecf20Sopenharmony_ci if (vcpu_kick) 5498c2ecf20Sopenharmony_ci kvm_vcpu_kick(vcpu); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic void stimer_cleanup(struct kvm_vcpu_hv_stimer *stimer) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci trace_kvm_hv_stimer_cleanup(stimer_to_vcpu(stimer)->vcpu_id, 5578c2ecf20Sopenharmony_ci stimer->index); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci hrtimer_cancel(&stimer->timer); 5608c2ecf20Sopenharmony_ci clear_bit(stimer->index, 5618c2ecf20Sopenharmony_ci vcpu_to_hv_vcpu(vcpu)->stimer_pending_bitmap); 5628c2ecf20Sopenharmony_ci stimer->msg_pending = false; 5638c2ecf20Sopenharmony_ci stimer->exp_time = 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic enum hrtimer_restart stimer_timer_callback(struct hrtimer *timer) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_stimer *stimer; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci stimer = container_of(timer, struct kvm_vcpu_hv_stimer, timer); 5718c2ecf20Sopenharmony_ci trace_kvm_hv_stimer_callback(stimer_to_vcpu(stimer)->vcpu_id, 5728c2ecf20Sopenharmony_ci stimer->index); 5738c2ecf20Sopenharmony_ci stimer_mark_pending(stimer, true); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci return HRTIMER_NORESTART; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci/* 5798c2ecf20Sopenharmony_ci * stimer_start() assumptions: 5808c2ecf20Sopenharmony_ci * a) stimer->count is not equal to 0 5818c2ecf20Sopenharmony_ci * b) stimer->config has HV_STIMER_ENABLE flag 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_cistatic int stimer_start(struct kvm_vcpu_hv_stimer *stimer) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci u64 time_now; 5868c2ecf20Sopenharmony_ci ktime_t ktime_now; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci time_now = get_time_ref_counter(stimer_to_vcpu(stimer)->kvm); 5898c2ecf20Sopenharmony_ci ktime_now = ktime_get(); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (stimer->config.periodic) { 5928c2ecf20Sopenharmony_ci if (stimer->exp_time) { 5938c2ecf20Sopenharmony_ci if (time_now >= stimer->exp_time) { 5948c2ecf20Sopenharmony_ci u64 remainder; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci div64_u64_rem(time_now - stimer->exp_time, 5978c2ecf20Sopenharmony_ci stimer->count, &remainder); 5988c2ecf20Sopenharmony_ci stimer->exp_time = 5998c2ecf20Sopenharmony_ci time_now + (stimer->count - remainder); 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci } else 6028c2ecf20Sopenharmony_ci stimer->exp_time = time_now + stimer->count; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci trace_kvm_hv_stimer_start_periodic( 6058c2ecf20Sopenharmony_ci stimer_to_vcpu(stimer)->vcpu_id, 6068c2ecf20Sopenharmony_ci stimer->index, 6078c2ecf20Sopenharmony_ci time_now, stimer->exp_time); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci hrtimer_start(&stimer->timer, 6108c2ecf20Sopenharmony_ci ktime_add_ns(ktime_now, 6118c2ecf20Sopenharmony_ci 100 * (stimer->exp_time - time_now)), 6128c2ecf20Sopenharmony_ci HRTIMER_MODE_ABS); 6138c2ecf20Sopenharmony_ci return 0; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci stimer->exp_time = stimer->count; 6168c2ecf20Sopenharmony_ci if (time_now >= stimer->count) { 6178c2ecf20Sopenharmony_ci /* 6188c2ecf20Sopenharmony_ci * Expire timer according to Hypervisor Top-Level Functional 6198c2ecf20Sopenharmony_ci * specification v4(15.3.1): 6208c2ecf20Sopenharmony_ci * "If a one shot is enabled and the specified count is in 6218c2ecf20Sopenharmony_ci * the past, it will expire immediately." 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci stimer_mark_pending(stimer, false); 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci trace_kvm_hv_stimer_start_one_shot(stimer_to_vcpu(stimer)->vcpu_id, 6288c2ecf20Sopenharmony_ci stimer->index, 6298c2ecf20Sopenharmony_ci time_now, stimer->count); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci hrtimer_start(&stimer->timer, 6328c2ecf20Sopenharmony_ci ktime_add_ns(ktime_now, 100 * (stimer->count - time_now)), 6338c2ecf20Sopenharmony_ci HRTIMER_MODE_ABS); 6348c2ecf20Sopenharmony_ci return 0; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic int stimer_set_config(struct kvm_vcpu_hv_stimer *stimer, u64 config, 6388c2ecf20Sopenharmony_ci bool host) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci union hv_stimer_config new_config = {.as_uint64 = config}, 6418c2ecf20Sopenharmony_ci old_config = {.as_uint64 = stimer->config.as_uint64}; 6428c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); 6438c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (!synic->active && (!host || config)) 6468c2ecf20Sopenharmony_ci return 1; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci trace_kvm_hv_stimer_set_config(stimer_to_vcpu(stimer)->vcpu_id, 6498c2ecf20Sopenharmony_ci stimer->index, config, host); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci stimer_cleanup(stimer); 6528c2ecf20Sopenharmony_ci if (old_config.enable && 6538c2ecf20Sopenharmony_ci !new_config.direct_mode && new_config.sintx == 0) 6548c2ecf20Sopenharmony_ci new_config.enable = 0; 6558c2ecf20Sopenharmony_ci stimer->config.as_uint64 = new_config.as_uint64; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (stimer->config.enable) 6588c2ecf20Sopenharmony_ci stimer_mark_pending(stimer, false); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return 0; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int stimer_set_count(struct kvm_vcpu_hv_stimer *stimer, u64 count, 6648c2ecf20Sopenharmony_ci bool host) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); 6678c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (!synic->active && (!host || count)) 6708c2ecf20Sopenharmony_ci return 1; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci trace_kvm_hv_stimer_set_count(stimer_to_vcpu(stimer)->vcpu_id, 6738c2ecf20Sopenharmony_ci stimer->index, count, host); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci stimer_cleanup(stimer); 6768c2ecf20Sopenharmony_ci stimer->count = count; 6778c2ecf20Sopenharmony_ci if (!host) { 6788c2ecf20Sopenharmony_ci if (stimer->count == 0) 6798c2ecf20Sopenharmony_ci stimer->config.enable = 0; 6808c2ecf20Sopenharmony_ci else if (stimer->config.auto_enable) 6818c2ecf20Sopenharmony_ci stimer->config.enable = 1; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (stimer->config.enable) 6858c2ecf20Sopenharmony_ci stimer_mark_pending(stimer, false); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic int stimer_get_config(struct kvm_vcpu_hv_stimer *stimer, u64 *pconfig) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci *pconfig = stimer->config.as_uint64; 6938c2ecf20Sopenharmony_ci return 0; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic int stimer_get_count(struct kvm_vcpu_hv_stimer *stimer, u64 *pcount) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci *pcount = stimer->count; 6998c2ecf20Sopenharmony_ci return 0; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic int synic_deliver_msg(struct kvm_vcpu_hv_synic *synic, u32 sint, 7038c2ecf20Sopenharmony_ci struct hv_message *src_msg, bool no_retry) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = synic_to_vcpu(synic); 7068c2ecf20Sopenharmony_ci int msg_off = offsetof(struct hv_message_page, sint_message[sint]); 7078c2ecf20Sopenharmony_ci gfn_t msg_page_gfn; 7088c2ecf20Sopenharmony_ci struct hv_message_header hv_hdr; 7098c2ecf20Sopenharmony_ci int r; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (!(synic->msg_page & HV_SYNIC_SIMP_ENABLE)) 7128c2ecf20Sopenharmony_ci return -ENOENT; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci msg_page_gfn = synic->msg_page >> PAGE_SHIFT; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* 7178c2ecf20Sopenharmony_ci * Strictly following the spec-mandated ordering would assume setting 7188c2ecf20Sopenharmony_ci * .msg_pending before checking .message_type. However, this function 7198c2ecf20Sopenharmony_ci * is only called in vcpu context so the entire update is atomic from 7208c2ecf20Sopenharmony_ci * guest POV and thus the exact order here doesn't matter. 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci r = kvm_vcpu_read_guest_page(vcpu, msg_page_gfn, &hv_hdr.message_type, 7238c2ecf20Sopenharmony_ci msg_off + offsetof(struct hv_message, 7248c2ecf20Sopenharmony_ci header.message_type), 7258c2ecf20Sopenharmony_ci sizeof(hv_hdr.message_type)); 7268c2ecf20Sopenharmony_ci if (r < 0) 7278c2ecf20Sopenharmony_ci return r; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci if (hv_hdr.message_type != HVMSG_NONE) { 7308c2ecf20Sopenharmony_ci if (no_retry) 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci hv_hdr.message_flags.msg_pending = 1; 7348c2ecf20Sopenharmony_ci r = kvm_vcpu_write_guest_page(vcpu, msg_page_gfn, 7358c2ecf20Sopenharmony_ci &hv_hdr.message_flags, 7368c2ecf20Sopenharmony_ci msg_off + 7378c2ecf20Sopenharmony_ci offsetof(struct hv_message, 7388c2ecf20Sopenharmony_ci header.message_flags), 7398c2ecf20Sopenharmony_ci sizeof(hv_hdr.message_flags)); 7408c2ecf20Sopenharmony_ci if (r < 0) 7418c2ecf20Sopenharmony_ci return r; 7428c2ecf20Sopenharmony_ci return -EAGAIN; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci r = kvm_vcpu_write_guest_page(vcpu, msg_page_gfn, src_msg, msg_off, 7468c2ecf20Sopenharmony_ci sizeof(src_msg->header) + 7478c2ecf20Sopenharmony_ci src_msg->header.payload_size); 7488c2ecf20Sopenharmony_ci if (r < 0) 7498c2ecf20Sopenharmony_ci return r; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci r = synic_set_irq(synic, sint); 7528c2ecf20Sopenharmony_ci if (r < 0) 7538c2ecf20Sopenharmony_ci return r; 7548c2ecf20Sopenharmony_ci if (r == 0) 7558c2ecf20Sopenharmony_ci return -EFAULT; 7568c2ecf20Sopenharmony_ci return 0; 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_cistatic int stimer_send_msg(struct kvm_vcpu_hv_stimer *stimer) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); 7628c2ecf20Sopenharmony_ci struct hv_message *msg = &stimer->msg; 7638c2ecf20Sopenharmony_ci struct hv_timer_message_payload *payload = 7648c2ecf20Sopenharmony_ci (struct hv_timer_message_payload *)&msg->u.payload; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci /* 7678c2ecf20Sopenharmony_ci * To avoid piling up periodic ticks, don't retry message 7688c2ecf20Sopenharmony_ci * delivery for them (within "lazy" lost ticks policy). 7698c2ecf20Sopenharmony_ci */ 7708c2ecf20Sopenharmony_ci bool no_retry = stimer->config.periodic; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci payload->expiration_time = stimer->exp_time; 7738c2ecf20Sopenharmony_ci payload->delivery_time = get_time_ref_counter(vcpu->kvm); 7748c2ecf20Sopenharmony_ci return synic_deliver_msg(vcpu_to_synic(vcpu), 7758c2ecf20Sopenharmony_ci stimer->config.sintx, msg, 7768c2ecf20Sopenharmony_ci no_retry); 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic int stimer_notify_direct(struct kvm_vcpu_hv_stimer *stimer) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); 7828c2ecf20Sopenharmony_ci struct kvm_lapic_irq irq = { 7838c2ecf20Sopenharmony_ci .delivery_mode = APIC_DM_FIXED, 7848c2ecf20Sopenharmony_ci .vector = stimer->config.apic_vector 7858c2ecf20Sopenharmony_ci }; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (lapic_in_kernel(vcpu)) 7888c2ecf20Sopenharmony_ci return !kvm_apic_set_irq(vcpu, &irq, NULL); 7898c2ecf20Sopenharmony_ci return 0; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic void stimer_expiration(struct kvm_vcpu_hv_stimer *stimer) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci int r, direct = stimer->config.direct_mode; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci stimer->msg_pending = true; 7978c2ecf20Sopenharmony_ci if (!direct) 7988c2ecf20Sopenharmony_ci r = stimer_send_msg(stimer); 7998c2ecf20Sopenharmony_ci else 8008c2ecf20Sopenharmony_ci r = stimer_notify_direct(stimer); 8018c2ecf20Sopenharmony_ci trace_kvm_hv_stimer_expiration(stimer_to_vcpu(stimer)->vcpu_id, 8028c2ecf20Sopenharmony_ci stimer->index, direct, r); 8038c2ecf20Sopenharmony_ci if (!r) { 8048c2ecf20Sopenharmony_ci stimer->msg_pending = false; 8058c2ecf20Sopenharmony_ci if (!(stimer->config.periodic)) 8068c2ecf20Sopenharmony_ci stimer->config.enable = 0; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_civoid kvm_hv_process_stimers(struct kvm_vcpu *vcpu) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu); 8138c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_stimer *stimer; 8148c2ecf20Sopenharmony_ci u64 time_now, exp_time; 8158c2ecf20Sopenharmony_ci int i; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++) 8188c2ecf20Sopenharmony_ci if (test_and_clear_bit(i, hv_vcpu->stimer_pending_bitmap)) { 8198c2ecf20Sopenharmony_ci stimer = &hv_vcpu->stimer[i]; 8208c2ecf20Sopenharmony_ci if (stimer->config.enable) { 8218c2ecf20Sopenharmony_ci exp_time = stimer->exp_time; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci if (exp_time) { 8248c2ecf20Sopenharmony_ci time_now = 8258c2ecf20Sopenharmony_ci get_time_ref_counter(vcpu->kvm); 8268c2ecf20Sopenharmony_ci if (time_now >= exp_time) 8278c2ecf20Sopenharmony_ci stimer_expiration(stimer); 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if ((stimer->config.enable) && 8318c2ecf20Sopenharmony_ci stimer->count) { 8328c2ecf20Sopenharmony_ci if (!stimer->msg_pending) 8338c2ecf20Sopenharmony_ci stimer_start(stimer); 8348c2ecf20Sopenharmony_ci } else 8358c2ecf20Sopenharmony_ci stimer_cleanup(stimer); 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_civoid kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu); 8438c2ecf20Sopenharmony_ci int i; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++) 8468c2ecf20Sopenharmony_ci stimer_cleanup(&hv_vcpu->stimer[i]); 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cibool kvm_hv_assist_page_enabled(struct kvm_vcpu *vcpu) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci if (!(vcpu->arch.hyperv.hv_vapic & HV_X64_MSR_VP_ASSIST_PAGE_ENABLE)) 8528c2ecf20Sopenharmony_ci return false; 8538c2ecf20Sopenharmony_ci return vcpu->arch.pv_eoi.msr_val & KVM_MSR_ENABLED; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvm_hv_assist_page_enabled); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cibool kvm_hv_get_assist_page(struct kvm_vcpu *vcpu, 8588c2ecf20Sopenharmony_ci struct hv_vp_assist_page *assist_page) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci if (!kvm_hv_assist_page_enabled(vcpu)) 8618c2ecf20Sopenharmony_ci return false; 8628c2ecf20Sopenharmony_ci return !kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.pv_eoi.data, 8638c2ecf20Sopenharmony_ci assist_page, sizeof(*assist_page)); 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvm_hv_get_assist_page); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic void stimer_prepare_msg(struct kvm_vcpu_hv_stimer *stimer) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct hv_message *msg = &stimer->msg; 8708c2ecf20Sopenharmony_ci struct hv_timer_message_payload *payload = 8718c2ecf20Sopenharmony_ci (struct hv_timer_message_payload *)&msg->u.payload; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci memset(&msg->header, 0, sizeof(msg->header)); 8748c2ecf20Sopenharmony_ci msg->header.message_type = HVMSG_TIMER_EXPIRED; 8758c2ecf20Sopenharmony_ci msg->header.payload_size = sizeof(*payload); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci payload->timer_index = stimer->index; 8788c2ecf20Sopenharmony_ci payload->expiration_time = 0; 8798c2ecf20Sopenharmony_ci payload->delivery_time = 0; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic void stimer_init(struct kvm_vcpu_hv_stimer *stimer, int timer_index) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci memset(stimer, 0, sizeof(*stimer)); 8858c2ecf20Sopenharmony_ci stimer->index = timer_index; 8868c2ecf20Sopenharmony_ci hrtimer_init(&stimer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 8878c2ecf20Sopenharmony_ci stimer->timer.function = stimer_timer_callback; 8888c2ecf20Sopenharmony_ci stimer_prepare_msg(stimer); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_civoid kvm_hv_vcpu_init(struct kvm_vcpu *vcpu) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu); 8948c2ecf20Sopenharmony_ci int i; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci synic_init(&hv_vcpu->synic); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci bitmap_zero(hv_vcpu->stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT); 8998c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++) 9008c2ecf20Sopenharmony_ci stimer_init(&hv_vcpu->stimer[i], i); 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_civoid kvm_hv_vcpu_postcreate(struct kvm_vcpu *vcpu) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci hv_vcpu->vp_index = kvm_vcpu_get_idx(vcpu); 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ciint kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci /* 9158c2ecf20Sopenharmony_ci * Hyper-V SynIC auto EOI SINT's are 9168c2ecf20Sopenharmony_ci * not compatible with APICV, so request 9178c2ecf20Sopenharmony_ci * to deactivate APICV permanently. 9188c2ecf20Sopenharmony_ci */ 9198c2ecf20Sopenharmony_ci kvm_request_apicv_update(vcpu->kvm, false, APICV_INHIBIT_REASON_HYPERV); 9208c2ecf20Sopenharmony_ci synic->active = true; 9218c2ecf20Sopenharmony_ci synic->dont_zero_synic_pages = dont_zero_synic_pages; 9228c2ecf20Sopenharmony_ci synic->control = HV_SYNIC_CONTROL_ENABLE; 9238c2ecf20Sopenharmony_ci return 0; 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cistatic bool kvm_hv_msr_partition_wide(u32 msr) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci bool r = false; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci switch (msr) { 9318c2ecf20Sopenharmony_ci case HV_X64_MSR_GUEST_OS_ID: 9328c2ecf20Sopenharmony_ci case HV_X64_MSR_HYPERCALL: 9338c2ecf20Sopenharmony_ci case HV_X64_MSR_REFERENCE_TSC: 9348c2ecf20Sopenharmony_ci case HV_X64_MSR_TIME_REF_COUNT: 9358c2ecf20Sopenharmony_ci case HV_X64_MSR_CRASH_CTL: 9368c2ecf20Sopenharmony_ci case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: 9378c2ecf20Sopenharmony_ci case HV_X64_MSR_RESET: 9388c2ecf20Sopenharmony_ci case HV_X64_MSR_REENLIGHTENMENT_CONTROL: 9398c2ecf20Sopenharmony_ci case HV_X64_MSR_TSC_EMULATION_CONTROL: 9408c2ecf20Sopenharmony_ci case HV_X64_MSR_TSC_EMULATION_STATUS: 9418c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_OPTIONS: 9428c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER: 9438c2ecf20Sopenharmony_ci r = true; 9448c2ecf20Sopenharmony_ci break; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return r; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu, 9518c2ecf20Sopenharmony_ci u32 index, u64 *pdata) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 9548c2ecf20Sopenharmony_ci size_t size = ARRAY_SIZE(hv->hv_crash_param); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(index >= size)) 9578c2ecf20Sopenharmony_ci return -EINVAL; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci *pdata = hv->hv_crash_param[array_index_nospec(index, size)]; 9608c2ecf20Sopenharmony_ci return 0; 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic int kvm_hv_msr_get_crash_ctl(struct kvm_vcpu *vcpu, u64 *pdata) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci *pdata = hv->hv_crash_ctl; 9688c2ecf20Sopenharmony_ci return 0; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic int kvm_hv_msr_set_crash_ctl(struct kvm_vcpu *vcpu, u64 data, bool host) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (host) 9768c2ecf20Sopenharmony_ci hv->hv_crash_ctl = data & HV_CRASH_CTL_CRASH_NOTIFY; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (!host && (data & HV_CRASH_CTL_CRASH_NOTIFY)) { 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci vcpu_debug(vcpu, "hv crash (0x%llx 0x%llx 0x%llx 0x%llx 0x%llx)\n", 9818c2ecf20Sopenharmony_ci hv->hv_crash_param[0], 9828c2ecf20Sopenharmony_ci hv->hv_crash_param[1], 9838c2ecf20Sopenharmony_ci hv->hv_crash_param[2], 9848c2ecf20Sopenharmony_ci hv->hv_crash_param[3], 9858c2ecf20Sopenharmony_ci hv->hv_crash_param[4]); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* Send notification about crash to user space */ 9888c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_HV_CRASH, vcpu); 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci return 0; 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu, 9958c2ecf20Sopenharmony_ci u32 index, u64 data) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 9988c2ecf20Sopenharmony_ci size_t size = ARRAY_SIZE(hv->hv_crash_param); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(index >= size)) 10018c2ecf20Sopenharmony_ci return -EINVAL; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci hv->hv_crash_param[array_index_nospec(index, size)] = data; 10048c2ecf20Sopenharmony_ci return 0; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci/* 10088c2ecf20Sopenharmony_ci * The kvmclock and Hyper-V TSC page use similar formulas, and converting 10098c2ecf20Sopenharmony_ci * between them is possible: 10108c2ecf20Sopenharmony_ci * 10118c2ecf20Sopenharmony_ci * kvmclock formula: 10128c2ecf20Sopenharmony_ci * nsec = (ticks - tsc_timestamp) * tsc_to_system_mul * 2^(tsc_shift-32) 10138c2ecf20Sopenharmony_ci * + system_time 10148c2ecf20Sopenharmony_ci * 10158c2ecf20Sopenharmony_ci * Hyper-V formula: 10168c2ecf20Sopenharmony_ci * nsec/100 = ticks * scale / 2^64 + offset 10178c2ecf20Sopenharmony_ci * 10188c2ecf20Sopenharmony_ci * When tsc_timestamp = system_time = 0, offset is zero in the Hyper-V formula. 10198c2ecf20Sopenharmony_ci * By dividing the kvmclock formula by 100 and equating what's left we get: 10208c2ecf20Sopenharmony_ci * ticks * scale / 2^64 = ticks * tsc_to_system_mul * 2^(tsc_shift-32) / 100 10218c2ecf20Sopenharmony_ci * scale / 2^64 = tsc_to_system_mul * 2^(tsc_shift-32) / 100 10228c2ecf20Sopenharmony_ci * scale = tsc_to_system_mul * 2^(32+tsc_shift) / 100 10238c2ecf20Sopenharmony_ci * 10248c2ecf20Sopenharmony_ci * Now expand the kvmclock formula and divide by 100: 10258c2ecf20Sopenharmony_ci * nsec = ticks * tsc_to_system_mul * 2^(tsc_shift-32) 10268c2ecf20Sopenharmony_ci * - tsc_timestamp * tsc_to_system_mul * 2^(tsc_shift-32) 10278c2ecf20Sopenharmony_ci * + system_time 10288c2ecf20Sopenharmony_ci * nsec/100 = ticks * tsc_to_system_mul * 2^(tsc_shift-32) / 100 10298c2ecf20Sopenharmony_ci * - tsc_timestamp * tsc_to_system_mul * 2^(tsc_shift-32) / 100 10308c2ecf20Sopenharmony_ci * + system_time / 100 10318c2ecf20Sopenharmony_ci * 10328c2ecf20Sopenharmony_ci * Replace tsc_to_system_mul * 2^(tsc_shift-32) / 100 by scale / 2^64: 10338c2ecf20Sopenharmony_ci * nsec/100 = ticks * scale / 2^64 10348c2ecf20Sopenharmony_ci * - tsc_timestamp * scale / 2^64 10358c2ecf20Sopenharmony_ci * + system_time / 100 10368c2ecf20Sopenharmony_ci * 10378c2ecf20Sopenharmony_ci * Equate with the Hyper-V formula so that ticks * scale / 2^64 cancels out: 10388c2ecf20Sopenharmony_ci * offset = system_time / 100 - tsc_timestamp * scale / 2^64 10398c2ecf20Sopenharmony_ci * 10408c2ecf20Sopenharmony_ci * These two equivalencies are implemented in this function. 10418c2ecf20Sopenharmony_ci */ 10428c2ecf20Sopenharmony_cistatic bool compute_tsc_page_parameters(struct pvclock_vcpu_time_info *hv_clock, 10438c2ecf20Sopenharmony_ci struct ms_hyperv_tsc_page *tsc_ref) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci u64 max_mul; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (!(hv_clock->flags & PVCLOCK_TSC_STABLE_BIT)) 10488c2ecf20Sopenharmony_ci return false; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* 10518c2ecf20Sopenharmony_ci * check if scale would overflow, if so we use the time ref counter 10528c2ecf20Sopenharmony_ci * tsc_to_system_mul * 2^(tsc_shift+32) / 100 >= 2^64 10538c2ecf20Sopenharmony_ci * tsc_to_system_mul / 100 >= 2^(32-tsc_shift) 10548c2ecf20Sopenharmony_ci * tsc_to_system_mul >= 100 * 2^(32-tsc_shift) 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci max_mul = 100ull << (32 - hv_clock->tsc_shift); 10578c2ecf20Sopenharmony_ci if (hv_clock->tsc_to_system_mul >= max_mul) 10588c2ecf20Sopenharmony_ci return false; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci /* 10618c2ecf20Sopenharmony_ci * Otherwise compute the scale and offset according to the formulas 10628c2ecf20Sopenharmony_ci * derived above. 10638c2ecf20Sopenharmony_ci */ 10648c2ecf20Sopenharmony_ci tsc_ref->tsc_scale = 10658c2ecf20Sopenharmony_ci mul_u64_u32_div(1ULL << (32 + hv_clock->tsc_shift), 10668c2ecf20Sopenharmony_ci hv_clock->tsc_to_system_mul, 10678c2ecf20Sopenharmony_ci 100); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci tsc_ref->tsc_offset = hv_clock->system_time; 10708c2ecf20Sopenharmony_ci do_div(tsc_ref->tsc_offset, 100); 10718c2ecf20Sopenharmony_ci tsc_ref->tsc_offset -= 10728c2ecf20Sopenharmony_ci mul_u64_u64_shr(hv_clock->tsc_timestamp, tsc_ref->tsc_scale, 64); 10738c2ecf20Sopenharmony_ci return true; 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_civoid kvm_hv_setup_tsc_page(struct kvm *kvm, 10778c2ecf20Sopenharmony_ci struct pvclock_vcpu_time_info *hv_clock) 10788c2ecf20Sopenharmony_ci{ 10798c2ecf20Sopenharmony_ci struct kvm_hv *hv = &kvm->arch.hyperv; 10808c2ecf20Sopenharmony_ci u32 tsc_seq; 10818c2ecf20Sopenharmony_ci u64 gfn; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(tsc_seq) != sizeof(hv->tsc_ref.tsc_sequence)); 10848c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct ms_hyperv_tsc_page, tsc_sequence) != 0); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE)) 10878c2ecf20Sopenharmony_ci return; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci mutex_lock(&kvm->arch.hyperv.hv_lock); 10908c2ecf20Sopenharmony_ci if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE)) 10918c2ecf20Sopenharmony_ci goto out_unlock; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT; 10948c2ecf20Sopenharmony_ci /* 10958c2ecf20Sopenharmony_ci * Because the TSC parameters only vary when there is a 10968c2ecf20Sopenharmony_ci * change in the master clock, do not bother with caching. 10978c2ecf20Sopenharmony_ci */ 10988c2ecf20Sopenharmony_ci if (unlikely(kvm_read_guest(kvm, gfn_to_gpa(gfn), 10998c2ecf20Sopenharmony_ci &tsc_seq, sizeof(tsc_seq)))) 11008c2ecf20Sopenharmony_ci goto out_unlock; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* 11038c2ecf20Sopenharmony_ci * While we're computing and writing the parameters, force the 11048c2ecf20Sopenharmony_ci * guest to use the time reference count MSR. 11058c2ecf20Sopenharmony_ci */ 11068c2ecf20Sopenharmony_ci hv->tsc_ref.tsc_sequence = 0; 11078c2ecf20Sopenharmony_ci if (kvm_write_guest(kvm, gfn_to_gpa(gfn), 11088c2ecf20Sopenharmony_ci &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence))) 11098c2ecf20Sopenharmony_ci goto out_unlock; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (!compute_tsc_page_parameters(hv_clock, &hv->tsc_ref)) 11128c2ecf20Sopenharmony_ci goto out_unlock; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* Ensure sequence is zero before writing the rest of the struct. */ 11158c2ecf20Sopenharmony_ci smp_wmb(); 11168c2ecf20Sopenharmony_ci if (kvm_write_guest(kvm, gfn_to_gpa(gfn), &hv->tsc_ref, sizeof(hv->tsc_ref))) 11178c2ecf20Sopenharmony_ci goto out_unlock; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci /* 11208c2ecf20Sopenharmony_ci * Now switch to the TSC page mechanism by writing the sequence. 11218c2ecf20Sopenharmony_ci */ 11228c2ecf20Sopenharmony_ci tsc_seq++; 11238c2ecf20Sopenharmony_ci if (tsc_seq == 0xFFFFFFFF || tsc_seq == 0) 11248c2ecf20Sopenharmony_ci tsc_seq = 1; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* Write the struct entirely before the non-zero sequence. */ 11278c2ecf20Sopenharmony_ci smp_wmb(); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci hv->tsc_ref.tsc_sequence = tsc_seq; 11308c2ecf20Sopenharmony_ci kvm_write_guest(kvm, gfn_to_gpa(gfn), 11318c2ecf20Sopenharmony_ci &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence)); 11328c2ecf20Sopenharmony_ciout_unlock: 11338c2ecf20Sopenharmony_ci mutex_unlock(&kvm->arch.hyperv.hv_lock); 11348c2ecf20Sopenharmony_ci} 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_cistatic int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, 11378c2ecf20Sopenharmony_ci bool host) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci struct kvm *kvm = vcpu->kvm; 11408c2ecf20Sopenharmony_ci struct kvm_hv *hv = &kvm->arch.hyperv; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci switch (msr) { 11438c2ecf20Sopenharmony_ci case HV_X64_MSR_GUEST_OS_ID: 11448c2ecf20Sopenharmony_ci hv->hv_guest_os_id = data; 11458c2ecf20Sopenharmony_ci /* setting guest os id to zero disables hypercall page */ 11468c2ecf20Sopenharmony_ci if (!hv->hv_guest_os_id) 11478c2ecf20Sopenharmony_ci hv->hv_hypercall &= ~HV_X64_MSR_HYPERCALL_ENABLE; 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci case HV_X64_MSR_HYPERCALL: { 11508c2ecf20Sopenharmony_ci u64 gfn; 11518c2ecf20Sopenharmony_ci unsigned long addr; 11528c2ecf20Sopenharmony_ci u8 instructions[4]; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci /* if guest os id is not set hypercall should remain disabled */ 11558c2ecf20Sopenharmony_ci if (!hv->hv_guest_os_id) 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci if (!(data & HV_X64_MSR_HYPERCALL_ENABLE)) { 11588c2ecf20Sopenharmony_ci hv->hv_hypercall = data; 11598c2ecf20Sopenharmony_ci break; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci gfn = data >> HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT; 11628c2ecf20Sopenharmony_ci addr = gfn_to_hva(kvm, gfn); 11638c2ecf20Sopenharmony_ci if (kvm_is_error_hva(addr)) 11648c2ecf20Sopenharmony_ci return 1; 11658c2ecf20Sopenharmony_ci kvm_x86_ops.patch_hypercall(vcpu, instructions); 11668c2ecf20Sopenharmony_ci ((unsigned char *)instructions)[3] = 0xc3; /* ret */ 11678c2ecf20Sopenharmony_ci if (__copy_to_user((void __user *)addr, instructions, 4)) 11688c2ecf20Sopenharmony_ci return 1; 11698c2ecf20Sopenharmony_ci hv->hv_hypercall = data; 11708c2ecf20Sopenharmony_ci mark_page_dirty(kvm, gfn); 11718c2ecf20Sopenharmony_ci break; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci case HV_X64_MSR_REFERENCE_TSC: 11748c2ecf20Sopenharmony_ci hv->hv_tsc_page = data; 11758c2ecf20Sopenharmony_ci if (hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE) 11768c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu); 11778c2ecf20Sopenharmony_ci break; 11788c2ecf20Sopenharmony_ci case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: 11798c2ecf20Sopenharmony_ci return kvm_hv_msr_set_crash_data(vcpu, 11808c2ecf20Sopenharmony_ci msr - HV_X64_MSR_CRASH_P0, 11818c2ecf20Sopenharmony_ci data); 11828c2ecf20Sopenharmony_ci case HV_X64_MSR_CRASH_CTL: 11838c2ecf20Sopenharmony_ci return kvm_hv_msr_set_crash_ctl(vcpu, data, host); 11848c2ecf20Sopenharmony_ci case HV_X64_MSR_RESET: 11858c2ecf20Sopenharmony_ci if (data == 1) { 11868c2ecf20Sopenharmony_ci vcpu_debug(vcpu, "hyper-v reset requested\n"); 11878c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_HV_RESET, vcpu); 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci break; 11908c2ecf20Sopenharmony_ci case HV_X64_MSR_REENLIGHTENMENT_CONTROL: 11918c2ecf20Sopenharmony_ci hv->hv_reenlightenment_control = data; 11928c2ecf20Sopenharmony_ci break; 11938c2ecf20Sopenharmony_ci case HV_X64_MSR_TSC_EMULATION_CONTROL: 11948c2ecf20Sopenharmony_ci hv->hv_tsc_emulation_control = data; 11958c2ecf20Sopenharmony_ci break; 11968c2ecf20Sopenharmony_ci case HV_X64_MSR_TSC_EMULATION_STATUS: 11978c2ecf20Sopenharmony_ci hv->hv_tsc_emulation_status = data; 11988c2ecf20Sopenharmony_ci break; 11998c2ecf20Sopenharmony_ci case HV_X64_MSR_TIME_REF_COUNT: 12008c2ecf20Sopenharmony_ci /* read-only, but still ignore it if host-initiated */ 12018c2ecf20Sopenharmony_ci if (!host) 12028c2ecf20Sopenharmony_ci return 1; 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_OPTIONS: 12058c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER: 12068c2ecf20Sopenharmony_ci return syndbg_set_msr(vcpu, msr, data, host); 12078c2ecf20Sopenharmony_ci default: 12088c2ecf20Sopenharmony_ci vcpu_unimpl(vcpu, "Hyper-V unhandled wrmsr: 0x%x data 0x%llx\n", 12098c2ecf20Sopenharmony_ci msr, data); 12108c2ecf20Sopenharmony_ci return 1; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci return 0; 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci/* Calculate cpu time spent by current task in 100ns units */ 12168c2ecf20Sopenharmony_cistatic u64 current_task_runtime_100ns(void) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci u64 utime, stime; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci task_cputime_adjusted(current, &utime, &stime); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci return div_u64(utime + stime, 100); 12238c2ecf20Sopenharmony_ci} 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci switch (msr) { 12308c2ecf20Sopenharmony_ci case HV_X64_MSR_VP_INDEX: { 12318c2ecf20Sopenharmony_ci struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 12328c2ecf20Sopenharmony_ci int vcpu_idx = kvm_vcpu_get_idx(vcpu); 12338c2ecf20Sopenharmony_ci u32 new_vp_index = (u32)data; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci if (!host || new_vp_index >= KVM_MAX_VCPUS) 12368c2ecf20Sopenharmony_ci return 1; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (new_vp_index == hv_vcpu->vp_index) 12398c2ecf20Sopenharmony_ci return 0; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* 12428c2ecf20Sopenharmony_ci * The VP index is initialized to vcpu_index by 12438c2ecf20Sopenharmony_ci * kvm_hv_vcpu_postcreate so they initially match. Now the 12448c2ecf20Sopenharmony_ci * VP index is changing, adjust num_mismatched_vp_indexes if 12458c2ecf20Sopenharmony_ci * it now matches or no longer matches vcpu_idx. 12468c2ecf20Sopenharmony_ci */ 12478c2ecf20Sopenharmony_ci if (hv_vcpu->vp_index == vcpu_idx) 12488c2ecf20Sopenharmony_ci atomic_inc(&hv->num_mismatched_vp_indexes); 12498c2ecf20Sopenharmony_ci else if (new_vp_index == vcpu_idx) 12508c2ecf20Sopenharmony_ci atomic_dec(&hv->num_mismatched_vp_indexes); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci hv_vcpu->vp_index = new_vp_index; 12538c2ecf20Sopenharmony_ci break; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci case HV_X64_MSR_VP_ASSIST_PAGE: { 12568c2ecf20Sopenharmony_ci u64 gfn; 12578c2ecf20Sopenharmony_ci unsigned long addr; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (!(data & HV_X64_MSR_VP_ASSIST_PAGE_ENABLE)) { 12608c2ecf20Sopenharmony_ci hv_vcpu->hv_vapic = data; 12618c2ecf20Sopenharmony_ci if (kvm_lapic_enable_pv_eoi(vcpu, 0, 0)) 12628c2ecf20Sopenharmony_ci return 1; 12638c2ecf20Sopenharmony_ci break; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci gfn = data >> HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT; 12668c2ecf20Sopenharmony_ci addr = kvm_vcpu_gfn_to_hva(vcpu, gfn); 12678c2ecf20Sopenharmony_ci if (kvm_is_error_hva(addr)) 12688c2ecf20Sopenharmony_ci return 1; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci /* 12718c2ecf20Sopenharmony_ci * Clear apic_assist portion of struct hv_vp_assist_page 12728c2ecf20Sopenharmony_ci * only, there can be valuable data in the rest which needs 12738c2ecf20Sopenharmony_ci * to be preserved e.g. on migration. 12748c2ecf20Sopenharmony_ci */ 12758c2ecf20Sopenharmony_ci if (__put_user(0, (u32 __user *)addr)) 12768c2ecf20Sopenharmony_ci return 1; 12778c2ecf20Sopenharmony_ci hv_vcpu->hv_vapic = data; 12788c2ecf20Sopenharmony_ci kvm_vcpu_mark_page_dirty(vcpu, gfn); 12798c2ecf20Sopenharmony_ci if (kvm_lapic_enable_pv_eoi(vcpu, 12808c2ecf20Sopenharmony_ci gfn_to_gpa(gfn) | KVM_MSR_ENABLED, 12818c2ecf20Sopenharmony_ci sizeof(struct hv_vp_assist_page))) 12828c2ecf20Sopenharmony_ci return 1; 12838c2ecf20Sopenharmony_ci break; 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci case HV_X64_MSR_EOI: 12868c2ecf20Sopenharmony_ci return kvm_hv_vapic_msr_write(vcpu, APIC_EOI, data); 12878c2ecf20Sopenharmony_ci case HV_X64_MSR_ICR: 12888c2ecf20Sopenharmony_ci return kvm_hv_vapic_msr_write(vcpu, APIC_ICR, data); 12898c2ecf20Sopenharmony_ci case HV_X64_MSR_TPR: 12908c2ecf20Sopenharmony_ci return kvm_hv_vapic_msr_write(vcpu, APIC_TASKPRI, data); 12918c2ecf20Sopenharmony_ci case HV_X64_MSR_VP_RUNTIME: 12928c2ecf20Sopenharmony_ci if (!host) 12938c2ecf20Sopenharmony_ci return 1; 12948c2ecf20Sopenharmony_ci hv_vcpu->runtime_offset = data - current_task_runtime_100ns(); 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci case HV_X64_MSR_SCONTROL: 12978c2ecf20Sopenharmony_ci case HV_X64_MSR_SVERSION: 12988c2ecf20Sopenharmony_ci case HV_X64_MSR_SIEFP: 12998c2ecf20Sopenharmony_ci case HV_X64_MSR_SIMP: 13008c2ecf20Sopenharmony_ci case HV_X64_MSR_EOM: 13018c2ecf20Sopenharmony_ci case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: 13028c2ecf20Sopenharmony_ci return synic_set_msr(vcpu_to_synic(vcpu), msr, data, host); 13038c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER0_CONFIG: 13048c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER1_CONFIG: 13058c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER2_CONFIG: 13068c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER3_CONFIG: { 13078c2ecf20Sopenharmony_ci int timer_index = (msr - HV_X64_MSR_STIMER0_CONFIG)/2; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci return stimer_set_config(vcpu_to_stimer(vcpu, timer_index), 13108c2ecf20Sopenharmony_ci data, host); 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER0_COUNT: 13138c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER1_COUNT: 13148c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER2_COUNT: 13158c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER3_COUNT: { 13168c2ecf20Sopenharmony_ci int timer_index = (msr - HV_X64_MSR_STIMER0_COUNT)/2; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci return stimer_set_count(vcpu_to_stimer(vcpu, timer_index), 13198c2ecf20Sopenharmony_ci data, host); 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci case HV_X64_MSR_TSC_FREQUENCY: 13228c2ecf20Sopenharmony_ci case HV_X64_MSR_APIC_FREQUENCY: 13238c2ecf20Sopenharmony_ci /* read-only, but still ignore it if host-initiated */ 13248c2ecf20Sopenharmony_ci if (!host) 13258c2ecf20Sopenharmony_ci return 1; 13268c2ecf20Sopenharmony_ci break; 13278c2ecf20Sopenharmony_ci default: 13288c2ecf20Sopenharmony_ci vcpu_unimpl(vcpu, "Hyper-V unhandled wrmsr: 0x%x data 0x%llx\n", 13298c2ecf20Sopenharmony_ci msr, data); 13308c2ecf20Sopenharmony_ci return 1; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci return 0; 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_cistatic int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, 13378c2ecf20Sopenharmony_ci bool host) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci u64 data = 0; 13408c2ecf20Sopenharmony_ci struct kvm *kvm = vcpu->kvm; 13418c2ecf20Sopenharmony_ci struct kvm_hv *hv = &kvm->arch.hyperv; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci switch (msr) { 13448c2ecf20Sopenharmony_ci case HV_X64_MSR_GUEST_OS_ID: 13458c2ecf20Sopenharmony_ci data = hv->hv_guest_os_id; 13468c2ecf20Sopenharmony_ci break; 13478c2ecf20Sopenharmony_ci case HV_X64_MSR_HYPERCALL: 13488c2ecf20Sopenharmony_ci data = hv->hv_hypercall; 13498c2ecf20Sopenharmony_ci break; 13508c2ecf20Sopenharmony_ci case HV_X64_MSR_TIME_REF_COUNT: 13518c2ecf20Sopenharmony_ci data = get_time_ref_counter(kvm); 13528c2ecf20Sopenharmony_ci break; 13538c2ecf20Sopenharmony_ci case HV_X64_MSR_REFERENCE_TSC: 13548c2ecf20Sopenharmony_ci data = hv->hv_tsc_page; 13558c2ecf20Sopenharmony_ci break; 13568c2ecf20Sopenharmony_ci case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: 13578c2ecf20Sopenharmony_ci return kvm_hv_msr_get_crash_data(vcpu, 13588c2ecf20Sopenharmony_ci msr - HV_X64_MSR_CRASH_P0, 13598c2ecf20Sopenharmony_ci pdata); 13608c2ecf20Sopenharmony_ci case HV_X64_MSR_CRASH_CTL: 13618c2ecf20Sopenharmony_ci return kvm_hv_msr_get_crash_ctl(vcpu, pdata); 13628c2ecf20Sopenharmony_ci case HV_X64_MSR_RESET: 13638c2ecf20Sopenharmony_ci data = 0; 13648c2ecf20Sopenharmony_ci break; 13658c2ecf20Sopenharmony_ci case HV_X64_MSR_REENLIGHTENMENT_CONTROL: 13668c2ecf20Sopenharmony_ci data = hv->hv_reenlightenment_control; 13678c2ecf20Sopenharmony_ci break; 13688c2ecf20Sopenharmony_ci case HV_X64_MSR_TSC_EMULATION_CONTROL: 13698c2ecf20Sopenharmony_ci data = hv->hv_tsc_emulation_control; 13708c2ecf20Sopenharmony_ci break; 13718c2ecf20Sopenharmony_ci case HV_X64_MSR_TSC_EMULATION_STATUS: 13728c2ecf20Sopenharmony_ci data = hv->hv_tsc_emulation_status; 13738c2ecf20Sopenharmony_ci break; 13748c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_OPTIONS: 13758c2ecf20Sopenharmony_ci case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER: 13768c2ecf20Sopenharmony_ci return syndbg_get_msr(vcpu, msr, pdata, host); 13778c2ecf20Sopenharmony_ci default: 13788c2ecf20Sopenharmony_ci vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr); 13798c2ecf20Sopenharmony_ci return 1; 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci *pdata = data; 13838c2ecf20Sopenharmony_ci return 0; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, 13878c2ecf20Sopenharmony_ci bool host) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci u64 data = 0; 13908c2ecf20Sopenharmony_ci struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci switch (msr) { 13938c2ecf20Sopenharmony_ci case HV_X64_MSR_VP_INDEX: 13948c2ecf20Sopenharmony_ci data = hv_vcpu->vp_index; 13958c2ecf20Sopenharmony_ci break; 13968c2ecf20Sopenharmony_ci case HV_X64_MSR_EOI: 13978c2ecf20Sopenharmony_ci return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata); 13988c2ecf20Sopenharmony_ci case HV_X64_MSR_ICR: 13998c2ecf20Sopenharmony_ci return kvm_hv_vapic_msr_read(vcpu, APIC_ICR, pdata); 14008c2ecf20Sopenharmony_ci case HV_X64_MSR_TPR: 14018c2ecf20Sopenharmony_ci return kvm_hv_vapic_msr_read(vcpu, APIC_TASKPRI, pdata); 14028c2ecf20Sopenharmony_ci case HV_X64_MSR_VP_ASSIST_PAGE: 14038c2ecf20Sopenharmony_ci data = hv_vcpu->hv_vapic; 14048c2ecf20Sopenharmony_ci break; 14058c2ecf20Sopenharmony_ci case HV_X64_MSR_VP_RUNTIME: 14068c2ecf20Sopenharmony_ci data = current_task_runtime_100ns() + hv_vcpu->runtime_offset; 14078c2ecf20Sopenharmony_ci break; 14088c2ecf20Sopenharmony_ci case HV_X64_MSR_SCONTROL: 14098c2ecf20Sopenharmony_ci case HV_X64_MSR_SVERSION: 14108c2ecf20Sopenharmony_ci case HV_X64_MSR_SIEFP: 14118c2ecf20Sopenharmony_ci case HV_X64_MSR_SIMP: 14128c2ecf20Sopenharmony_ci case HV_X64_MSR_EOM: 14138c2ecf20Sopenharmony_ci case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: 14148c2ecf20Sopenharmony_ci return synic_get_msr(vcpu_to_synic(vcpu), msr, pdata, host); 14158c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER0_CONFIG: 14168c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER1_CONFIG: 14178c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER2_CONFIG: 14188c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER3_CONFIG: { 14198c2ecf20Sopenharmony_ci int timer_index = (msr - HV_X64_MSR_STIMER0_CONFIG)/2; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci return stimer_get_config(vcpu_to_stimer(vcpu, timer_index), 14228c2ecf20Sopenharmony_ci pdata); 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER0_COUNT: 14258c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER1_COUNT: 14268c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER2_COUNT: 14278c2ecf20Sopenharmony_ci case HV_X64_MSR_STIMER3_COUNT: { 14288c2ecf20Sopenharmony_ci int timer_index = (msr - HV_X64_MSR_STIMER0_COUNT)/2; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci return stimer_get_count(vcpu_to_stimer(vcpu, timer_index), 14318c2ecf20Sopenharmony_ci pdata); 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci case HV_X64_MSR_TSC_FREQUENCY: 14348c2ecf20Sopenharmony_ci data = (u64)vcpu->arch.virtual_tsc_khz * 1000; 14358c2ecf20Sopenharmony_ci break; 14368c2ecf20Sopenharmony_ci case HV_X64_MSR_APIC_FREQUENCY: 14378c2ecf20Sopenharmony_ci data = APIC_BUS_FREQUENCY; 14388c2ecf20Sopenharmony_ci break; 14398c2ecf20Sopenharmony_ci default: 14408c2ecf20Sopenharmony_ci vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr); 14418c2ecf20Sopenharmony_ci return 1; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci *pdata = data; 14448c2ecf20Sopenharmony_ci return 0; 14458c2ecf20Sopenharmony_ci} 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ciint kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci if (kvm_hv_msr_partition_wide(msr)) { 14508c2ecf20Sopenharmony_ci int r; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci mutex_lock(&vcpu->kvm->arch.hyperv.hv_lock); 14538c2ecf20Sopenharmony_ci r = kvm_hv_set_msr_pw(vcpu, msr, data, host); 14548c2ecf20Sopenharmony_ci mutex_unlock(&vcpu->kvm->arch.hyperv.hv_lock); 14558c2ecf20Sopenharmony_ci return r; 14568c2ecf20Sopenharmony_ci } else 14578c2ecf20Sopenharmony_ci return kvm_hv_set_msr(vcpu, msr, data, host); 14588c2ecf20Sopenharmony_ci} 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ciint kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci if (kvm_hv_msr_partition_wide(msr)) { 14638c2ecf20Sopenharmony_ci int r; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci mutex_lock(&vcpu->kvm->arch.hyperv.hv_lock); 14668c2ecf20Sopenharmony_ci r = kvm_hv_get_msr_pw(vcpu, msr, pdata, host); 14678c2ecf20Sopenharmony_ci mutex_unlock(&vcpu->kvm->arch.hyperv.hv_lock); 14688c2ecf20Sopenharmony_ci return r; 14698c2ecf20Sopenharmony_ci } else 14708c2ecf20Sopenharmony_ci return kvm_hv_get_msr(vcpu, msr, pdata, host); 14718c2ecf20Sopenharmony_ci} 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_cistatic __always_inline unsigned long *sparse_set_to_vcpu_mask( 14748c2ecf20Sopenharmony_ci struct kvm *kvm, u64 *sparse_banks, u64 valid_bank_mask, 14758c2ecf20Sopenharmony_ci u64 *vp_bitmap, unsigned long *vcpu_bitmap) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci struct kvm_hv *hv = &kvm->arch.hyperv; 14788c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 14798c2ecf20Sopenharmony_ci int i, bank, sbank = 0; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci memset(vp_bitmap, 0, 14828c2ecf20Sopenharmony_ci KVM_HV_MAX_SPARSE_VCPU_SET_BITS * sizeof(*vp_bitmap)); 14838c2ecf20Sopenharmony_ci for_each_set_bit(bank, (unsigned long *)&valid_bank_mask, 14848c2ecf20Sopenharmony_ci KVM_HV_MAX_SPARSE_VCPU_SET_BITS) 14858c2ecf20Sopenharmony_ci vp_bitmap[bank] = sparse_banks[sbank++]; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (likely(!atomic_read(&hv->num_mismatched_vp_indexes))) { 14888c2ecf20Sopenharmony_ci /* for all vcpus vp_index == vcpu_idx */ 14898c2ecf20Sopenharmony_ci return (unsigned long *)vp_bitmap; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci bitmap_zero(vcpu_bitmap, KVM_MAX_VCPUS); 14938c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 14948c2ecf20Sopenharmony_ci if (test_bit(vcpu_to_hv_vcpu(vcpu)->vp_index, 14958c2ecf20Sopenharmony_ci (unsigned long *)vp_bitmap)) 14968c2ecf20Sopenharmony_ci __set_bit(i, vcpu_bitmap); 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci return vcpu_bitmap; 14998c2ecf20Sopenharmony_ci} 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_cistatic u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, 15028c2ecf20Sopenharmony_ci u16 rep_cnt, bool ex) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci struct kvm *kvm = current_vcpu->kvm; 15058c2ecf20Sopenharmony_ci struct kvm_vcpu_hv *hv_vcpu = ¤t_vcpu->arch.hyperv; 15068c2ecf20Sopenharmony_ci struct hv_tlb_flush_ex flush_ex; 15078c2ecf20Sopenharmony_ci struct hv_tlb_flush flush; 15088c2ecf20Sopenharmony_ci u64 vp_bitmap[KVM_HV_MAX_SPARSE_VCPU_SET_BITS]; 15098c2ecf20Sopenharmony_ci DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS); 15108c2ecf20Sopenharmony_ci unsigned long *vcpu_mask; 15118c2ecf20Sopenharmony_ci u64 valid_bank_mask; 15128c2ecf20Sopenharmony_ci u64 sparse_banks[64]; 15138c2ecf20Sopenharmony_ci int sparse_banks_len; 15148c2ecf20Sopenharmony_ci bool all_cpus; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (!ex) { 15178c2ecf20Sopenharmony_ci if (unlikely(kvm_read_guest(kvm, ingpa, &flush, sizeof(flush)))) 15188c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_HYPERCALL_INPUT; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci trace_kvm_hv_flush_tlb(flush.processor_mask, 15218c2ecf20Sopenharmony_ci flush.address_space, flush.flags); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci valid_bank_mask = BIT_ULL(0); 15248c2ecf20Sopenharmony_ci sparse_banks[0] = flush.processor_mask; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* 15278c2ecf20Sopenharmony_ci * Work around possible WS2012 bug: it sends hypercalls 15288c2ecf20Sopenharmony_ci * with processor_mask = 0x0 and HV_FLUSH_ALL_PROCESSORS clear, 15298c2ecf20Sopenharmony_ci * while also expecting us to flush something and crashing if 15308c2ecf20Sopenharmony_ci * we don't. Let's treat processor_mask == 0 same as 15318c2ecf20Sopenharmony_ci * HV_FLUSH_ALL_PROCESSORS. 15328c2ecf20Sopenharmony_ci */ 15338c2ecf20Sopenharmony_ci all_cpus = (flush.flags & HV_FLUSH_ALL_PROCESSORS) || 15348c2ecf20Sopenharmony_ci flush.processor_mask == 0; 15358c2ecf20Sopenharmony_ci } else { 15368c2ecf20Sopenharmony_ci if (unlikely(kvm_read_guest(kvm, ingpa, &flush_ex, 15378c2ecf20Sopenharmony_ci sizeof(flush_ex)))) 15388c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_HYPERCALL_INPUT; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci trace_kvm_hv_flush_tlb_ex(flush_ex.hv_vp_set.valid_bank_mask, 15418c2ecf20Sopenharmony_ci flush_ex.hv_vp_set.format, 15428c2ecf20Sopenharmony_ci flush_ex.address_space, 15438c2ecf20Sopenharmony_ci flush_ex.flags); 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci valid_bank_mask = flush_ex.hv_vp_set.valid_bank_mask; 15468c2ecf20Sopenharmony_ci all_cpus = flush_ex.hv_vp_set.format != 15478c2ecf20Sopenharmony_ci HV_GENERIC_SET_SPARSE_4K; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci sparse_banks_len = 15508c2ecf20Sopenharmony_ci bitmap_weight((unsigned long *)&valid_bank_mask, 64) * 15518c2ecf20Sopenharmony_ci sizeof(sparse_banks[0]); 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (!sparse_banks_len && !all_cpus) 15548c2ecf20Sopenharmony_ci goto ret_success; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (!all_cpus && 15578c2ecf20Sopenharmony_ci kvm_read_guest(kvm, 15588c2ecf20Sopenharmony_ci ingpa + offsetof(struct hv_tlb_flush_ex, 15598c2ecf20Sopenharmony_ci hv_vp_set.bank_contents), 15608c2ecf20Sopenharmony_ci sparse_banks, 15618c2ecf20Sopenharmony_ci sparse_banks_len)) 15628c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_HYPERCALL_INPUT; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci cpumask_clear(&hv_vcpu->tlb_flush); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci /* 15688c2ecf20Sopenharmony_ci * vcpu->arch.cr3 may not be up-to-date for running vCPUs so we can't 15698c2ecf20Sopenharmony_ci * analyze it here, flush TLB regardless of the specified address space. 15708c2ecf20Sopenharmony_ci */ 15718c2ecf20Sopenharmony_ci if (all_cpus) { 15728c2ecf20Sopenharmony_ci kvm_make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH_GUEST); 15738c2ecf20Sopenharmony_ci } else { 15748c2ecf20Sopenharmony_ci vcpu_mask = sparse_set_to_vcpu_mask(kvm, sparse_banks, valid_bank_mask, 15758c2ecf20Sopenharmony_ci vp_bitmap, vcpu_bitmap); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci kvm_make_vcpus_request_mask(kvm, KVM_REQ_TLB_FLUSH_GUEST, 15788c2ecf20Sopenharmony_ci NULL, vcpu_mask, &hv_vcpu->tlb_flush); 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ciret_success: 15828c2ecf20Sopenharmony_ci /* We always do full TLB flush, set rep_done = rep_cnt. */ 15838c2ecf20Sopenharmony_ci return (u64)HV_STATUS_SUCCESS | 15848c2ecf20Sopenharmony_ci ((u64)rep_cnt << HV_HYPERCALL_REP_COMP_OFFSET); 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic void kvm_send_ipi_to_many(struct kvm *kvm, u32 vector, 15888c2ecf20Sopenharmony_ci unsigned long *vcpu_bitmap) 15898c2ecf20Sopenharmony_ci{ 15908c2ecf20Sopenharmony_ci struct kvm_lapic_irq irq = { 15918c2ecf20Sopenharmony_ci .delivery_mode = APIC_DM_FIXED, 15928c2ecf20Sopenharmony_ci .vector = vector 15938c2ecf20Sopenharmony_ci }; 15948c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 15958c2ecf20Sopenharmony_ci int i; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 15988c2ecf20Sopenharmony_ci if (vcpu_bitmap && !test_bit(i, vcpu_bitmap)) 15998c2ecf20Sopenharmony_ci continue; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci /* We fail only when APIC is disabled */ 16028c2ecf20Sopenharmony_ci kvm_apic_set_irq(vcpu, &irq, NULL); 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci} 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_cistatic u64 kvm_hv_send_ipi(struct kvm_vcpu *current_vcpu, u64 ingpa, u64 outgpa, 16078c2ecf20Sopenharmony_ci bool ex, bool fast) 16088c2ecf20Sopenharmony_ci{ 16098c2ecf20Sopenharmony_ci struct kvm *kvm = current_vcpu->kvm; 16108c2ecf20Sopenharmony_ci struct hv_send_ipi_ex send_ipi_ex; 16118c2ecf20Sopenharmony_ci struct hv_send_ipi send_ipi; 16128c2ecf20Sopenharmony_ci u64 vp_bitmap[KVM_HV_MAX_SPARSE_VCPU_SET_BITS]; 16138c2ecf20Sopenharmony_ci DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS); 16148c2ecf20Sopenharmony_ci unsigned long *vcpu_mask; 16158c2ecf20Sopenharmony_ci unsigned long valid_bank_mask; 16168c2ecf20Sopenharmony_ci u64 sparse_banks[64]; 16178c2ecf20Sopenharmony_ci int sparse_banks_len; 16188c2ecf20Sopenharmony_ci u32 vector; 16198c2ecf20Sopenharmony_ci bool all_cpus; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (!ex) { 16228c2ecf20Sopenharmony_ci if (!fast) { 16238c2ecf20Sopenharmony_ci if (unlikely(kvm_read_guest(kvm, ingpa, &send_ipi, 16248c2ecf20Sopenharmony_ci sizeof(send_ipi)))) 16258c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_HYPERCALL_INPUT; 16268c2ecf20Sopenharmony_ci sparse_banks[0] = send_ipi.cpu_mask; 16278c2ecf20Sopenharmony_ci vector = send_ipi.vector; 16288c2ecf20Sopenharmony_ci } else { 16298c2ecf20Sopenharmony_ci /* 'reserved' part of hv_send_ipi should be 0 */ 16308c2ecf20Sopenharmony_ci if (unlikely(ingpa >> 32 != 0)) 16318c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_HYPERCALL_INPUT; 16328c2ecf20Sopenharmony_ci sparse_banks[0] = outgpa; 16338c2ecf20Sopenharmony_ci vector = (u32)ingpa; 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci all_cpus = false; 16368c2ecf20Sopenharmony_ci valid_bank_mask = BIT_ULL(0); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci trace_kvm_hv_send_ipi(vector, sparse_banks[0]); 16398c2ecf20Sopenharmony_ci } else { 16408c2ecf20Sopenharmony_ci if (unlikely(kvm_read_guest(kvm, ingpa, &send_ipi_ex, 16418c2ecf20Sopenharmony_ci sizeof(send_ipi_ex)))) 16428c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_HYPERCALL_INPUT; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci trace_kvm_hv_send_ipi_ex(send_ipi_ex.vector, 16458c2ecf20Sopenharmony_ci send_ipi_ex.vp_set.format, 16468c2ecf20Sopenharmony_ci send_ipi_ex.vp_set.valid_bank_mask); 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci vector = send_ipi_ex.vector; 16498c2ecf20Sopenharmony_ci valid_bank_mask = send_ipi_ex.vp_set.valid_bank_mask; 16508c2ecf20Sopenharmony_ci sparse_banks_len = bitmap_weight(&valid_bank_mask, 64) * 16518c2ecf20Sopenharmony_ci sizeof(sparse_banks[0]); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci all_cpus = send_ipi_ex.vp_set.format == HV_GENERIC_SET_ALL; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci if (all_cpus) 16568c2ecf20Sopenharmony_ci goto check_and_send_ipi; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (!sparse_banks_len) 16598c2ecf20Sopenharmony_ci goto ret_success; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (kvm_read_guest(kvm, 16628c2ecf20Sopenharmony_ci ingpa + offsetof(struct hv_send_ipi_ex, 16638c2ecf20Sopenharmony_ci vp_set.bank_contents), 16648c2ecf20Sopenharmony_ci sparse_banks, 16658c2ecf20Sopenharmony_ci sparse_banks_len)) 16668c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_HYPERCALL_INPUT; 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_cicheck_and_send_ipi: 16708c2ecf20Sopenharmony_ci if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR)) 16718c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_HYPERCALL_INPUT; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci vcpu_mask = all_cpus ? NULL : 16748c2ecf20Sopenharmony_ci sparse_set_to_vcpu_mask(kvm, sparse_banks, valid_bank_mask, 16758c2ecf20Sopenharmony_ci vp_bitmap, vcpu_bitmap); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci kvm_send_ipi_to_many(kvm, vector, vcpu_mask); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ciret_success: 16808c2ecf20Sopenharmony_ci return HV_STATUS_SUCCESS; 16818c2ecf20Sopenharmony_ci} 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_cibool kvm_hv_hypercall_enabled(struct kvm *kvm) 16848c2ecf20Sopenharmony_ci{ 16858c2ecf20Sopenharmony_ci return READ_ONCE(kvm->arch.hyperv.hv_guest_os_id) != 0; 16868c2ecf20Sopenharmony_ci} 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_cistatic void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result) 16898c2ecf20Sopenharmony_ci{ 16908c2ecf20Sopenharmony_ci bool longmode; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci longmode = is_64_bit_mode(vcpu); 16938c2ecf20Sopenharmony_ci if (longmode) 16948c2ecf20Sopenharmony_ci kvm_rax_write(vcpu, result); 16958c2ecf20Sopenharmony_ci else { 16968c2ecf20Sopenharmony_ci kvm_rdx_write(vcpu, result >> 32); 16978c2ecf20Sopenharmony_ci kvm_rax_write(vcpu, result & 0xffffffff); 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci} 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_cistatic int kvm_hv_hypercall_complete(struct kvm_vcpu *vcpu, u64 result) 17028c2ecf20Sopenharmony_ci{ 17038c2ecf20Sopenharmony_ci kvm_hv_hypercall_set_result(vcpu, result); 17048c2ecf20Sopenharmony_ci ++vcpu->stat.hypercalls; 17058c2ecf20Sopenharmony_ci return kvm_skip_emulated_instruction(vcpu); 17068c2ecf20Sopenharmony_ci} 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_cistatic int kvm_hv_hypercall_complete_userspace(struct kvm_vcpu *vcpu) 17098c2ecf20Sopenharmony_ci{ 17108c2ecf20Sopenharmony_ci return kvm_hv_hypercall_complete(vcpu, vcpu->run->hyperv.u.hcall.result); 17118c2ecf20Sopenharmony_ci} 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_cistatic u16 kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, bool fast, u64 param) 17148c2ecf20Sopenharmony_ci{ 17158c2ecf20Sopenharmony_ci struct eventfd_ctx *eventfd; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci if (unlikely(!fast)) { 17188c2ecf20Sopenharmony_ci int ret; 17198c2ecf20Sopenharmony_ci gpa_t gpa = param; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci if ((gpa & (__alignof__(param) - 1)) || 17228c2ecf20Sopenharmony_ci offset_in_page(gpa) + sizeof(param) > PAGE_SIZE) 17238c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_ALIGNMENT; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci ret = kvm_vcpu_read_guest(vcpu, gpa, ¶m, sizeof(param)); 17268c2ecf20Sopenharmony_ci if (ret < 0) 17278c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_ALIGNMENT; 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci /* 17318c2ecf20Sopenharmony_ci * Per spec, bits 32-47 contain the extra "flag number". However, we 17328c2ecf20Sopenharmony_ci * have no use for it, and in all known usecases it is zero, so just 17338c2ecf20Sopenharmony_ci * report lookup failure if it isn't. 17348c2ecf20Sopenharmony_ci */ 17358c2ecf20Sopenharmony_ci if (param & 0xffff00000000ULL) 17368c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_PORT_ID; 17378c2ecf20Sopenharmony_ci /* remaining bits are reserved-zero */ 17388c2ecf20Sopenharmony_ci if (param & ~KVM_HYPERV_CONN_ID_MASK) 17398c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_HYPERCALL_INPUT; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci /* the eventfd is protected by vcpu->kvm->srcu, but conn_to_evt isn't */ 17428c2ecf20Sopenharmony_ci rcu_read_lock(); 17438c2ecf20Sopenharmony_ci eventfd = idr_find(&vcpu->kvm->arch.hyperv.conn_to_evt, param); 17448c2ecf20Sopenharmony_ci rcu_read_unlock(); 17458c2ecf20Sopenharmony_ci if (!eventfd) 17468c2ecf20Sopenharmony_ci return HV_STATUS_INVALID_PORT_ID; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci eventfd_signal(eventfd, 1); 17498c2ecf20Sopenharmony_ci return HV_STATUS_SUCCESS; 17508c2ecf20Sopenharmony_ci} 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ciint kvm_hv_hypercall(struct kvm_vcpu *vcpu) 17538c2ecf20Sopenharmony_ci{ 17548c2ecf20Sopenharmony_ci u64 param, ingpa, outgpa, ret = HV_STATUS_SUCCESS; 17558c2ecf20Sopenharmony_ci uint16_t code, rep_idx, rep_cnt; 17568c2ecf20Sopenharmony_ci bool fast, rep; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci /* 17598c2ecf20Sopenharmony_ci * hypercall generates UD from non zero cpl and real mode 17608c2ecf20Sopenharmony_ci * per HYPER-V spec 17618c2ecf20Sopenharmony_ci */ 17628c2ecf20Sopenharmony_ci if (kvm_x86_ops.get_cpl(vcpu) != 0 || !is_protmode(vcpu)) { 17638c2ecf20Sopenharmony_ci kvm_queue_exception(vcpu, UD_VECTOR); 17648c2ecf20Sopenharmony_ci return 1; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 17688c2ecf20Sopenharmony_ci if (is_64_bit_mode(vcpu)) { 17698c2ecf20Sopenharmony_ci param = kvm_rcx_read(vcpu); 17708c2ecf20Sopenharmony_ci ingpa = kvm_rdx_read(vcpu); 17718c2ecf20Sopenharmony_ci outgpa = kvm_r8_read(vcpu); 17728c2ecf20Sopenharmony_ci } else 17738c2ecf20Sopenharmony_ci#endif 17748c2ecf20Sopenharmony_ci { 17758c2ecf20Sopenharmony_ci param = ((u64)kvm_rdx_read(vcpu) << 32) | 17768c2ecf20Sopenharmony_ci (kvm_rax_read(vcpu) & 0xffffffff); 17778c2ecf20Sopenharmony_ci ingpa = ((u64)kvm_rbx_read(vcpu) << 32) | 17788c2ecf20Sopenharmony_ci (kvm_rcx_read(vcpu) & 0xffffffff); 17798c2ecf20Sopenharmony_ci outgpa = ((u64)kvm_rdi_read(vcpu) << 32) | 17808c2ecf20Sopenharmony_ci (kvm_rsi_read(vcpu) & 0xffffffff); 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci code = param & 0xffff; 17848c2ecf20Sopenharmony_ci fast = !!(param & HV_HYPERCALL_FAST_BIT); 17858c2ecf20Sopenharmony_ci rep_cnt = (param >> HV_HYPERCALL_REP_COMP_OFFSET) & 0xfff; 17868c2ecf20Sopenharmony_ci rep_idx = (param >> HV_HYPERCALL_REP_START_OFFSET) & 0xfff; 17878c2ecf20Sopenharmony_ci rep = !!(rep_cnt || rep_idx); 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa); 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci switch (code) { 17928c2ecf20Sopenharmony_ci case HVCALL_NOTIFY_LONG_SPIN_WAIT: 17938c2ecf20Sopenharmony_ci if (unlikely(rep)) { 17948c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_INPUT; 17958c2ecf20Sopenharmony_ci break; 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci kvm_vcpu_on_spin(vcpu, true); 17988c2ecf20Sopenharmony_ci break; 17998c2ecf20Sopenharmony_ci case HVCALL_SIGNAL_EVENT: 18008c2ecf20Sopenharmony_ci if (unlikely(rep)) { 18018c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_INPUT; 18028c2ecf20Sopenharmony_ci break; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci ret = kvm_hvcall_signal_event(vcpu, fast, ingpa); 18058c2ecf20Sopenharmony_ci if (ret != HV_STATUS_INVALID_PORT_ID) 18068c2ecf20Sopenharmony_ci break; 18078c2ecf20Sopenharmony_ci fallthrough; /* maybe userspace knows this conn_id */ 18088c2ecf20Sopenharmony_ci case HVCALL_POST_MESSAGE: 18098c2ecf20Sopenharmony_ci /* don't bother userspace if it has no way to handle it */ 18108c2ecf20Sopenharmony_ci if (unlikely(rep || !vcpu_to_synic(vcpu)->active)) { 18118c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_INPUT; 18128c2ecf20Sopenharmony_ci break; 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_HYPERV; 18158c2ecf20Sopenharmony_ci vcpu->run->hyperv.type = KVM_EXIT_HYPERV_HCALL; 18168c2ecf20Sopenharmony_ci vcpu->run->hyperv.u.hcall.input = param; 18178c2ecf20Sopenharmony_ci vcpu->run->hyperv.u.hcall.params[0] = ingpa; 18188c2ecf20Sopenharmony_ci vcpu->run->hyperv.u.hcall.params[1] = outgpa; 18198c2ecf20Sopenharmony_ci vcpu->arch.complete_userspace_io = 18208c2ecf20Sopenharmony_ci kvm_hv_hypercall_complete_userspace; 18218c2ecf20Sopenharmony_ci return 0; 18228c2ecf20Sopenharmony_ci case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST: 18238c2ecf20Sopenharmony_ci if (unlikely(fast || !rep_cnt || rep_idx)) { 18248c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_INPUT; 18258c2ecf20Sopenharmony_ci break; 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ci ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt, false); 18288c2ecf20Sopenharmony_ci break; 18298c2ecf20Sopenharmony_ci case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE: 18308c2ecf20Sopenharmony_ci if (unlikely(fast || rep)) { 18318c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_INPUT; 18328c2ecf20Sopenharmony_ci break; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt, false); 18358c2ecf20Sopenharmony_ci break; 18368c2ecf20Sopenharmony_ci case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX: 18378c2ecf20Sopenharmony_ci if (unlikely(fast || !rep_cnt || rep_idx)) { 18388c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_INPUT; 18398c2ecf20Sopenharmony_ci break; 18408c2ecf20Sopenharmony_ci } 18418c2ecf20Sopenharmony_ci ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt, true); 18428c2ecf20Sopenharmony_ci break; 18438c2ecf20Sopenharmony_ci case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX: 18448c2ecf20Sopenharmony_ci if (unlikely(fast || rep)) { 18458c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_INPUT; 18468c2ecf20Sopenharmony_ci break; 18478c2ecf20Sopenharmony_ci } 18488c2ecf20Sopenharmony_ci ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt, true); 18498c2ecf20Sopenharmony_ci break; 18508c2ecf20Sopenharmony_ci case HVCALL_SEND_IPI: 18518c2ecf20Sopenharmony_ci if (unlikely(rep)) { 18528c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_INPUT; 18538c2ecf20Sopenharmony_ci break; 18548c2ecf20Sopenharmony_ci } 18558c2ecf20Sopenharmony_ci ret = kvm_hv_send_ipi(vcpu, ingpa, outgpa, false, fast); 18568c2ecf20Sopenharmony_ci break; 18578c2ecf20Sopenharmony_ci case HVCALL_SEND_IPI_EX: 18588c2ecf20Sopenharmony_ci if (unlikely(fast || rep)) { 18598c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_INPUT; 18608c2ecf20Sopenharmony_ci break; 18618c2ecf20Sopenharmony_ci } 18628c2ecf20Sopenharmony_ci ret = kvm_hv_send_ipi(vcpu, ingpa, outgpa, true, false); 18638c2ecf20Sopenharmony_ci break; 18648c2ecf20Sopenharmony_ci case HVCALL_POST_DEBUG_DATA: 18658c2ecf20Sopenharmony_ci case HVCALL_RETRIEVE_DEBUG_DATA: 18668c2ecf20Sopenharmony_ci if (unlikely(fast)) { 18678c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_PARAMETER; 18688c2ecf20Sopenharmony_ci break; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci fallthrough; 18718c2ecf20Sopenharmony_ci case HVCALL_RESET_DEBUG_SESSION: { 18728c2ecf20Sopenharmony_ci struct kvm_hv_syndbg *syndbg = vcpu_to_hv_syndbg(vcpu); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci if (!kvm_hv_is_syndbg_enabled(vcpu)) { 18758c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_CODE; 18768c2ecf20Sopenharmony_ci break; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci if (!(syndbg->options & HV_X64_SYNDBG_OPTION_USE_HCALLS)) { 18808c2ecf20Sopenharmony_ci ret = HV_STATUS_OPERATION_DENIED; 18818c2ecf20Sopenharmony_ci break; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_HYPERV; 18848c2ecf20Sopenharmony_ci vcpu->run->hyperv.type = KVM_EXIT_HYPERV_HCALL; 18858c2ecf20Sopenharmony_ci vcpu->run->hyperv.u.hcall.input = param; 18868c2ecf20Sopenharmony_ci vcpu->run->hyperv.u.hcall.params[0] = ingpa; 18878c2ecf20Sopenharmony_ci vcpu->run->hyperv.u.hcall.params[1] = outgpa; 18888c2ecf20Sopenharmony_ci vcpu->arch.complete_userspace_io = 18898c2ecf20Sopenharmony_ci kvm_hv_hypercall_complete_userspace; 18908c2ecf20Sopenharmony_ci return 0; 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci default: 18938c2ecf20Sopenharmony_ci ret = HV_STATUS_INVALID_HYPERCALL_CODE; 18948c2ecf20Sopenharmony_ci break; 18958c2ecf20Sopenharmony_ci } 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci return kvm_hv_hypercall_complete(vcpu, ret); 18988c2ecf20Sopenharmony_ci} 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_civoid kvm_hv_init_vm(struct kvm *kvm) 19018c2ecf20Sopenharmony_ci{ 19028c2ecf20Sopenharmony_ci mutex_init(&kvm->arch.hyperv.hv_lock); 19038c2ecf20Sopenharmony_ci idr_init(&kvm->arch.hyperv.conn_to_evt); 19048c2ecf20Sopenharmony_ci} 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_civoid kvm_hv_destroy_vm(struct kvm *kvm) 19078c2ecf20Sopenharmony_ci{ 19088c2ecf20Sopenharmony_ci struct eventfd_ctx *eventfd; 19098c2ecf20Sopenharmony_ci int i; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci idr_for_each_entry(&kvm->arch.hyperv.conn_to_evt, eventfd, i) 19128c2ecf20Sopenharmony_ci eventfd_ctx_put(eventfd); 19138c2ecf20Sopenharmony_ci idr_destroy(&kvm->arch.hyperv.conn_to_evt); 19148c2ecf20Sopenharmony_ci} 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_cistatic int kvm_hv_eventfd_assign(struct kvm *kvm, u32 conn_id, int fd) 19178c2ecf20Sopenharmony_ci{ 19188c2ecf20Sopenharmony_ci struct kvm_hv *hv = &kvm->arch.hyperv; 19198c2ecf20Sopenharmony_ci struct eventfd_ctx *eventfd; 19208c2ecf20Sopenharmony_ci int ret; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci eventfd = eventfd_ctx_fdget(fd); 19238c2ecf20Sopenharmony_ci if (IS_ERR(eventfd)) 19248c2ecf20Sopenharmony_ci return PTR_ERR(eventfd); 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci mutex_lock(&hv->hv_lock); 19278c2ecf20Sopenharmony_ci ret = idr_alloc(&hv->conn_to_evt, eventfd, conn_id, conn_id + 1, 19288c2ecf20Sopenharmony_ci GFP_KERNEL_ACCOUNT); 19298c2ecf20Sopenharmony_ci mutex_unlock(&hv->hv_lock); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci if (ret >= 0) 19328c2ecf20Sopenharmony_ci return 0; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci if (ret == -ENOSPC) 19358c2ecf20Sopenharmony_ci ret = -EEXIST; 19368c2ecf20Sopenharmony_ci eventfd_ctx_put(eventfd); 19378c2ecf20Sopenharmony_ci return ret; 19388c2ecf20Sopenharmony_ci} 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_cistatic int kvm_hv_eventfd_deassign(struct kvm *kvm, u32 conn_id) 19418c2ecf20Sopenharmony_ci{ 19428c2ecf20Sopenharmony_ci struct kvm_hv *hv = &kvm->arch.hyperv; 19438c2ecf20Sopenharmony_ci struct eventfd_ctx *eventfd; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci mutex_lock(&hv->hv_lock); 19468c2ecf20Sopenharmony_ci eventfd = idr_remove(&hv->conn_to_evt, conn_id); 19478c2ecf20Sopenharmony_ci mutex_unlock(&hv->hv_lock); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci if (!eventfd) 19508c2ecf20Sopenharmony_ci return -ENOENT; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci synchronize_srcu(&kvm->srcu); 19538c2ecf20Sopenharmony_ci eventfd_ctx_put(eventfd); 19548c2ecf20Sopenharmony_ci return 0; 19558c2ecf20Sopenharmony_ci} 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ciint kvm_vm_ioctl_hv_eventfd(struct kvm *kvm, struct kvm_hyperv_eventfd *args) 19588c2ecf20Sopenharmony_ci{ 19598c2ecf20Sopenharmony_ci if ((args->flags & ~KVM_HYPERV_EVENTFD_DEASSIGN) || 19608c2ecf20Sopenharmony_ci (args->conn_id & ~KVM_HYPERV_CONN_ID_MASK)) 19618c2ecf20Sopenharmony_ci return -EINVAL; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci if (args->flags == KVM_HYPERV_EVENTFD_DEASSIGN) 19648c2ecf20Sopenharmony_ci return kvm_hv_eventfd_deassign(kvm, args->conn_id); 19658c2ecf20Sopenharmony_ci return kvm_hv_eventfd_assign(kvm, args->conn_id, args->fd); 19668c2ecf20Sopenharmony_ci} 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ciint kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, 19698c2ecf20Sopenharmony_ci struct kvm_cpuid_entry2 __user *entries) 19708c2ecf20Sopenharmony_ci{ 19718c2ecf20Sopenharmony_ci uint16_t evmcs_ver = 0; 19728c2ecf20Sopenharmony_ci struct kvm_cpuid_entry2 cpuid_entries[] = { 19738c2ecf20Sopenharmony_ci { .function = HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS }, 19748c2ecf20Sopenharmony_ci { .function = HYPERV_CPUID_INTERFACE }, 19758c2ecf20Sopenharmony_ci { .function = HYPERV_CPUID_VERSION }, 19768c2ecf20Sopenharmony_ci { .function = HYPERV_CPUID_FEATURES }, 19778c2ecf20Sopenharmony_ci { .function = HYPERV_CPUID_ENLIGHTMENT_INFO }, 19788c2ecf20Sopenharmony_ci { .function = HYPERV_CPUID_IMPLEMENT_LIMITS }, 19798c2ecf20Sopenharmony_ci { .function = HYPERV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS }, 19808c2ecf20Sopenharmony_ci { .function = HYPERV_CPUID_SYNDBG_INTERFACE }, 19818c2ecf20Sopenharmony_ci { .function = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES }, 19828c2ecf20Sopenharmony_ci { .function = HYPERV_CPUID_NESTED_FEATURES }, 19838c2ecf20Sopenharmony_ci }; 19848c2ecf20Sopenharmony_ci int i, nent = ARRAY_SIZE(cpuid_entries); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (kvm_x86_ops.nested_ops->get_evmcs_version) 19878c2ecf20Sopenharmony_ci evmcs_ver = kvm_x86_ops.nested_ops->get_evmcs_version(vcpu); 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci /* Skip NESTED_FEATURES if eVMCS is not supported */ 19908c2ecf20Sopenharmony_ci if (!evmcs_ver) 19918c2ecf20Sopenharmony_ci --nent; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci if (cpuid->nent < nent) 19948c2ecf20Sopenharmony_ci return -E2BIG; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci if (cpuid->nent > nent) 19978c2ecf20Sopenharmony_ci cpuid->nent = nent; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci for (i = 0; i < nent; i++) { 20008c2ecf20Sopenharmony_ci struct kvm_cpuid_entry2 *ent = &cpuid_entries[i]; 20018c2ecf20Sopenharmony_ci u32 signature[3]; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci switch (ent->function) { 20048c2ecf20Sopenharmony_ci case HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS: 20058c2ecf20Sopenharmony_ci memcpy(signature, "Linux KVM Hv", 12); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci ent->eax = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES; 20088c2ecf20Sopenharmony_ci ent->ebx = signature[0]; 20098c2ecf20Sopenharmony_ci ent->ecx = signature[1]; 20108c2ecf20Sopenharmony_ci ent->edx = signature[2]; 20118c2ecf20Sopenharmony_ci break; 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci case HYPERV_CPUID_INTERFACE: 20148c2ecf20Sopenharmony_ci memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12); 20158c2ecf20Sopenharmony_ci ent->eax = signature[0]; 20168c2ecf20Sopenharmony_ci break; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci case HYPERV_CPUID_VERSION: 20198c2ecf20Sopenharmony_ci /* 20208c2ecf20Sopenharmony_ci * We implement some Hyper-V 2016 functions so let's use 20218c2ecf20Sopenharmony_ci * this version. 20228c2ecf20Sopenharmony_ci */ 20238c2ecf20Sopenharmony_ci ent->eax = 0x00003839; 20248c2ecf20Sopenharmony_ci ent->ebx = 0x000A0000; 20258c2ecf20Sopenharmony_ci break; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci case HYPERV_CPUID_FEATURES: 20288c2ecf20Sopenharmony_ci ent->eax |= HV_MSR_VP_RUNTIME_AVAILABLE; 20298c2ecf20Sopenharmony_ci ent->eax |= HV_MSR_TIME_REF_COUNT_AVAILABLE; 20308c2ecf20Sopenharmony_ci ent->eax |= HV_MSR_SYNIC_AVAILABLE; 20318c2ecf20Sopenharmony_ci ent->eax |= HV_MSR_SYNTIMER_AVAILABLE; 20328c2ecf20Sopenharmony_ci ent->eax |= HV_MSR_APIC_ACCESS_AVAILABLE; 20338c2ecf20Sopenharmony_ci ent->eax |= HV_MSR_HYPERCALL_AVAILABLE; 20348c2ecf20Sopenharmony_ci ent->eax |= HV_MSR_VP_INDEX_AVAILABLE; 20358c2ecf20Sopenharmony_ci ent->eax |= HV_MSR_RESET_AVAILABLE; 20368c2ecf20Sopenharmony_ci ent->eax |= HV_MSR_REFERENCE_TSC_AVAILABLE; 20378c2ecf20Sopenharmony_ci ent->eax |= HV_ACCESS_FREQUENCY_MSRS; 20388c2ecf20Sopenharmony_ci ent->eax |= HV_ACCESS_REENLIGHTENMENT; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci ent->ebx |= HV_POST_MESSAGES; 20418c2ecf20Sopenharmony_ci ent->ebx |= HV_SIGNAL_EVENTS; 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci ent->edx |= HV_FEATURE_FREQUENCY_MSRS_AVAILABLE; 20448c2ecf20Sopenharmony_ci ent->edx |= HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE; 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci ent->ebx |= HV_DEBUGGING; 20478c2ecf20Sopenharmony_ci ent->edx |= HV_X64_GUEST_DEBUGGING_AVAILABLE; 20488c2ecf20Sopenharmony_ci ent->edx |= HV_FEATURE_DEBUG_MSRS_AVAILABLE; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci /* 20518c2ecf20Sopenharmony_ci * Direct Synthetic timers only make sense with in-kernel 20528c2ecf20Sopenharmony_ci * LAPIC 20538c2ecf20Sopenharmony_ci */ 20548c2ecf20Sopenharmony_ci if (lapic_in_kernel(vcpu)) 20558c2ecf20Sopenharmony_ci ent->edx |= HV_STIMER_DIRECT_MODE_AVAILABLE; 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci break; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci case HYPERV_CPUID_ENLIGHTMENT_INFO: 20608c2ecf20Sopenharmony_ci ent->eax |= HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED; 20618c2ecf20Sopenharmony_ci ent->eax |= HV_X64_APIC_ACCESS_RECOMMENDED; 20628c2ecf20Sopenharmony_ci ent->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED; 20638c2ecf20Sopenharmony_ci ent->eax |= HV_X64_CLUSTER_IPI_RECOMMENDED; 20648c2ecf20Sopenharmony_ci ent->eax |= HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED; 20658c2ecf20Sopenharmony_ci if (evmcs_ver) 20668c2ecf20Sopenharmony_ci ent->eax |= HV_X64_ENLIGHTENED_VMCS_RECOMMENDED; 20678c2ecf20Sopenharmony_ci if (!cpu_smt_possible()) 20688c2ecf20Sopenharmony_ci ent->eax |= HV_X64_NO_NONARCH_CORESHARING; 20698c2ecf20Sopenharmony_ci /* 20708c2ecf20Sopenharmony_ci * Default number of spinlock retry attempts, matches 20718c2ecf20Sopenharmony_ci * HyperV 2016. 20728c2ecf20Sopenharmony_ci */ 20738c2ecf20Sopenharmony_ci ent->ebx = 0x00000FFF; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci break; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci case HYPERV_CPUID_IMPLEMENT_LIMITS: 20788c2ecf20Sopenharmony_ci /* Maximum number of virtual processors */ 20798c2ecf20Sopenharmony_ci ent->eax = KVM_MAX_VCPUS; 20808c2ecf20Sopenharmony_ci /* 20818c2ecf20Sopenharmony_ci * Maximum number of logical processors, matches 20828c2ecf20Sopenharmony_ci * HyperV 2016. 20838c2ecf20Sopenharmony_ci */ 20848c2ecf20Sopenharmony_ci ent->ebx = 64; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci break; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci case HYPERV_CPUID_NESTED_FEATURES: 20898c2ecf20Sopenharmony_ci ent->eax = evmcs_ver; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci break; 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci case HYPERV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS: 20948c2ecf20Sopenharmony_ci memcpy(signature, "Linux KVM Hv", 12); 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci ent->eax = 0; 20978c2ecf20Sopenharmony_ci ent->ebx = signature[0]; 20988c2ecf20Sopenharmony_ci ent->ecx = signature[1]; 20998c2ecf20Sopenharmony_ci ent->edx = signature[2]; 21008c2ecf20Sopenharmony_ci break; 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci case HYPERV_CPUID_SYNDBG_INTERFACE: 21038c2ecf20Sopenharmony_ci memcpy(signature, "VS#1\0\0\0\0\0\0\0\0", 12); 21048c2ecf20Sopenharmony_ci ent->eax = signature[0]; 21058c2ecf20Sopenharmony_ci break; 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci case HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES: 21088c2ecf20Sopenharmony_ci ent->eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; 21098c2ecf20Sopenharmony_ci break; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci default: 21128c2ecf20Sopenharmony_ci break; 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci if (copy_to_user(entries, cpuid_entries, 21178c2ecf20Sopenharmony_ci nent * sizeof(struct kvm_cpuid_entry2))) 21188c2ecf20Sopenharmony_ci return -EFAULT; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci return 0; 21218c2ecf20Sopenharmony_ci} 2122