Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'kvm-x86 mmio'

Merge the MMIO stale data branch with the device posted IRQs branch to
provide a common base for removing KVM's tracking of "assigned" devices.

Link: https://lore.kernel.org/all/20250523011756.3243624-1-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>

+67 -8
+1
arch/x86/include/asm/kvm_host.h
··· 1459 1459 bool x2apic_format; 1460 1460 bool x2apic_broadcast_quirk_disabled; 1461 1461 1462 + bool has_mapped_host_mmio; 1462 1463 bool guest_can_read_msr_platform_info; 1463 1464 bool exception_payload_enabled; 1464 1465
+3
arch/x86/kvm/mmu/mmu_internal.h
··· 103 103 int root_count; 104 104 refcount_t tdp_mmu_root_count; 105 105 }; 106 + 107 + bool has_mapped_host_mmio; 108 + 106 109 union { 107 110 /* These two members aren't used for TDP MMU */ 108 111 struct {
+40 -3
arch/x86/kvm/mmu/spte.c
··· 104 104 return spte; 105 105 } 106 106 107 - static bool kvm_is_mmio_pfn(kvm_pfn_t pfn) 107 + static bool __kvm_is_mmio_pfn(kvm_pfn_t pfn) 108 108 { 109 109 if (pfn_valid(pfn)) 110 110 return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn)) && ··· 123 123 return !e820__mapped_raw_any(pfn_to_hpa(pfn), 124 124 pfn_to_hpa(pfn + 1) - 1, 125 125 E820_TYPE_RAM); 126 + } 127 + 128 + static bool kvm_is_mmio_pfn(kvm_pfn_t pfn, int *is_host_mmio) 129 + { 130 + /* 131 + * Determining if a PFN is host MMIO is relative expensive. Cache the 132 + * result locally (in the sole caller) to avoid doing the full query 133 + * multiple times when creating a single SPTE. 134 + */ 135 + if (*is_host_mmio < 0) 136 + *is_host_mmio = __kvm_is_mmio_pfn(pfn); 137 + 138 + return *is_host_mmio; 139 + } 140 + 141 + static void kvm_track_host_mmio_mapping(struct kvm_vcpu *vcpu) 142 + { 143 + struct kvm_mmu_page *root = root_to_sp(vcpu->arch.mmu->root.hpa); 144 + 145 + if (root) 146 + WRITE_ONCE(root->has_mapped_host_mmio, true); 147 + else 148 + WRITE_ONCE(vcpu->kvm->arch.has_mapped_host_mmio, true); 149 + 150 + /* 151 + * Force vCPUs to exit and flush CPU buffers if the vCPU is using the 152 + * affected root(s). 153 + */ 154 + kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_OUTSIDE_GUEST_MODE); 126 155 } 127 156 128 157 /* ··· 191 162 { 192 163 int level = sp->role.level; 193 164 u64 spte = SPTE_MMU_PRESENT_MASK; 165 + int is_host_mmio = -1; 194 166 bool wrprot = false; 195 167 196 168 /* ··· 239 209 if (level > PG_LEVEL_4K) 240 210 spte |= PT_PAGE_SIZE_MASK; 241 211 242 - spte |= kvm_x86_call(get_mt_mask)(vcpu, gfn, kvm_is_mmio_pfn(pfn)); 212 + if (kvm_x86_ops.get_mt_mask) 213 + spte |= kvm_x86_call(get_mt_mask)(vcpu, gfn, 214 + kvm_is_mmio_pfn(pfn, &is_host_mmio)); 243 215 if (host_writable) 244 216 spte |= shadow_host_writable_mask; 245 217 else 246 218 pte_access &= ~ACC_WRITE_MASK; 247 219 248 - if (shadow_me_value && !kvm_is_mmio_pfn(pfn)) 220 + if (shadow_me_value && !kvm_is_mmio_pfn(pfn, &is_host_mmio)) 249 221 spte |= shadow_me_value; 250 222 251 223 spte |= (u64)pfn << PAGE_SHIFT; ··· 291 259 WARN_ON_ONCE(level > PG_LEVEL_4K); 292 260 mark_page_dirty_in_slot(vcpu->kvm, slot, gfn); 293 261 } 262 + 263 + if (static_branch_unlikely(&cpu_buf_vm_clear) && 264 + !kvm_vcpu_can_access_host_mmio(vcpu) && 265 + kvm_is_mmio_pfn(pfn, &is_host_mmio)) 266 + kvm_track_host_mmio_mapping(vcpu); 294 267 295 268 *new_spte = spte; 296 269 return wrprot;
+10
arch/x86/kvm/mmu/spte.h
··· 280 280 return is_mirror_sp(sptep_to_sp(rcu_dereference(sptep))); 281 281 } 282 282 283 + static inline bool kvm_vcpu_can_access_host_mmio(struct kvm_vcpu *vcpu) 284 + { 285 + struct kvm_mmu_page *root = root_to_sp(vcpu->arch.mmu->root.hpa); 286 + 287 + if (root) 288 + return READ_ONCE(root->has_mapped_host_mmio); 289 + 290 + return READ_ONCE(vcpu->kvm->arch.has_mapped_host_mmio); 291 + } 292 + 283 293 static inline bool is_mmio_spte(struct kvm *kvm, u64 spte) 284 294 { 285 295 return (spte & shadow_mmio_mask) == kvm->arch.shadow_mmio_value &&
+6 -4
arch/x86/kvm/vmx/run_flags.h
··· 2 2 #ifndef __KVM_X86_VMX_RUN_FLAGS_H 3 3 #define __KVM_X86_VMX_RUN_FLAGS_H 4 4 5 - #define VMX_RUN_VMRESUME_SHIFT 0 6 - #define VMX_RUN_SAVE_SPEC_CTRL_SHIFT 1 5 + #define VMX_RUN_VMRESUME_SHIFT 0 6 + #define VMX_RUN_SAVE_SPEC_CTRL_SHIFT 1 7 + #define VMX_RUN_CLEAR_CPU_BUFFERS_FOR_MMIO_SHIFT 2 7 8 8 - #define VMX_RUN_VMRESUME BIT(VMX_RUN_VMRESUME_SHIFT) 9 - #define VMX_RUN_SAVE_SPEC_CTRL BIT(VMX_RUN_SAVE_SPEC_CTRL_SHIFT) 9 + #define VMX_RUN_VMRESUME BIT(VMX_RUN_VMRESUME_SHIFT) 10 + #define VMX_RUN_SAVE_SPEC_CTRL BIT(VMX_RUN_SAVE_SPEC_CTRL_SHIFT) 11 + #define VMX_RUN_CLEAR_CPU_BUFFERS_FOR_MMIO BIT(VMX_RUN_CLEAR_CPU_BUFFERS_FOR_MMIO_SHIFT) 10 12 11 13 #endif /* __KVM_X86_VMX_RUN_FLAGS_H */
+7 -1
arch/x86/kvm/vmx/vmx.c
··· 75 75 #include "vmx_onhyperv.h" 76 76 #include "posted_intr.h" 77 77 78 + #include "mmu/spte.h" 79 + 78 80 MODULE_AUTHOR("Qumranet"); 79 81 MODULE_DESCRIPTION("KVM support for VMX (Intel VT-x) extensions"); 80 82 MODULE_LICENSE("GPL"); ··· 962 960 */ 963 961 if (!msr_write_intercepted(vmx, MSR_IA32_SPEC_CTRL)) 964 962 flags |= VMX_RUN_SAVE_SPEC_CTRL; 963 + 964 + if (static_branch_unlikely(&cpu_buf_vm_clear) && 965 + kvm_vcpu_can_access_host_mmio(&vmx->vcpu)) 966 + flags |= VMX_RUN_CLEAR_CPU_BUFFERS_FOR_MMIO; 965 967 966 968 return flags; 967 969 } ··· 7294 7288 if (static_branch_unlikely(&vmx_l1d_should_flush)) 7295 7289 vmx_l1d_flush(vcpu); 7296 7290 else if (static_branch_unlikely(&cpu_buf_vm_clear) && 7297 - kvm_arch_has_assigned_device(vcpu->kvm)) 7291 + (flags & VMX_RUN_CLEAR_CPU_BUFFERS_FOR_MMIO)) 7298 7292 mds_clear_cpu_buffers(); 7299 7293 7300 7294 vmx_disable_fb_clear(vmx);