On 1/23/2024 7:53 AM, isaku.yamahata@xxxxxxxxx wrote: > From: Isaku Yamahata <isaku.yamahata@xxxxxxxxx> > > Implement hooks of TDP MMU for TDX backend. TLB flush, TLB shootdown, > propagating the change private EPT entry to Secure EPT and freeing Secure > EPT page. TLB flush handles both shared EPT and private EPT. It flushes > shared EPT same as VMX. It also waits for the TDX TLB shootdown. For the > hook to free Secure EPT page, unlinks the Secure EPT page from the Secure > EPT so that the page can be freed to OS. > > Propagate the entry change to Secure EPT. The possible entry changes are > present -> non-present(zapping) and non-present -> present(population). On > population just link the Secure EPT page or the private guest page to the > Secure EPT by TDX SEAMCALL. Because TDP MMU allows concurrent > zapping/population, zapping requires synchronous TLB shoot down with the > frozen EPT entry. It zaps the secure entry, increments TLB counter, sends > IPI to remote vcpus to trigger TLB flush, and then unlinks the private > guest page from the Secure EPT. For simplicity, batched zapping with > exclude lock is handled as concurrent zapping. Although it's inefficient, > it can be optimized in the future. > > For MMIO SPTE, the spte value changes as follows. > initial value (suppress VE bit is set) > -> Guest issues MMIO and triggers EPT violation > -> KVM updates SPTE value to MMIO value (suppress VE bit is cleared) > -> Guest MMIO resumes. It triggers VE exception in guest TD > -> Guest VE handler issues TDG.VP.VMCALL<MMIO> > -> KVM handles MMIO > -> Guest VE handler resumes its execution after MMIO instruction > > Signed-off-by: Isaku Yamahata <isaku.yamahata@xxxxxxxxx> > > --- > v18: > - rename tdx_sept_page_aug() -> tdx_mem_page_aug() > - checkpatch: space => tab > > v15 -> v16: > - Add the handling of TD_ATTR_SEPT_VE_DISABLE case. > > v14 -> v15: > - Implemented tdx_flush_tlb_current() > - Removed unnecessary invept in tdx_flush_tlb(). It was carry over > from the very old code base. > --- > arch/x86/kvm/mmu/spte.c | 3 +- > arch/x86/kvm/vmx/main.c | 71 +++++++- > arch/x86/kvm/vmx/tdx.c | 342 +++++++++++++++++++++++++++++++++++++ > arch/x86/kvm/vmx/tdx.h | 2 +- > arch/x86/kvm/vmx/tdx_ops.h | 6 + > arch/x86/kvm/vmx/x86_ops.h | 6 + > 6 files changed, 424 insertions(+), 6 deletions(-) > > diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c > index 318135daf685..83926a35ea47 100644 > --- a/arch/x86/kvm/mmu/spte.c > +++ b/arch/x86/kvm/mmu/spte.c > @@ -74,7 +74,8 @@ u64 make_mmio_spte(struct kvm_vcpu *vcpu, u64 gfn, unsigned int access) > u64 spte = generation_mmio_spte_mask(gen); > u64 gpa = gfn << PAGE_SHIFT; > > - WARN_ON_ONCE(!vcpu->kvm->arch.shadow_mmio_value); > + WARN_ON_ONCE(!vcpu->kvm->arch.shadow_mmio_value && > + !kvm_gfn_shared_mask(vcpu->kvm)); > > access &= shadow_mmio_access_mask; > spte |= vcpu->kvm->arch.shadow_mmio_value | access; > diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c > index e77c045dca84..569f2f67094c 100644 > --- a/arch/x86/kvm/vmx/main.c > +++ b/arch/x86/kvm/vmx/main.c > @@ -28,6 +28,7 @@ static int vt_max_vcpus(struct kvm *kvm) > > return kvm->max_vcpus; > } > +static int vt_flush_remote_tlbs(struct kvm *kvm); > > static int vt_hardware_enable(void) > { > @@ -74,8 +75,22 @@ static __init int vt_hardware_setup(void) > pr_warn_ratelimited("TDX requires mmio caching. Please enable mmio caching for TDX.\n"); > } > > + /* > + * TDX KVM overrides flush_remote_tlbs method and assumes > + * flush_remote_tlbs_range = NULL that falls back to > + * flush_remote_tlbs. Disable TDX if there are conflicts. > + */ > + if (vt_x86_ops.flush_remote_tlbs || > + vt_x86_ops.flush_remote_tlbs_range) { > + enable_tdx = false; > + pr_warn_ratelimited("TDX requires baremetal. Not Supported on VMM guest.\n"); > + } > + > enable_tdx = enable_tdx && !tdx_hardware_setup(&vt_x86_ops); > > + if (enable_tdx) > + vt_x86_ops.flush_remote_tlbs = vt_flush_remote_tlbs; > + > return 0; > } > I hit some build issues when CONFIG_HYPERV=n: error: ‘struct kvm_x86_ops’ has no member named ‘flush_remote_tlbs’ error: ‘struct kvm_x86_ops’ has no member named ‘flush_remote_tlbs_range’ I think it should be related to the commit https://lore.kernel.org/all/20231018192325.1893896-1-seanjc@xxxxxxxxxx/