arch/x86/kvm/svm/avic.c
Source file repositories/reference/linux-study-clean/arch/x86/kvm/svm/avic.c
File Facts
- System
- Linux kernel
- Corpus path
arch/x86/kvm/svm/avic.c- Extension
.c- Size
- 39515 bytes
- Lines
- 1322
- Domain
- Architecture Layer
- Bucket
- arch/x86
- Inferred role
- Architecture Layer: implementation source
- Status
- source implementation candidate
Why This File Exists
CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.
- CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/kvm_types.hlinux/hashtable.hlinux/amd-iommu.hlinux/kvm_host.hlinux/kvm_irqfd.hlinux/sysfs.hasm/irq_remapping.hasm/msr.htrace.hlapic.hx86.hirq.hsvm.h
Detected Declarations
enum avic_vcpu_actionfunction avic_param_setfunction avic_param_getfunction avic_set_x2apic_msr_interceptionfunction __avic_get_max_physical_idfunction avic_get_max_physical_idfunction avic_activate_vmcbfunction avic_deactivate_vmcbfunction avic_ga_log_notifierfunction avic_get_physical_id_table_orderfunction avic_alloc_physical_id_tablefunction avic_vm_destroyfunction avic_vm_initfunction hash_for_each_possiblefunction avic_get_backing_page_addressfunction avic_init_vmcbfunction avic_init_backing_pagefunction avic_vcpu_loadfunction avic_ring_doorbellfunction avic_kick_vcpufunction avic_kick_vcpu_by_physical_idfunction avic_kick_vcpu_by_logical_idfunction avic_kick_target_vcpus_fastfunction avic_kick_target_vcpusfunction avic_incomplete_ipi_interceptionfunction avic_vcpu_get_apicv_inhibit_reasonsfunction avic_ldr_writefunction avic_invalidate_logical_id_entryfunction avic_handle_ldr_updatefunction avic_handle_dfr_updatefunction avic_unaccel_trap_writefunction is_avic_unaccelerated_access_trapfunction avic_unaccelerated_access_interceptionfunction avic_init_vcpufunction avic_apicv_post_state_restorefunction svm_ir_list_delfunction avic_pi_update_irtefunction avic_update_iommu_vcpu_affinityfunction list_for_each_entryfunction __avic_vcpu_loadfunction avic_vcpu_loadfunction __avic_vcpu_putfunction avic_vcpu_putfunction avic_refresh_virtual_apic_modefunction avic_refresh_apicv_exec_ctrlfunction avic_vcpu_blockingfunction avic_vcpu_unblockingfunction avic_want_avic_enabled
Annotated Snippet
hash_for_each_possible(svm_vm_data_hash, k2, hnode, vm_id) {
if (k2->avic_vm_id == vm_id)
goto again;
}
}
kvm_svm->avic_vm_id = vm_id;
hash_add(svm_vm_data_hash, &kvm_svm->hnode, kvm_svm->avic_vm_id);
spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
return 0;
free_avic:
avic_vm_destroy(kvm);
return err;
}
static phys_addr_t avic_get_backing_page_address(struct vcpu_svm *svm)
{
return __sme_set(__pa(svm->vcpu.arch.apic->regs));
}
void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb)
{
struct kvm_svm *kvm_svm = to_kvm_svm(svm->vcpu.kvm);
vmcb->control.avic_backing_page = avic_get_backing_page_address(svm);
vmcb->control.avic_logical_id = __sme_set(__pa(kvm_svm->avic_logical_id_table));
vmcb->control.avic_physical_id = __sme_set(__pa(kvm_svm->avic_physical_id_table));
vmcb->control.avic_vapic_bar = APIC_DEFAULT_PHYS_BASE;
if (kvm_vcpu_apicv_active(&svm->vcpu))
avic_activate_vmcb(svm);
else
avic_deactivate_vmcb(svm);
}
static int avic_init_backing_page(struct kvm_vcpu *vcpu)
{
u32 max_id = x2avic_enabled ? x2avic_max_physical_id : AVIC_MAX_PHYSICAL_ID;
struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm);
struct vcpu_svm *svm = to_svm(vcpu);
u32 id = vcpu->vcpu_id;
u64 new_entry;
/*
* Inhibit AVIC if the vCPU ID is bigger than what is supported by AVIC
* hardware. Immediately clear apicv_active, i.e. don't wait until the
* KVM_REQ_APICV_UPDATE request is processed on the first KVM_RUN, as
* avic_vcpu_load() expects to be called if and only if the vCPU has
* fully initialized AVIC.
*/
if (id > max_id) {
kvm_set_apicv_inhibit(vcpu->kvm, APICV_INHIBIT_REASON_PHYSICAL_ID_TOO_BIG);
vcpu->arch.apic->apicv_active = false;
return 0;
}
BUILD_BUG_ON((AVIC_MAX_PHYSICAL_ID + 1) * sizeof(new_entry) > PAGE_SIZE ||
(X2AVIC_MAX_PHYSICAL_ID + 1) * sizeof(new_entry) > PAGE_SIZE);
if (WARN_ON_ONCE(!vcpu->arch.apic->regs))
return -EINVAL;
if (kvm_apicv_activated(vcpu->kvm)) {
int ret;
/*
* Note, AVIC hardware walks the nested page table to check
* permissions, but does not use the SPA address specified in
* the leaf SPTE since it uses address in the AVIC_BACKING_PAGE
* pointer field of the VMCB.
*/
ret = kvm_alloc_apic_access_page(vcpu->kvm);
if (ret)
return ret;
}
/* Note, fls64() returns the bit position, +1. */
BUILD_BUG_ON(__PHYSICAL_MASK_SHIFT >
fls64(AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK));
/* Setting AVIC backing page address in the phy APIC ID table */
new_entry = avic_get_backing_page_address(svm) |
AVIC_PHYSICAL_ID_ENTRY_VALID_MASK;
svm->avic_physical_id_entry = new_entry;
/*
* Initialize the real table, as vCPUs must have a valid entry in order
* for broadcast IPIs to function correctly (broadcast IPIs ignore
* invalid entries, i.e. aren't guaranteed to generate a VM-Exit).
Annotation
- Immediate include surface: `linux/kvm_types.h`, `linux/hashtable.h`, `linux/amd-iommu.h`, `linux/kvm_host.h`, `linux/kvm_irqfd.h`, `linux/sysfs.h`, `asm/irq_remapping.h`, `asm/msr.h`.
- Detected declarations: `enum avic_vcpu_action`, `function avic_param_set`, `function avic_param_get`, `function avic_set_x2apic_msr_interception`, `function __avic_get_max_physical_id`, `function avic_get_max_physical_id`, `function avic_activate_vmcb`, `function avic_deactivate_vmcb`, `function avic_ga_log_notifier`, `function avic_get_physical_id_table_order`.
- Atlas domain: Architecture Layer / arch/x86.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.