]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: TDX: Force APICv active for TDX guest
authorIsaku Yamahata <isaku.yamahata@intel.com>
Sat, 22 Feb 2025 01:47:52 +0000 (09:47 +0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 14 Mar 2025 18:20:56 +0000 (14:20 -0400)
Force APICv active for TDX guests in KVM because APICv is always enabled
by TDX module.

From the view of KVM, whether APICv state is active or not is decided by:
1. APIC is hw enabled
2. VM and vCPU have no inhibit reasons set.

After TDX vCPU init, APIC is set to x2APIC mode. KVM_SET_{SREGS,SREGS2} are
rejected due to has_protected_state for TDs and guest_state_protected
for TDX vCPUs are set.  Reject KVM_{GET,SET}_LAPIC from userspace since
migration is not supported yet, so that userspace cannot disable APIC.

For various APICv inhibit reasons:
- APICV_INHIBIT_REASON_DISABLED is impossible after checking enable_apicv
  in tdx_bringup(). If !enable_apicv, TDX support will be disabled.
- APICV_INHIBIT_REASON_PHYSICAL_ID_ALIASED is impossible since x2APIC is
  mandatory, KVM emulates APIC_ID as read-only for x2APIC mode. (Note:
  APICV_INHIBIT_REASON_PHYSICAL_ID_ALIASED could be set if the memory
  allocation fails for KVM apic_map.)
- APICV_INHIBIT_REASON_HYPERV is impossible since TDX doesn't support
  HyperV guest yet.
- APICV_INHIBIT_REASON_ABSENT is impossible since in-kernel LAPIC is
  checked in tdx_vcpu_create().
- APICV_INHIBIT_REASON_BLOCKIRQ is impossible since TDX doesn't support
  KVM_SET_GUEST_DEBUG.
- APICV_INHIBIT_REASON_APIC_ID_MODIFIED is impossible since x2APIC is
  mandatory.
- APICV_INHIBIT_REASON_APIC_BASE_MODIFIED is impossible since KVM rejects
  userspace to set APIC base.
- The rest inhibit reasons are relevant only to AMD's AVIC, including
  APICV_INHIBIT_REASON_NESTED, APICV_INHIBIT_REASON_IRQWIN,
  APICV_INHIBIT_REASON_PIT_REINJ, APICV_INHIBIT_REASON_SEV, and
  APICV_INHIBIT_REASON_LOGICAL_ID_ALIASED.
  (For APICV_INHIBIT_REASON_PIT_REINJ, similar to AVIC, KVM can't intercept
   EOI for TDX guests neither, but KVM enforces KVM_IRQCHIP_SPLIT for TDX
   guests, which eliminates the in-kernel PIT.)

Implement vt_refresh_apicv_exec_ctrl() to call KVM_BUG_ON() if APICv is
disabled for TDX guests.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Co-developed-by: Binbin Wu <binbin.wu@linux.intel.com>
Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
Message-ID: <20250222014757.897978-12-binbin.wu@linux.intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx/main.c
arch/x86/kvm/vmx/tdx.c
arch/x86/kvm/x86.c

index 0be6abc77f4c3b0dbb1a287618cdd5f62da3ad88..66545d5b009dcc1d5409c8f0fa3821a248a1b1d0 100644 (file)
@@ -437,6 +437,16 @@ static void vt_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
        vmx_get_exit_info(vcpu, reason, info1, info2, intr_info, error_code);
 }
 
+static void vt_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
+{
+       if (is_td_vcpu(vcpu)) {
+               KVM_BUG_ON(!kvm_vcpu_apicv_active(vcpu), vcpu->kvm);
+               return;
+       }
+
+       vmx_refresh_apicv_exec_ctrl(vcpu);
+}
+
 static int vt_mem_enc_ioctl(struct kvm *kvm, void __user *argp)
 {
        if (!is_td(kvm))
@@ -553,7 +563,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
        .x2apic_icr_is_split = false,
        .set_virtual_apic_mode = vmx_set_virtual_apic_mode,
        .set_apic_access_page_addr = vmx_set_apic_access_page_addr,
-       .refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl,
+       .refresh_apicv_exec_ctrl = vt_refresh_apicv_exec_ctrl,
        .load_eoi_exitmap = vmx_load_eoi_exitmap,
        .apicv_pre_state_restore = vt_apicv_pre_state_restore,
        .required_apicv_inhibits = VMX_REQUIRED_APICV_INHIBITS,
index f833aae03d3fda3effa64cc11210339c86522347..a748957755932b3f84ba2a62f937c0aa9c57a96a 100644 (file)
@@ -3058,6 +3058,11 @@ int __init tdx_bringup(void)
                goto success_disable_tdx;
        }
 
+       if (!enable_apicv) {
+               pr_err("APICv is required for TDX\n");
+               goto success_disable_tdx;
+       }
+
        if (!cpu_feature_enabled(X86_FEATURE_OSXSAVE)) {
                pr_err("tdx: OSXSAVE is required for TDX\n");
                goto success_disable_tdx;
index 5c37bc4fb80eaef32c9d07b0c40d5ef452dfdb02..2ed3122f484f08180563ac24baebdc44a206514e 100644 (file)
@@ -5114,6 +5114,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
                                    struct kvm_lapic_state *s)
 {
+       if (vcpu->arch.apic->guest_apic_protected)
+               return -EINVAL;
+
        kvm_x86_call(sync_pir_to_irr)(vcpu);
 
        return kvm_apic_get_state(vcpu, s);
@@ -5124,6 +5127,9 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
 {
        int r;
 
+       if (vcpu->arch.apic->guest_apic_protected)
+               return -EINVAL;
+
        r = kvm_apic_set_state(vcpu, s);
        if (r)
                return r;