162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Kernel-based Virtual Machine driver for Linux 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * AMD SVM support 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2006 Qumranet, Inc. 862306a36Sopenharmony_ci * Copyright 2010 Red Hat, Inc. and/or its affiliates. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Authors: 1162306a36Sopenharmony_ci * Yaniv Kamay <yaniv@qumranet.com> 1262306a36Sopenharmony_ci * Avi Kivity <avi@qumranet.com> 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/kvm_types.h> 1862306a36Sopenharmony_ci#include <linux/hashtable.h> 1962306a36Sopenharmony_ci#include <linux/amd-iommu.h> 2062306a36Sopenharmony_ci#include <linux/kvm_host.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <asm/irq_remapping.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "trace.h" 2562306a36Sopenharmony_ci#include "lapic.h" 2662306a36Sopenharmony_ci#include "x86.h" 2762306a36Sopenharmony_ci#include "irq.h" 2862306a36Sopenharmony_ci#include "svm.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * Encode the arbitrary VM ID and the vCPU's default APIC ID, i.e the vCPU ID, 3262306a36Sopenharmony_ci * into the GATag so that KVM can retrieve the correct vCPU from a GALog entry 3362306a36Sopenharmony_ci * if an interrupt can't be delivered, e.g. because the vCPU isn't running. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * For the vCPU ID, use however many bits are currently allowed for the max 3662306a36Sopenharmony_ci * guest physical APIC ID (limited by the size of the physical ID table), and 3762306a36Sopenharmony_ci * use whatever bits remain to assign arbitrary AVIC IDs to VMs. Note, the 3862306a36Sopenharmony_ci * size of the GATag is defined by hardware (32 bits), but is an opaque value 3962306a36Sopenharmony_ci * as far as hardware is concerned. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci#define AVIC_VCPU_ID_MASK AVIC_PHYSICAL_MAX_INDEX_MASK 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define AVIC_VM_ID_SHIFT HWEIGHT32(AVIC_PHYSICAL_MAX_INDEX_MASK) 4462306a36Sopenharmony_ci#define AVIC_VM_ID_MASK (GENMASK(31, AVIC_VM_ID_SHIFT) >> AVIC_VM_ID_SHIFT) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define AVIC_GATAG_TO_VMID(x) ((x >> AVIC_VM_ID_SHIFT) & AVIC_VM_ID_MASK) 4762306a36Sopenharmony_ci#define AVIC_GATAG_TO_VCPUID(x) (x & AVIC_VCPU_ID_MASK) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define __AVIC_GATAG(vm_id, vcpu_id) ((((vm_id) & AVIC_VM_ID_MASK) << AVIC_VM_ID_SHIFT) | \ 5062306a36Sopenharmony_ci ((vcpu_id) & AVIC_VCPU_ID_MASK)) 5162306a36Sopenharmony_ci#define AVIC_GATAG(vm_id, vcpu_id) \ 5262306a36Sopenharmony_ci({ \ 5362306a36Sopenharmony_ci u32 ga_tag = __AVIC_GATAG(vm_id, vcpu_id); \ 5462306a36Sopenharmony_ci \ 5562306a36Sopenharmony_ci WARN_ON_ONCE(AVIC_GATAG_TO_VCPUID(ga_tag) != (vcpu_id)); \ 5662306a36Sopenharmony_ci WARN_ON_ONCE(AVIC_GATAG_TO_VMID(ga_tag) != (vm_id)); \ 5762306a36Sopenharmony_ci ga_tag; \ 5862306a36Sopenharmony_ci}) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic_assert(__AVIC_GATAG(AVIC_VM_ID_MASK, AVIC_VCPU_ID_MASK) == -1u); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic bool force_avic; 6362306a36Sopenharmony_cimodule_param_unsafe(force_avic, bool, 0444); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* Note: 6662306a36Sopenharmony_ci * This hash table is used to map VM_ID to a struct kvm_svm, 6762306a36Sopenharmony_ci * when handling AMD IOMMU GALOG notification to schedule in 6862306a36Sopenharmony_ci * a particular vCPU. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci#define SVM_VM_DATA_HASH_BITS 8 7162306a36Sopenharmony_cistatic DEFINE_HASHTABLE(svm_vm_data_hash, SVM_VM_DATA_HASH_BITS); 7262306a36Sopenharmony_cistatic u32 next_vm_id = 0; 7362306a36Sopenharmony_cistatic bool next_vm_id_wrapped = 0; 7462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(svm_vm_data_hash_lock); 7562306a36Sopenharmony_cibool x2avic_enabled; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * This is a wrapper of struct amd_iommu_ir_data. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_cistruct amd_svm_iommu_ir { 8162306a36Sopenharmony_ci struct list_head node; /* Used by SVM for per-vcpu ir_list */ 8262306a36Sopenharmony_ci void *data; /* Storing pointer to struct amd_ir_data */ 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic void avic_activate_vmcb(struct vcpu_svm *svm) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct vmcb *vmcb = svm->vmcb01.ptr; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK); 9062306a36Sopenharmony_ci vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci vmcb->control.int_ctl |= AVIC_ENABLE_MASK; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* 9562306a36Sopenharmony_ci * Note: KVM supports hybrid-AVIC mode, where KVM emulates x2APIC MSR 9662306a36Sopenharmony_ci * accesses, while interrupt injection to a running vCPU can be 9762306a36Sopenharmony_ci * achieved using AVIC doorbell. KVM disables the APIC access page 9862306a36Sopenharmony_ci * (deletes the memslot) if any vCPU has x2APIC enabled, thus enabling 9962306a36Sopenharmony_ci * AVIC in hybrid mode activates only the doorbell mechanism. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci if (x2avic_enabled && apic_x2apic_mode(svm->vcpu.arch.apic)) { 10262306a36Sopenharmony_ci vmcb->control.int_ctl |= X2APIC_MODE_MASK; 10362306a36Sopenharmony_ci vmcb->control.avic_physical_id |= X2AVIC_MAX_PHYSICAL_ID; 10462306a36Sopenharmony_ci /* Disabling MSR intercept for x2APIC registers */ 10562306a36Sopenharmony_ci svm_set_x2apic_msr_interception(svm, false); 10662306a36Sopenharmony_ci } else { 10762306a36Sopenharmony_ci /* 10862306a36Sopenharmony_ci * Flush the TLB, the guest may have inserted a non-APIC 10962306a36Sopenharmony_ci * mapping into the TLB while AVIC was disabled. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, &svm->vcpu); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* For xAVIC and hybrid-xAVIC modes */ 11462306a36Sopenharmony_ci vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID; 11562306a36Sopenharmony_ci /* Enabling MSR intercept for x2APIC registers */ 11662306a36Sopenharmony_ci svm_set_x2apic_msr_interception(svm, true); 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic void avic_deactivate_vmcb(struct vcpu_svm *svm) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct vmcb *vmcb = svm->vmcb01.ptr; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK); 12562306a36Sopenharmony_ci vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * If running nested and the guest uses its own MSR bitmap, there 12962306a36Sopenharmony_ci * is no need to update L0's msr bitmap 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci if (is_guest_mode(&svm->vcpu) && 13262306a36Sopenharmony_ci vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_MSR_PROT)) 13362306a36Sopenharmony_ci return; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* Enabling MSR intercept for x2APIC registers */ 13662306a36Sopenharmony_ci svm_set_x2apic_msr_interception(svm, true); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* Note: 14062306a36Sopenharmony_ci * This function is called from IOMMU driver to notify 14162306a36Sopenharmony_ci * SVM to schedule in a particular vCPU of a particular VM. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ciint avic_ga_log_notifier(u32 ga_tag) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci unsigned long flags; 14662306a36Sopenharmony_ci struct kvm_svm *kvm_svm; 14762306a36Sopenharmony_ci struct kvm_vcpu *vcpu = NULL; 14862306a36Sopenharmony_ci u32 vm_id = AVIC_GATAG_TO_VMID(ga_tag); 14962306a36Sopenharmony_ci u32 vcpu_id = AVIC_GATAG_TO_VCPUID(ga_tag); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci pr_debug("SVM: %s: vm_id=%#x, vcpu_id=%#x\n", __func__, vm_id, vcpu_id); 15262306a36Sopenharmony_ci trace_kvm_avic_ga_log(vm_id, vcpu_id); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci spin_lock_irqsave(&svm_vm_data_hash_lock, flags); 15562306a36Sopenharmony_ci hash_for_each_possible(svm_vm_data_hash, kvm_svm, hnode, vm_id) { 15662306a36Sopenharmony_ci if (kvm_svm->avic_vm_id != vm_id) 15762306a36Sopenharmony_ci continue; 15862306a36Sopenharmony_ci vcpu = kvm_get_vcpu_by_id(&kvm_svm->kvm, vcpu_id); 15962306a36Sopenharmony_ci break; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* Note: 16462306a36Sopenharmony_ci * At this point, the IOMMU should have already set the pending 16562306a36Sopenharmony_ci * bit in the vAPIC backing page. So, we just need to schedule 16662306a36Sopenharmony_ci * in the vcpu. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci if (vcpu) 16962306a36Sopenharmony_ci kvm_vcpu_wake_up(vcpu); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_civoid avic_vm_destroy(struct kvm *kvm) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci unsigned long flags; 17762306a36Sopenharmony_ci struct kvm_svm *kvm_svm = to_kvm_svm(kvm); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (!enable_apicv) 18062306a36Sopenharmony_ci return; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (kvm_svm->avic_logical_id_table_page) 18362306a36Sopenharmony_ci __free_page(kvm_svm->avic_logical_id_table_page); 18462306a36Sopenharmony_ci if (kvm_svm->avic_physical_id_table_page) 18562306a36Sopenharmony_ci __free_page(kvm_svm->avic_physical_id_table_page); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci spin_lock_irqsave(&svm_vm_data_hash_lock, flags); 18862306a36Sopenharmony_ci hash_del(&kvm_svm->hnode); 18962306a36Sopenharmony_ci spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciint avic_vm_init(struct kvm *kvm) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci unsigned long flags; 19562306a36Sopenharmony_ci int err = -ENOMEM; 19662306a36Sopenharmony_ci struct kvm_svm *kvm_svm = to_kvm_svm(kvm); 19762306a36Sopenharmony_ci struct kvm_svm *k2; 19862306a36Sopenharmony_ci struct page *p_page; 19962306a36Sopenharmony_ci struct page *l_page; 20062306a36Sopenharmony_ci u32 vm_id; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (!enable_apicv) 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Allocating physical APIC ID table (4KB) */ 20662306a36Sopenharmony_ci p_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); 20762306a36Sopenharmony_ci if (!p_page) 20862306a36Sopenharmony_ci goto free_avic; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci kvm_svm->avic_physical_id_table_page = p_page; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Allocating logical APIC ID table (4KB) */ 21362306a36Sopenharmony_ci l_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); 21462306a36Sopenharmony_ci if (!l_page) 21562306a36Sopenharmony_ci goto free_avic; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci kvm_svm->avic_logical_id_table_page = l_page; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci spin_lock_irqsave(&svm_vm_data_hash_lock, flags); 22062306a36Sopenharmony_ci again: 22162306a36Sopenharmony_ci vm_id = next_vm_id = (next_vm_id + 1) & AVIC_VM_ID_MASK; 22262306a36Sopenharmony_ci if (vm_id == 0) { /* id is 1-based, zero is not okay */ 22362306a36Sopenharmony_ci next_vm_id_wrapped = 1; 22462306a36Sopenharmony_ci goto again; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci /* Is it still in use? Only possible if wrapped at least once */ 22762306a36Sopenharmony_ci if (next_vm_id_wrapped) { 22862306a36Sopenharmony_ci hash_for_each_possible(svm_vm_data_hash, k2, hnode, vm_id) { 22962306a36Sopenharmony_ci if (k2->avic_vm_id == vm_id) 23062306a36Sopenharmony_ci goto again; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci kvm_svm->avic_vm_id = vm_id; 23462306a36Sopenharmony_ci hash_add(svm_vm_data_hash, &kvm_svm->hnode, kvm_svm->avic_vm_id); 23562306a36Sopenharmony_ci spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cifree_avic: 24062306a36Sopenharmony_ci avic_vm_destroy(kvm); 24162306a36Sopenharmony_ci return err; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_civoid avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct kvm_svm *kvm_svm = to_kvm_svm(svm->vcpu.kvm); 24762306a36Sopenharmony_ci phys_addr_t bpa = __sme_set(page_to_phys(svm->avic_backing_page)); 24862306a36Sopenharmony_ci phys_addr_t lpa = __sme_set(page_to_phys(kvm_svm->avic_logical_id_table_page)); 24962306a36Sopenharmony_ci phys_addr_t ppa = __sme_set(page_to_phys(kvm_svm->avic_physical_id_table_page)); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci vmcb->control.avic_backing_page = bpa & AVIC_HPA_MASK; 25262306a36Sopenharmony_ci vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK; 25362306a36Sopenharmony_ci vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK; 25462306a36Sopenharmony_ci vmcb->control.avic_vapic_bar = APIC_DEFAULT_PHYS_BASE & VMCB_AVIC_APIC_BAR_MASK; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (kvm_apicv_activated(svm->vcpu.kvm)) 25762306a36Sopenharmony_ci avic_activate_vmcb(svm); 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci avic_deactivate_vmcb(svm); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu, 26362306a36Sopenharmony_ci unsigned int index) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci u64 *avic_physical_id_table; 26662306a36Sopenharmony_ci struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if ((!x2avic_enabled && index > AVIC_MAX_PHYSICAL_ID) || 26962306a36Sopenharmony_ci (index > X2AVIC_MAX_PHYSICAL_ID)) 27062306a36Sopenharmony_ci return NULL; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci avic_physical_id_table = page_address(kvm_svm->avic_physical_id_table_page); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return &avic_physical_id_table[index]; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic int avic_init_backing_page(struct kvm_vcpu *vcpu) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci u64 *entry, new_entry; 28062306a36Sopenharmony_ci int id = vcpu->vcpu_id; 28162306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if ((!x2avic_enabled && id > AVIC_MAX_PHYSICAL_ID) || 28462306a36Sopenharmony_ci (id > X2AVIC_MAX_PHYSICAL_ID)) 28562306a36Sopenharmony_ci return -EINVAL; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (!vcpu->arch.apic->regs) 28862306a36Sopenharmony_ci return -EINVAL; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (kvm_apicv_activated(vcpu->kvm)) { 29162306a36Sopenharmony_ci int ret; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * Note, AVIC hardware walks the nested page table to check 29562306a36Sopenharmony_ci * permissions, but does not use the SPA address specified in 29662306a36Sopenharmony_ci * the leaf SPTE since it uses address in the AVIC_BACKING_PAGE 29762306a36Sopenharmony_ci * pointer field of the VMCB. 29862306a36Sopenharmony_ci */ 29962306a36Sopenharmony_ci ret = kvm_alloc_apic_access_page(vcpu->kvm); 30062306a36Sopenharmony_ci if (ret) 30162306a36Sopenharmony_ci return ret; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci svm->avic_backing_page = virt_to_page(vcpu->arch.apic->regs); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* Setting AVIC backing page address in the phy APIC ID table */ 30762306a36Sopenharmony_ci entry = avic_get_physical_id_entry(vcpu, id); 30862306a36Sopenharmony_ci if (!entry) 30962306a36Sopenharmony_ci return -EINVAL; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci new_entry = __sme_set((page_to_phys(svm->avic_backing_page) & 31262306a36Sopenharmony_ci AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK) | 31362306a36Sopenharmony_ci AVIC_PHYSICAL_ID_ENTRY_VALID_MASK); 31462306a36Sopenharmony_ci WRITE_ONCE(*entry, new_entry); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci svm->avic_physical_id_cache = entry; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_civoid avic_ring_doorbell(struct kvm_vcpu *vcpu) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci /* 32462306a36Sopenharmony_ci * Note, the vCPU could get migrated to a different pCPU at any point, 32562306a36Sopenharmony_ci * which could result in signalling the wrong/previous pCPU. But if 32662306a36Sopenharmony_ci * that happens the vCPU is guaranteed to do a VMRUN (after being 32762306a36Sopenharmony_ci * migrated) and thus will process pending interrupts, i.e. a doorbell 32862306a36Sopenharmony_ci * is not needed (and the spurious one is harmless). 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci int cpu = READ_ONCE(vcpu->cpu); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (cpu != get_cpu()) { 33362306a36Sopenharmony_ci wrmsrl(MSR_AMD64_SVM_AVIC_DOORBELL, kvm_cpu_get_apicid(cpu)); 33462306a36Sopenharmony_ci trace_kvm_avic_doorbell(vcpu->vcpu_id, kvm_cpu_get_apicid(cpu)); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci put_cpu(); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void avic_kick_vcpu(struct kvm_vcpu *vcpu, u32 icrl) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci vcpu->arch.apic->irr_pending = true; 34362306a36Sopenharmony_ci svm_complete_interrupt_delivery(vcpu, 34462306a36Sopenharmony_ci icrl & APIC_MODE_MASK, 34562306a36Sopenharmony_ci icrl & APIC_INT_LEVELTRIG, 34662306a36Sopenharmony_ci icrl & APIC_VECTOR_MASK); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic void avic_kick_vcpu_by_physical_id(struct kvm *kvm, u32 physical_id, 35062306a36Sopenharmony_ci u32 icrl) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci /* 35362306a36Sopenharmony_ci * KVM inhibits AVIC if any vCPU ID diverges from the vCPUs APIC ID, 35462306a36Sopenharmony_ci * i.e. APIC ID == vCPU ID. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ci struct kvm_vcpu *target_vcpu = kvm_get_vcpu_by_id(kvm, physical_id); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* Once again, nothing to do if the target vCPU doesn't exist. */ 35962306a36Sopenharmony_ci if (unlikely(!target_vcpu)) 36062306a36Sopenharmony_ci return; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci avic_kick_vcpu(target_vcpu, icrl); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic void avic_kick_vcpu_by_logical_id(struct kvm *kvm, u32 *avic_logical_id_table, 36662306a36Sopenharmony_ci u32 logid_index, u32 icrl) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci u32 physical_id; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (avic_logical_id_table) { 37162306a36Sopenharmony_ci u32 logid_entry = avic_logical_id_table[logid_index]; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* Nothing to do if the logical destination is invalid. */ 37462306a36Sopenharmony_ci if (unlikely(!(logid_entry & AVIC_LOGICAL_ID_ENTRY_VALID_MASK))) 37562306a36Sopenharmony_ci return; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci physical_id = logid_entry & 37862306a36Sopenharmony_ci AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK; 37962306a36Sopenharmony_ci } else { 38062306a36Sopenharmony_ci /* 38162306a36Sopenharmony_ci * For x2APIC, the logical APIC ID is a read-only value that is 38262306a36Sopenharmony_ci * derived from the x2APIC ID, thus the x2APIC ID can be found 38362306a36Sopenharmony_ci * by reversing the calculation (stored in logid_index). Note, 38462306a36Sopenharmony_ci * bits 31:20 of the x2APIC ID aren't propagated to the logical 38562306a36Sopenharmony_ci * ID, but KVM limits the x2APIC ID limited to KVM_MAX_VCPU_IDS. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci physical_id = logid_index; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci avic_kick_vcpu_by_physical_id(kvm, physical_id, icrl); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci/* 39462306a36Sopenharmony_ci * A fast-path version of avic_kick_target_vcpus(), which attempts to match 39562306a36Sopenharmony_ci * destination APIC ID to vCPU without looping through all vCPUs. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_cistatic int avic_kick_target_vcpus_fast(struct kvm *kvm, struct kvm_lapic *source, 39862306a36Sopenharmony_ci u32 icrl, u32 icrh, u32 index) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci int dest_mode = icrl & APIC_DEST_MASK; 40162306a36Sopenharmony_ci int shorthand = icrl & APIC_SHORT_MASK; 40262306a36Sopenharmony_ci struct kvm_svm *kvm_svm = to_kvm_svm(kvm); 40362306a36Sopenharmony_ci u32 dest; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (shorthand != APIC_DEST_NOSHORT) 40662306a36Sopenharmony_ci return -EINVAL; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (apic_x2apic_mode(source)) 40962306a36Sopenharmony_ci dest = icrh; 41062306a36Sopenharmony_ci else 41162306a36Sopenharmony_ci dest = GET_XAPIC_DEST_FIELD(icrh); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (dest_mode == APIC_DEST_PHYSICAL) { 41462306a36Sopenharmony_ci /* broadcast destination, use slow path */ 41562306a36Sopenharmony_ci if (apic_x2apic_mode(source) && dest == X2APIC_BROADCAST) 41662306a36Sopenharmony_ci return -EINVAL; 41762306a36Sopenharmony_ci if (!apic_x2apic_mode(source) && dest == APIC_BROADCAST) 41862306a36Sopenharmony_ci return -EINVAL; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (WARN_ON_ONCE(dest != index)) 42162306a36Sopenharmony_ci return -EINVAL; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci avic_kick_vcpu_by_physical_id(kvm, dest, icrl); 42462306a36Sopenharmony_ci } else { 42562306a36Sopenharmony_ci u32 *avic_logical_id_table; 42662306a36Sopenharmony_ci unsigned long bitmap, i; 42762306a36Sopenharmony_ci u32 cluster; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (apic_x2apic_mode(source)) { 43062306a36Sopenharmony_ci /* 16 bit dest mask, 16 bit cluster id */ 43162306a36Sopenharmony_ci bitmap = dest & 0xFFFF; 43262306a36Sopenharmony_ci cluster = (dest >> 16) << 4; 43362306a36Sopenharmony_ci } else if (kvm_lapic_get_reg(source, APIC_DFR) == APIC_DFR_FLAT) { 43462306a36Sopenharmony_ci /* 8 bit dest mask*/ 43562306a36Sopenharmony_ci bitmap = dest; 43662306a36Sopenharmony_ci cluster = 0; 43762306a36Sopenharmony_ci } else { 43862306a36Sopenharmony_ci /* 4 bit desk mask, 4 bit cluster id */ 43962306a36Sopenharmony_ci bitmap = dest & 0xF; 44062306a36Sopenharmony_ci cluster = (dest >> 4) << 2; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Nothing to do if there are no destinations in the cluster. */ 44462306a36Sopenharmony_ci if (unlikely(!bitmap)) 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (apic_x2apic_mode(source)) 44862306a36Sopenharmony_ci avic_logical_id_table = NULL; 44962306a36Sopenharmony_ci else 45062306a36Sopenharmony_ci avic_logical_id_table = page_address(kvm_svm->avic_logical_id_table_page); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* 45362306a36Sopenharmony_ci * AVIC is inhibited if vCPUs aren't mapped 1:1 with logical 45462306a36Sopenharmony_ci * IDs, thus each bit in the destination is guaranteed to map 45562306a36Sopenharmony_ci * to at most one vCPU. 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci for_each_set_bit(i, &bitmap, 16) 45862306a36Sopenharmony_ci avic_kick_vcpu_by_logical_id(kvm, avic_logical_id_table, 45962306a36Sopenharmony_ci cluster + i, icrl); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic void avic_kick_target_vcpus(struct kvm *kvm, struct kvm_lapic *source, 46662306a36Sopenharmony_ci u32 icrl, u32 icrh, u32 index) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci u32 dest = apic_x2apic_mode(source) ? icrh : GET_XAPIC_DEST_FIELD(icrh); 46962306a36Sopenharmony_ci unsigned long i; 47062306a36Sopenharmony_ci struct kvm_vcpu *vcpu; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (!avic_kick_target_vcpus_fast(kvm, source, icrl, icrh, index)) 47362306a36Sopenharmony_ci return; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci trace_kvm_avic_kick_vcpu_slowpath(icrh, icrl, index); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* 47862306a36Sopenharmony_ci * Wake any target vCPUs that are blocking, i.e. waiting for a wake 47962306a36Sopenharmony_ci * event. There's no need to signal doorbells, as hardware has handled 48062306a36Sopenharmony_ci * vCPUs that were in guest at the time of the IPI, and vCPUs that have 48162306a36Sopenharmony_ci * since entered the guest will have processed pending IRQs at VMRUN. 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 48462306a36Sopenharmony_ci if (kvm_apic_match_dest(vcpu, source, icrl & APIC_SHORT_MASK, 48562306a36Sopenharmony_ci dest, icrl & APIC_DEST_MASK)) 48662306a36Sopenharmony_ci avic_kick_vcpu(vcpu, icrl); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ciint avic_incomplete_ipi_interception(struct kvm_vcpu *vcpu) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 49362306a36Sopenharmony_ci u32 icrh = svm->vmcb->control.exit_info_1 >> 32; 49462306a36Sopenharmony_ci u32 icrl = svm->vmcb->control.exit_info_1; 49562306a36Sopenharmony_ci u32 id = svm->vmcb->control.exit_info_2 >> 32; 49662306a36Sopenharmony_ci u32 index = svm->vmcb->control.exit_info_2 & 0x1FF; 49762306a36Sopenharmony_ci struct kvm_lapic *apic = vcpu->arch.apic; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci trace_kvm_avic_incomplete_ipi(vcpu->vcpu_id, icrh, icrl, id, index); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci switch (id) { 50262306a36Sopenharmony_ci case AVIC_IPI_FAILURE_INVALID_TARGET: 50362306a36Sopenharmony_ci case AVIC_IPI_FAILURE_INVALID_INT_TYPE: 50462306a36Sopenharmony_ci /* 50562306a36Sopenharmony_ci * Emulate IPIs that are not handled by AVIC hardware, which 50662306a36Sopenharmony_ci * only virtualizes Fixed, Edge-Triggered INTRs, and falls over 50762306a36Sopenharmony_ci * if _any_ targets are invalid, e.g. if the logical mode mask 50862306a36Sopenharmony_ci * is a superset of running vCPUs. 50962306a36Sopenharmony_ci * 51062306a36Sopenharmony_ci * The exit is a trap, e.g. ICR holds the correct value and RIP 51162306a36Sopenharmony_ci * has been advanced, KVM is responsible only for emulating the 51262306a36Sopenharmony_ci * IPI. Sadly, hardware may sometimes leave the BUSY flag set, 51362306a36Sopenharmony_ci * in which case KVM needs to emulate the ICR write as well in 51462306a36Sopenharmony_ci * order to clear the BUSY flag. 51562306a36Sopenharmony_ci */ 51662306a36Sopenharmony_ci if (icrl & APIC_ICR_BUSY) 51762306a36Sopenharmony_ci kvm_apic_write_nodecode(vcpu, APIC_ICR); 51862306a36Sopenharmony_ci else 51962306a36Sopenharmony_ci kvm_apic_send_ipi(apic, icrl, icrh); 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci case AVIC_IPI_FAILURE_TARGET_NOT_RUNNING: 52262306a36Sopenharmony_ci /* 52362306a36Sopenharmony_ci * At this point, we expect that the AVIC HW has already 52462306a36Sopenharmony_ci * set the appropriate IRR bits on the valid target 52562306a36Sopenharmony_ci * vcpus. So, we just need to kick the appropriate vcpu. 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_ci avic_kick_target_vcpus(vcpu->kvm, apic, icrl, icrh, index); 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE: 53062306a36Sopenharmony_ci WARN_ONCE(1, "Invalid backing page\n"); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci case AVIC_IPI_FAILURE_INVALID_IPI_VECTOR: 53362306a36Sopenharmony_ci /* Invalid IPI with vector < 16 */ 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci default: 53662306a36Sopenharmony_ci vcpu_unimpl(vcpu, "Unknown avic incomplete IPI interception\n"); 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return 1; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ciunsigned long avic_vcpu_get_apicv_inhibit_reasons(struct kvm_vcpu *vcpu) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci if (is_guest_mode(vcpu)) 54562306a36Sopenharmony_ci return APICV_INHIBIT_REASON_NESTED; 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic u32 *avic_get_logical_id_entry(struct kvm_vcpu *vcpu, u32 ldr, bool flat) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm); 55262306a36Sopenharmony_ci u32 *logical_apic_id_table; 55362306a36Sopenharmony_ci u32 cluster, index; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci ldr = GET_APIC_LOGICAL_ID(ldr); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (flat) { 55862306a36Sopenharmony_ci cluster = 0; 55962306a36Sopenharmony_ci } else { 56062306a36Sopenharmony_ci cluster = (ldr >> 4); 56162306a36Sopenharmony_ci if (cluster >= 0xf) 56262306a36Sopenharmony_ci return NULL; 56362306a36Sopenharmony_ci ldr &= 0xf; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci if (!ldr || !is_power_of_2(ldr)) 56662306a36Sopenharmony_ci return NULL; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci index = __ffs(ldr); 56962306a36Sopenharmony_ci if (WARN_ON_ONCE(index > 7)) 57062306a36Sopenharmony_ci return NULL; 57162306a36Sopenharmony_ci index += (cluster << 2); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci logical_apic_id_table = (u32 *) page_address(kvm_svm->avic_logical_id_table_page); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return &logical_apic_id_table[index]; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic void avic_ldr_write(struct kvm_vcpu *vcpu, u8 g_physical_id, u32 ldr) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci bool flat; 58162306a36Sopenharmony_ci u32 *entry, new_entry; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci flat = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR) == APIC_DFR_FLAT; 58462306a36Sopenharmony_ci entry = avic_get_logical_id_entry(vcpu, ldr, flat); 58562306a36Sopenharmony_ci if (!entry) 58662306a36Sopenharmony_ci return; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci new_entry = READ_ONCE(*entry); 58962306a36Sopenharmony_ci new_entry &= ~AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK; 59062306a36Sopenharmony_ci new_entry |= (g_physical_id & AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK); 59162306a36Sopenharmony_ci new_entry |= AVIC_LOGICAL_ID_ENTRY_VALID_MASK; 59262306a36Sopenharmony_ci WRITE_ONCE(*entry, new_entry); 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic void avic_invalidate_logical_id_entry(struct kvm_vcpu *vcpu) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 59862306a36Sopenharmony_ci bool flat = svm->dfr_reg == APIC_DFR_FLAT; 59962306a36Sopenharmony_ci u32 *entry; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* Note: x2AVIC does not use logical APIC ID table */ 60262306a36Sopenharmony_ci if (apic_x2apic_mode(vcpu->arch.apic)) 60362306a36Sopenharmony_ci return; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci entry = avic_get_logical_id_entry(vcpu, svm->ldr_reg, flat); 60662306a36Sopenharmony_ci if (entry) 60762306a36Sopenharmony_ci clear_bit(AVIC_LOGICAL_ID_ENTRY_VALID_BIT, (unsigned long *)entry); 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic void avic_handle_ldr_update(struct kvm_vcpu *vcpu) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 61362306a36Sopenharmony_ci u32 ldr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_LDR); 61462306a36Sopenharmony_ci u32 id = kvm_xapic_id(vcpu->arch.apic); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* AVIC does not support LDR update for x2APIC */ 61762306a36Sopenharmony_ci if (apic_x2apic_mode(vcpu->arch.apic)) 61862306a36Sopenharmony_ci return; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (ldr == svm->ldr_reg) 62162306a36Sopenharmony_ci return; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci avic_invalidate_logical_id_entry(vcpu); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci svm->ldr_reg = ldr; 62662306a36Sopenharmony_ci avic_ldr_write(vcpu, id, ldr); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic void avic_handle_dfr_update(struct kvm_vcpu *vcpu) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 63262306a36Sopenharmony_ci u32 dfr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (svm->dfr_reg == dfr) 63562306a36Sopenharmony_ci return; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci avic_invalidate_logical_id_entry(vcpu); 63862306a36Sopenharmony_ci svm->dfr_reg = dfr; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic int avic_unaccel_trap_write(struct kvm_vcpu *vcpu) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci u32 offset = to_svm(vcpu)->vmcb->control.exit_info_1 & 64462306a36Sopenharmony_ci AVIC_UNACCEL_ACCESS_OFFSET_MASK; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci switch (offset) { 64762306a36Sopenharmony_ci case APIC_LDR: 64862306a36Sopenharmony_ci avic_handle_ldr_update(vcpu); 64962306a36Sopenharmony_ci break; 65062306a36Sopenharmony_ci case APIC_DFR: 65162306a36Sopenharmony_ci avic_handle_dfr_update(vcpu); 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci case APIC_RRR: 65462306a36Sopenharmony_ci /* Ignore writes to Read Remote Data, it's read-only. */ 65562306a36Sopenharmony_ci return 1; 65662306a36Sopenharmony_ci default: 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci kvm_apic_write_nodecode(vcpu, offset); 66162306a36Sopenharmony_ci return 1; 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic bool is_avic_unaccelerated_access_trap(u32 offset) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci bool ret = false; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci switch (offset) { 66962306a36Sopenharmony_ci case APIC_ID: 67062306a36Sopenharmony_ci case APIC_EOI: 67162306a36Sopenharmony_ci case APIC_RRR: 67262306a36Sopenharmony_ci case APIC_LDR: 67362306a36Sopenharmony_ci case APIC_DFR: 67462306a36Sopenharmony_ci case APIC_SPIV: 67562306a36Sopenharmony_ci case APIC_ESR: 67662306a36Sopenharmony_ci case APIC_ICR: 67762306a36Sopenharmony_ci case APIC_LVTT: 67862306a36Sopenharmony_ci case APIC_LVTTHMR: 67962306a36Sopenharmony_ci case APIC_LVTPC: 68062306a36Sopenharmony_ci case APIC_LVT0: 68162306a36Sopenharmony_ci case APIC_LVT1: 68262306a36Sopenharmony_ci case APIC_LVTERR: 68362306a36Sopenharmony_ci case APIC_TMICT: 68462306a36Sopenharmony_ci case APIC_TDCR: 68562306a36Sopenharmony_ci ret = true; 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci default: 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci return ret; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ciint avic_unaccelerated_access_interception(struct kvm_vcpu *vcpu) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 69662306a36Sopenharmony_ci int ret = 0; 69762306a36Sopenharmony_ci u32 offset = svm->vmcb->control.exit_info_1 & 69862306a36Sopenharmony_ci AVIC_UNACCEL_ACCESS_OFFSET_MASK; 69962306a36Sopenharmony_ci u32 vector = svm->vmcb->control.exit_info_2 & 70062306a36Sopenharmony_ci AVIC_UNACCEL_ACCESS_VECTOR_MASK; 70162306a36Sopenharmony_ci bool write = (svm->vmcb->control.exit_info_1 >> 32) & 70262306a36Sopenharmony_ci AVIC_UNACCEL_ACCESS_WRITE_MASK; 70362306a36Sopenharmony_ci bool trap = is_avic_unaccelerated_access_trap(offset); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci trace_kvm_avic_unaccelerated_access(vcpu->vcpu_id, offset, 70662306a36Sopenharmony_ci trap, write, vector); 70762306a36Sopenharmony_ci if (trap) { 70862306a36Sopenharmony_ci /* Handling Trap */ 70962306a36Sopenharmony_ci WARN_ONCE(!write, "svm: Handling trap read.\n"); 71062306a36Sopenharmony_ci ret = avic_unaccel_trap_write(vcpu); 71162306a36Sopenharmony_ci } else { 71262306a36Sopenharmony_ci /* Handling Fault */ 71362306a36Sopenharmony_ci ret = kvm_emulate_instruction(vcpu, 0); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci return ret; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ciint avic_init_vcpu(struct vcpu_svm *svm) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci int ret; 72262306a36Sopenharmony_ci struct kvm_vcpu *vcpu = &svm->vcpu; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (!enable_apicv || !irqchip_in_kernel(vcpu->kvm)) 72562306a36Sopenharmony_ci return 0; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ret = avic_init_backing_page(vcpu); 72862306a36Sopenharmony_ci if (ret) 72962306a36Sopenharmony_ci return ret; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci INIT_LIST_HEAD(&svm->ir_list); 73262306a36Sopenharmony_ci spin_lock_init(&svm->ir_list_lock); 73362306a36Sopenharmony_ci svm->dfr_reg = APIC_DFR_FLAT; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return ret; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_civoid avic_apicv_post_state_restore(struct kvm_vcpu *vcpu) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci avic_handle_dfr_update(vcpu); 74162306a36Sopenharmony_ci avic_handle_ldr_update(vcpu); 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic int avic_set_pi_irte_mode(struct kvm_vcpu *vcpu, bool activate) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci int ret = 0; 74762306a36Sopenharmony_ci unsigned long flags; 74862306a36Sopenharmony_ci struct amd_svm_iommu_ir *ir; 74962306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (!kvm_arch_has_assigned_device(vcpu->kvm)) 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* 75562306a36Sopenharmony_ci * Here, we go through the per-vcpu ir_list to update all existing 75662306a36Sopenharmony_ci * interrupt remapping table entry targeting this vcpu. 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_ci spin_lock_irqsave(&svm->ir_list_lock, flags); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (list_empty(&svm->ir_list)) 76162306a36Sopenharmony_ci goto out; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci list_for_each_entry(ir, &svm->ir_list, node) { 76462306a36Sopenharmony_ci if (activate) 76562306a36Sopenharmony_ci ret = amd_iommu_activate_guest_mode(ir->data); 76662306a36Sopenharmony_ci else 76762306a36Sopenharmony_ci ret = amd_iommu_deactivate_guest_mode(ir->data); 76862306a36Sopenharmony_ci if (ret) 76962306a36Sopenharmony_ci break; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ciout: 77262306a36Sopenharmony_ci spin_unlock_irqrestore(&svm->ir_list_lock, flags); 77362306a36Sopenharmony_ci return ret; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic void svm_ir_list_del(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci unsigned long flags; 77962306a36Sopenharmony_ci struct amd_svm_iommu_ir *cur; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci spin_lock_irqsave(&svm->ir_list_lock, flags); 78262306a36Sopenharmony_ci list_for_each_entry(cur, &svm->ir_list, node) { 78362306a36Sopenharmony_ci if (cur->data != pi->ir_data) 78462306a36Sopenharmony_ci continue; 78562306a36Sopenharmony_ci list_del(&cur->node); 78662306a36Sopenharmony_ci kfree(cur); 78762306a36Sopenharmony_ci break; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci spin_unlock_irqrestore(&svm->ir_list_lock, flags); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic int svm_ir_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci int ret = 0; 79562306a36Sopenharmony_ci unsigned long flags; 79662306a36Sopenharmony_ci struct amd_svm_iommu_ir *ir; 79762306a36Sopenharmony_ci u64 entry; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /** 80062306a36Sopenharmony_ci * In some cases, the existing irte is updated and re-set, 80162306a36Sopenharmony_ci * so we need to check here if it's already been * added 80262306a36Sopenharmony_ci * to the ir_list. 80362306a36Sopenharmony_ci */ 80462306a36Sopenharmony_ci if (pi->ir_data && (pi->prev_ga_tag != 0)) { 80562306a36Sopenharmony_ci struct kvm *kvm = svm->vcpu.kvm; 80662306a36Sopenharmony_ci u32 vcpu_id = AVIC_GATAG_TO_VCPUID(pi->prev_ga_tag); 80762306a36Sopenharmony_ci struct kvm_vcpu *prev_vcpu = kvm_get_vcpu_by_id(kvm, vcpu_id); 80862306a36Sopenharmony_ci struct vcpu_svm *prev_svm; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (!prev_vcpu) { 81162306a36Sopenharmony_ci ret = -EINVAL; 81262306a36Sopenharmony_ci goto out; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci prev_svm = to_svm(prev_vcpu); 81662306a36Sopenharmony_ci svm_ir_list_del(prev_svm, pi); 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci /** 82062306a36Sopenharmony_ci * Allocating new amd_iommu_pi_data, which will get 82162306a36Sopenharmony_ci * add to the per-vcpu ir_list. 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci ir = kzalloc(sizeof(struct amd_svm_iommu_ir), GFP_KERNEL_ACCOUNT); 82462306a36Sopenharmony_ci if (!ir) { 82562306a36Sopenharmony_ci ret = -ENOMEM; 82662306a36Sopenharmony_ci goto out; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci ir->data = pi->ir_data; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci spin_lock_irqsave(&svm->ir_list_lock, flags); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci /* 83362306a36Sopenharmony_ci * Update the target pCPU for IOMMU doorbells if the vCPU is running. 83462306a36Sopenharmony_ci * If the vCPU is NOT running, i.e. is blocking or scheduled out, KVM 83562306a36Sopenharmony_ci * will update the pCPU info when the vCPU awkened and/or scheduled in. 83662306a36Sopenharmony_ci * See also avic_vcpu_load(). 83762306a36Sopenharmony_ci */ 83862306a36Sopenharmony_ci entry = READ_ONCE(*(svm->avic_physical_id_cache)); 83962306a36Sopenharmony_ci if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) 84062306a36Sopenharmony_ci amd_iommu_update_ga(entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK, 84162306a36Sopenharmony_ci true, pi->ir_data); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci list_add(&ir->node, &svm->ir_list); 84462306a36Sopenharmony_ci spin_unlock_irqrestore(&svm->ir_list_lock, flags); 84562306a36Sopenharmony_ciout: 84662306a36Sopenharmony_ci return ret; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci/* 85062306a36Sopenharmony_ci * Note: 85162306a36Sopenharmony_ci * The HW cannot support posting multicast/broadcast 85262306a36Sopenharmony_ci * interrupts to a vCPU. So, we still use legacy interrupt 85362306a36Sopenharmony_ci * remapping for these kind of interrupts. 85462306a36Sopenharmony_ci * 85562306a36Sopenharmony_ci * For lowest-priority interrupts, we only support 85662306a36Sopenharmony_ci * those with single CPU as the destination, e.g. user 85762306a36Sopenharmony_ci * configures the interrupts via /proc/irq or uses 85862306a36Sopenharmony_ci * irqbalance to make the interrupts single-CPU. 85962306a36Sopenharmony_ci */ 86062306a36Sopenharmony_cistatic int 86162306a36Sopenharmony_ciget_pi_vcpu_info(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e, 86262306a36Sopenharmony_ci struct vcpu_data *vcpu_info, struct vcpu_svm **svm) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct kvm_lapic_irq irq; 86562306a36Sopenharmony_ci struct kvm_vcpu *vcpu = NULL; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci kvm_set_msi_irq(kvm, e, &irq); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu) || 87062306a36Sopenharmony_ci !kvm_irq_is_postable(&irq)) { 87162306a36Sopenharmony_ci pr_debug("SVM: %s: use legacy intr remap mode for irq %u\n", 87262306a36Sopenharmony_ci __func__, irq.vector); 87362306a36Sopenharmony_ci return -1; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci pr_debug("SVM: %s: use GA mode for irq %u\n", __func__, 87762306a36Sopenharmony_ci irq.vector); 87862306a36Sopenharmony_ci *svm = to_svm(vcpu); 87962306a36Sopenharmony_ci vcpu_info->pi_desc_addr = __sme_set(page_to_phys((*svm)->avic_backing_page)); 88062306a36Sopenharmony_ci vcpu_info->vector = irq.vector; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci return 0; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci/* 88662306a36Sopenharmony_ci * avic_pi_update_irte - set IRTE for Posted-Interrupts 88762306a36Sopenharmony_ci * 88862306a36Sopenharmony_ci * @kvm: kvm 88962306a36Sopenharmony_ci * @host_irq: host irq of the interrupt 89062306a36Sopenharmony_ci * @guest_irq: gsi of the interrupt 89162306a36Sopenharmony_ci * @set: set or unset PI 89262306a36Sopenharmony_ci * returns 0 on success, < 0 on failure 89362306a36Sopenharmony_ci */ 89462306a36Sopenharmony_ciint avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq, 89562306a36Sopenharmony_ci uint32_t guest_irq, bool set) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct kvm_kernel_irq_routing_entry *e; 89862306a36Sopenharmony_ci struct kvm_irq_routing_table *irq_rt; 89962306a36Sopenharmony_ci int idx, ret = 0; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (!kvm_arch_has_assigned_device(kvm) || 90262306a36Sopenharmony_ci !irq_remapping_cap(IRQ_POSTING_CAP)) 90362306a36Sopenharmony_ci return 0; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci pr_debug("SVM: %s: host_irq=%#x, guest_irq=%#x, set=%#x\n", 90662306a36Sopenharmony_ci __func__, host_irq, guest_irq, set); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci idx = srcu_read_lock(&kvm->irq_srcu); 90962306a36Sopenharmony_ci irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (guest_irq >= irq_rt->nr_rt_entries || 91262306a36Sopenharmony_ci hlist_empty(&irq_rt->map[guest_irq])) { 91362306a36Sopenharmony_ci pr_warn_once("no route for guest_irq %u/%u (broken user space?)\n", 91462306a36Sopenharmony_ci guest_irq, irq_rt->nr_rt_entries); 91562306a36Sopenharmony_ci goto out; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) { 91962306a36Sopenharmony_ci struct vcpu_data vcpu_info; 92062306a36Sopenharmony_ci struct vcpu_svm *svm = NULL; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (e->type != KVM_IRQ_ROUTING_MSI) 92362306a36Sopenharmony_ci continue; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /** 92662306a36Sopenharmony_ci * Here, we setup with legacy mode in the following cases: 92762306a36Sopenharmony_ci * 1. When cannot target interrupt to a specific vcpu. 92862306a36Sopenharmony_ci * 2. Unsetting posted interrupt. 92962306a36Sopenharmony_ci * 3. APIC virtualization is disabled for the vcpu. 93062306a36Sopenharmony_ci * 4. IRQ has incompatible delivery mode (SMI, INIT, etc) 93162306a36Sopenharmony_ci */ 93262306a36Sopenharmony_ci if (!get_pi_vcpu_info(kvm, e, &vcpu_info, &svm) && set && 93362306a36Sopenharmony_ci kvm_vcpu_apicv_active(&svm->vcpu)) { 93462306a36Sopenharmony_ci struct amd_iommu_pi_data pi; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Try to enable guest_mode in IRTE */ 93762306a36Sopenharmony_ci pi.base = __sme_set(page_to_phys(svm->avic_backing_page) & 93862306a36Sopenharmony_ci AVIC_HPA_MASK); 93962306a36Sopenharmony_ci pi.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id, 94062306a36Sopenharmony_ci svm->vcpu.vcpu_id); 94162306a36Sopenharmony_ci pi.is_guest_mode = true; 94262306a36Sopenharmony_ci pi.vcpu_data = &vcpu_info; 94362306a36Sopenharmony_ci ret = irq_set_vcpu_affinity(host_irq, &pi); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /** 94662306a36Sopenharmony_ci * Here, we successfully setting up vcpu affinity in 94762306a36Sopenharmony_ci * IOMMU guest mode. Now, we need to store the posted 94862306a36Sopenharmony_ci * interrupt information in a per-vcpu ir_list so that 94962306a36Sopenharmony_ci * we can reference to them directly when we update vcpu 95062306a36Sopenharmony_ci * scheduling information in IOMMU irte. 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_ci if (!ret && pi.is_guest_mode) 95362306a36Sopenharmony_ci svm_ir_list_add(svm, &pi); 95462306a36Sopenharmony_ci } else { 95562306a36Sopenharmony_ci /* Use legacy mode in IRTE */ 95662306a36Sopenharmony_ci struct amd_iommu_pi_data pi; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /** 95962306a36Sopenharmony_ci * Here, pi is used to: 96062306a36Sopenharmony_ci * - Tell IOMMU to use legacy mode for this interrupt. 96162306a36Sopenharmony_ci * - Retrieve ga_tag of prior interrupt remapping data. 96262306a36Sopenharmony_ci */ 96362306a36Sopenharmony_ci pi.prev_ga_tag = 0; 96462306a36Sopenharmony_ci pi.is_guest_mode = false; 96562306a36Sopenharmony_ci ret = irq_set_vcpu_affinity(host_irq, &pi); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /** 96862306a36Sopenharmony_ci * Check if the posted interrupt was previously 96962306a36Sopenharmony_ci * setup with the guest_mode by checking if the ga_tag 97062306a36Sopenharmony_ci * was cached. If so, we need to clean up the per-vcpu 97162306a36Sopenharmony_ci * ir_list. 97262306a36Sopenharmony_ci */ 97362306a36Sopenharmony_ci if (!ret && pi.prev_ga_tag) { 97462306a36Sopenharmony_ci int id = AVIC_GATAG_TO_VCPUID(pi.prev_ga_tag); 97562306a36Sopenharmony_ci struct kvm_vcpu *vcpu; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci vcpu = kvm_get_vcpu_by_id(kvm, id); 97862306a36Sopenharmony_ci if (vcpu) 97962306a36Sopenharmony_ci svm_ir_list_del(to_svm(vcpu), &pi); 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (!ret && svm) { 98462306a36Sopenharmony_ci trace_kvm_pi_irte_update(host_irq, svm->vcpu.vcpu_id, 98562306a36Sopenharmony_ci e->gsi, vcpu_info.vector, 98662306a36Sopenharmony_ci vcpu_info.pi_desc_addr, set); 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (ret < 0) { 99062306a36Sopenharmony_ci pr_err("%s: failed to update PI IRTE\n", __func__); 99162306a36Sopenharmony_ci goto out; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci ret = 0; 99662306a36Sopenharmony_ciout: 99762306a36Sopenharmony_ci srcu_read_unlock(&kvm->irq_srcu, idx); 99862306a36Sopenharmony_ci return ret; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic inline int 100262306a36Sopenharmony_ciavic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu, bool r) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci int ret = 0; 100562306a36Sopenharmony_ci struct amd_svm_iommu_ir *ir; 100662306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci lockdep_assert_held(&svm->ir_list_lock); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (!kvm_arch_has_assigned_device(vcpu->kvm)) 101162306a36Sopenharmony_ci return 0; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci /* 101462306a36Sopenharmony_ci * Here, we go through the per-vcpu ir_list to update all existing 101562306a36Sopenharmony_ci * interrupt remapping table entry targeting this vcpu. 101662306a36Sopenharmony_ci */ 101762306a36Sopenharmony_ci if (list_empty(&svm->ir_list)) 101862306a36Sopenharmony_ci return 0; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci list_for_each_entry(ir, &svm->ir_list, node) { 102162306a36Sopenharmony_ci ret = amd_iommu_update_ga(cpu, r, ir->data); 102262306a36Sopenharmony_ci if (ret) 102362306a36Sopenharmony_ci return ret; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci return 0; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_civoid avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci u64 entry; 103162306a36Sopenharmony_ci int h_physical_id = kvm_cpu_get_apicid(cpu); 103262306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 103362306a36Sopenharmony_ci unsigned long flags; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci lockdep_assert_preemption_disabled(); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (WARN_ON(h_physical_id & ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK)) 103862306a36Sopenharmony_ci return; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* 104162306a36Sopenharmony_ci * No need to update anything if the vCPU is blocking, i.e. if the vCPU 104262306a36Sopenharmony_ci * is being scheduled in after being preempted. The CPU entries in the 104362306a36Sopenharmony_ci * Physical APIC table and IRTE are consumed iff IsRun{ning} is '1'. 104462306a36Sopenharmony_ci * If the vCPU was migrated, its new CPU value will be stuffed when the 104562306a36Sopenharmony_ci * vCPU unblocks. 104662306a36Sopenharmony_ci */ 104762306a36Sopenharmony_ci if (kvm_vcpu_is_blocking(vcpu)) 104862306a36Sopenharmony_ci return; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci /* 105162306a36Sopenharmony_ci * Grab the per-vCPU interrupt remapping lock even if the VM doesn't 105262306a36Sopenharmony_ci * _currently_ have assigned devices, as that can change. Holding 105362306a36Sopenharmony_ci * ir_list_lock ensures that either svm_ir_list_add() will consume 105462306a36Sopenharmony_ci * up-to-date entry information, or that this task will wait until 105562306a36Sopenharmony_ci * svm_ir_list_add() completes to set the new target pCPU. 105662306a36Sopenharmony_ci */ 105762306a36Sopenharmony_ci spin_lock_irqsave(&svm->ir_list_lock, flags); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci entry = READ_ONCE(*(svm->avic_physical_id_cache)); 106062306a36Sopenharmony_ci WARN_ON_ONCE(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci entry &= ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK; 106362306a36Sopenharmony_ci entry |= (h_physical_id & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK); 106462306a36Sopenharmony_ci entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci WRITE_ONCE(*(svm->avic_physical_id_cache), entry); 106762306a36Sopenharmony_ci avic_update_iommu_vcpu_affinity(vcpu, h_physical_id, true); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci spin_unlock_irqrestore(&svm->ir_list_lock, flags); 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_civoid avic_vcpu_put(struct kvm_vcpu *vcpu) 107362306a36Sopenharmony_ci{ 107462306a36Sopenharmony_ci u64 entry; 107562306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 107662306a36Sopenharmony_ci unsigned long flags; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci lockdep_assert_preemption_disabled(); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci /* 108162306a36Sopenharmony_ci * Note, reading the Physical ID entry outside of ir_list_lock is safe 108262306a36Sopenharmony_ci * as only the pCPU that has loaded (or is loading) the vCPU is allowed 108362306a36Sopenharmony_ci * to modify the entry, and preemption is disabled. I.e. the vCPU 108462306a36Sopenharmony_ci * can't be scheduled out and thus avic_vcpu_{put,load}() can't run 108562306a36Sopenharmony_ci * recursively. 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_ci entry = READ_ONCE(*(svm->avic_physical_id_cache)); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci /* Nothing to do if IsRunning == '0' due to vCPU blocking. */ 109062306a36Sopenharmony_ci if (!(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)) 109162306a36Sopenharmony_ci return; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci /* 109462306a36Sopenharmony_ci * Take and hold the per-vCPU interrupt remapping lock while updating 109562306a36Sopenharmony_ci * the Physical ID entry even though the lock doesn't protect against 109662306a36Sopenharmony_ci * multiple writers (see above). Holding ir_list_lock ensures that 109762306a36Sopenharmony_ci * either svm_ir_list_add() will consume up-to-date entry information, 109862306a36Sopenharmony_ci * or that this task will wait until svm_ir_list_add() completes to 109962306a36Sopenharmony_ci * mark the vCPU as not running. 110062306a36Sopenharmony_ci */ 110162306a36Sopenharmony_ci spin_lock_irqsave(&svm->ir_list_lock, flags); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci avic_update_iommu_vcpu_affinity(vcpu, -1, 0); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; 110662306a36Sopenharmony_ci WRITE_ONCE(*(svm->avic_physical_id_cache), entry); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci spin_unlock_irqrestore(&svm->ir_list_lock, flags); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_civoid avic_refresh_virtual_apic_mode(struct kvm_vcpu *vcpu) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci struct vcpu_svm *svm = to_svm(vcpu); 111562306a36Sopenharmony_ci struct vmcb *vmcb = svm->vmcb01.ptr; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (!lapic_in_kernel(vcpu) || !enable_apicv) 111862306a36Sopenharmony_ci return; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci if (kvm_vcpu_apicv_active(vcpu)) { 112162306a36Sopenharmony_ci /** 112262306a36Sopenharmony_ci * During AVIC temporary deactivation, guest could update 112362306a36Sopenharmony_ci * APIC ID, DFR and LDR registers, which would not be trapped 112462306a36Sopenharmony_ci * by avic_unaccelerated_access_interception(). In this case, 112562306a36Sopenharmony_ci * we need to check and update the AVIC logical APIC ID table 112662306a36Sopenharmony_ci * accordingly before re-activating. 112762306a36Sopenharmony_ci */ 112862306a36Sopenharmony_ci avic_apicv_post_state_restore(vcpu); 112962306a36Sopenharmony_ci avic_activate_vmcb(svm); 113062306a36Sopenharmony_ci } else { 113162306a36Sopenharmony_ci avic_deactivate_vmcb(svm); 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci vmcb_mark_dirty(vmcb, VMCB_AVIC); 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_civoid avic_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci bool activated = kvm_vcpu_apicv_active(vcpu); 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci if (!enable_apicv) 114162306a36Sopenharmony_ci return; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci avic_refresh_virtual_apic_mode(vcpu); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci if (activated) 114662306a36Sopenharmony_ci avic_vcpu_load(vcpu, vcpu->cpu); 114762306a36Sopenharmony_ci else 114862306a36Sopenharmony_ci avic_vcpu_put(vcpu); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci avic_set_pi_irte_mode(vcpu, activated); 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_civoid avic_vcpu_blocking(struct kvm_vcpu *vcpu) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci if (!kvm_vcpu_apicv_active(vcpu)) 115662306a36Sopenharmony_ci return; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci /* 115962306a36Sopenharmony_ci * Unload the AVIC when the vCPU is about to block, _before_ 116062306a36Sopenharmony_ci * the vCPU actually blocks. 116162306a36Sopenharmony_ci * 116262306a36Sopenharmony_ci * Any IRQs that arrive before IsRunning=0 will not cause an 116362306a36Sopenharmony_ci * incomplete IPI vmexit on the source, therefore vIRR will also 116462306a36Sopenharmony_ci * be checked by kvm_vcpu_check_block() before blocking. The 116562306a36Sopenharmony_ci * memory barrier implicit in set_current_state orders writing 116662306a36Sopenharmony_ci * IsRunning=0 before reading the vIRR. The processor needs a 116762306a36Sopenharmony_ci * matching memory barrier on interrupt delivery between writing 116862306a36Sopenharmony_ci * IRR and reading IsRunning; the lack of this barrier might be 116962306a36Sopenharmony_ci * the cause of errata #1235). 117062306a36Sopenharmony_ci */ 117162306a36Sopenharmony_ci avic_vcpu_put(vcpu); 117262306a36Sopenharmony_ci} 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_civoid avic_vcpu_unblocking(struct kvm_vcpu *vcpu) 117562306a36Sopenharmony_ci{ 117662306a36Sopenharmony_ci if (!kvm_vcpu_apicv_active(vcpu)) 117762306a36Sopenharmony_ci return; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci avic_vcpu_load(vcpu, vcpu->cpu); 118062306a36Sopenharmony_ci} 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci/* 118362306a36Sopenharmony_ci * Note: 118462306a36Sopenharmony_ci * - The module param avic enable both xAPIC and x2APIC mode. 118562306a36Sopenharmony_ci * - Hypervisor can support both xAVIC and x2AVIC in the same guest. 118662306a36Sopenharmony_ci * - The mode can be switched at run-time. 118762306a36Sopenharmony_ci */ 118862306a36Sopenharmony_cibool avic_hardware_setup(void) 118962306a36Sopenharmony_ci{ 119062306a36Sopenharmony_ci if (!npt_enabled) 119162306a36Sopenharmony_ci return false; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci /* AVIC is a prerequisite for x2AVIC. */ 119462306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_AVIC) && !force_avic) { 119562306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_X2AVIC)) { 119662306a36Sopenharmony_ci pr_warn(FW_BUG "Cannot support x2AVIC due to AVIC is disabled"); 119762306a36Sopenharmony_ci pr_warn(FW_BUG "Try enable AVIC using force_avic option"); 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci return false; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_AVIC)) { 120362306a36Sopenharmony_ci pr_info("AVIC enabled\n"); 120462306a36Sopenharmony_ci } else if (force_avic) { 120562306a36Sopenharmony_ci /* 120662306a36Sopenharmony_ci * Some older systems does not advertise AVIC support. 120762306a36Sopenharmony_ci * See Revision Guide for specific AMD processor for more detail. 120862306a36Sopenharmony_ci */ 120962306a36Sopenharmony_ci pr_warn("AVIC is not supported in CPUID but force enabled"); 121062306a36Sopenharmony_ci pr_warn("Your system might crash and burn"); 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci /* AVIC is a prerequisite for x2AVIC. */ 121462306a36Sopenharmony_ci x2avic_enabled = boot_cpu_has(X86_FEATURE_X2AVIC); 121562306a36Sopenharmony_ci if (x2avic_enabled) 121662306a36Sopenharmony_ci pr_info("x2AVIC enabled\n"); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci amd_iommu_register_ga_log_notifier(&avic_ga_log_notifier); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci return true; 122162306a36Sopenharmony_ci} 1222