Add KVM_CAP_LAPIC2 to allow userspace to opt into extended APIC register space, i.e. to expose the full 4KB APIC page to the guest. Extended LVT registers are part of the 4KB APIC page and are AMD-specific. Extended APIC registers provide additional interrupt vectors for hardware features like Instruction Based Sampling (IBS). Use a capability negotiation model to allow for future extensibility. KVM_CHECK_EXTENSION returns a bitmask of supported capabilities, and userspace enables the intersection of KVM and VMM support via KVM_ENABLE_CAP. This allows KVM and userspace to independently add support for new APIC configurations without breaking compatibility. Define two capability flags: - KVM_LAPIC2_DEFAULT: full 4KB APIC page support - KVM_LAPIC2_AMD_DEFAULT: extended LVT registers are supported Require that the capability be enabled before vCPUs are created to avoid the need to handle runtime changes to the APIC page size. When KVM_LAPIC2_AMD_DEFAULT is enabled, set kvm->arch.nr_extlvt to KVM_X86_NR_EXTLVT_DEFAULT (4) to track the number of extended LVT registers available to the guest. Future patches will use nr_extlvt to emulate guest accesses to extended LVT registers at APIC offset 0x500. Suggested-by: Naveen N Rao (AMD) Signed-off-by: Manali Shukla --- Documentation/virt/kvm/api.rst | 31 +++++++++++++++++++++++++++++++ arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/x86.c | 30 ++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 5 +++++ 4 files changed, 67 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 01a3abef8abb..71b4d24f009a 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -9291,6 +9291,37 @@ KVM exits with the register state of either the L1 or L2 guest depending on which executed at the time of an exit. Userspace must take care to differentiate between these cases. +8.46 KVM_CAP_LAPIC2 +--------------------------- + +:Architectures: x86 +:Target: VM +:Parameters: args[0] is a bitmask of LAPIC2 capabilities +:Returns: 0 on success, -EINVAL when arg[0] contains invalid bits + +This capability indicates that KVM supports extended APIC register space of the +whole 4KB page. + +Calling KVM_CHECK_EXTENSION for this capability returns a bitmask of LAPIC2 +capabilities that can be enabled on a VM. + +The argument to KVM_ENABLE_CAP is also a bitmask that selects which LAPIC2 +capabilities to enable for the VM. Userspace should enable the intersection +of capabilities supported by KVM (from KVM_CHECK_EXTENSION) and capabilities +supported by the VMM. This must be called before creating any VCPUs. + +At this time, KVM_LAPIC2_DEFAULT and KVM_LAPIC2_AMD_DEFAULT are the supported +capabilities: + + - KVM_LAPIC2_DEFAULT: Full 4KB APIC page support + - KVM_LAPIC2_AMD_DEFAULT: Extended LVT registers are supported (they are part + of 4KB APIC page) + +KVM_LAPIC2_AMD_DEFAULT is available on AMD processors with ExtApicSpace feature +(CPUID 8000_0001h.ECX[3]). Extended APIC registers start at APIC offset 400h. +Currently 4 extended LVT registers are supported, used for features like +Instruction Based Sampling (IBS), but future processors may support more. + 9. Known KVM API problems ========================= diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index df642723cea6..5a659982aebd 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1460,6 +1460,7 @@ struct kvm_arch { u32 default_tsc_khz; bool user_set_tsc; u64 apic_bus_cycle_ns; + u8 nr_extlvt; seqcount_raw_spinlock_t pvclock_sc; bool use_master_clock; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8acfdfc583a1..368ee9276366 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4990,6 +4990,18 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_READONLY_MEM: r = kvm ? kvm_arch_has_readonly_mem(kvm) : 1; break; + case KVM_CAP_LAPIC2: { + u8 max_extlvt; + + r = KVM_LAPIC2_DEFAULT; + if (!kvm_caps.has_extapic) + break; + + max_extlvt = kvm_cpu_get_max_extlvt(); + if (max_extlvt == KVM_X86_NR_EXTLVT_DEFAULT) + r |= KVM_LAPIC2_AMD_DEFAULT; + break; + } default: break; } @@ -6966,6 +6978,24 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, mutex_unlock(&kvm->lock); break; } + case KVM_CAP_LAPIC2: { + r = -EINVAL; + + mutex_lock(&kvm->lock); + + kvm->arch.nr_extlvt = 0; + + if (!kvm->created_vcpus) { + if (cap->args[0] & KVM_LAPIC2_DEFAULT) { + r = 0; + if (cap->args[0] & KVM_LAPIC2_AMD_DEFAULT) + kvm->arch.nr_extlvt = KVM_X86_NR_EXTLVT_DEFAULT; + } + } + + mutex_unlock(&kvm->lock); + break; + } default: r = -EINVAL; break; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 76bd54848b11..cb27eeb09bdb 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -659,6 +659,10 @@ struct kvm_ioeventfd { #define KVM_X86_DISABLE_EXITS_CSTATE (1 << 3) #define KVM_X86_DISABLE_EXITS_APERFMPERF (1 << 4) +#define KVM_X86_NR_EXTLVT_DEFAULT 4 +#define KVM_LAPIC2_DEFAULT (1 << 0) +#define KVM_LAPIC2_AMD_DEFAULT (1 << 1) + /* for KVM_ENABLE_CAP */ struct kvm_enable_cap { /* in */ @@ -978,6 +982,7 @@ struct kvm_enable_cap { #define KVM_CAP_GUEST_MEMFD_FLAGS 244 #define KVM_CAP_ARM_SEA_TO_USER 245 #define KVM_CAP_S390_USER_OPEREXEC 246 +#define KVM_CAP_LAPIC2 247 struct kvm_irq_routing_irqchip { __u32 irqchip; -- 2.43.0