@@ -7,6 +7,7 @@ enum kvm_page_track_mode {
KVM_PAGE_TRACK_PREWRITE,
KVM_PAGE_TRACK_WRITE,
KVM_PAGE_TRACK_PREEXEC,
+ KVM_PAGE_TRACK_SVE,
KVM_PAGE_TRACK_MAX,
};
@@ -234,5 +234,7 @@ int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu, gpa_t l2_gpa);
int kvm_mmu_post_init_vm(struct kvm *kvm);
void kvm_mmu_pre_destroy_vm(struct kvm *kvm);
+bool kvm_mmu_set_ept_page_sve(struct kvm *kvm, struct kvm_memory_slot *slot,
+ gfn_t gfn, u16 index, bool suppress);
#endif
@@ -1890,6 +1890,41 @@ bool kvm_mmu_slot_gfn_exec_protect(struct kvm *kvm,
return exec_protected;
}
+static bool spte_suppress_ve(u64 *sptep, bool suppress)
+{
+ u64 spte = *sptep;
+
+ if (suppress)
+ spte |= VMX_EPT_SUPPRESS_VE_BIT;
+ else
+ spte &= ~VMX_EPT_SUPPRESS_VE_BIT;
+
+ return mmu_spte_update(sptep, spte);
+}
+
+bool kvm_mmu_set_ept_page_sve(struct kvm *kvm, struct kvm_memory_slot *slot,
+ gfn_t gfn, u16 index, bool suppress)
+{
+ struct kvm_rmap_head *rmap_head;
+ struct rmap_iterator iter;
+ struct kvm_mmu_page *sp;
+ bool flush = false;
+ u64 *sptep;
+ int i;
+
+ for (i = PG_LEVEL_4K; i <= KVM_MAX_HUGEPAGE_LEVEL; i++) {
+ rmap_head = __gfn_to_rmap(gfn, i, slot);
+ for_each_rmap_spte(rmap_head, &iter, sptep) {
+ sp = page_header(__pa(sptep));
+ if (index == 0 || (index > 0 && index == sp->view))
+ flush |= spte_suppress_ve(sptep, suppress);
+ }
+ }
+
+ return flush;
+}
+EXPORT_SYMBOL_GPL(kvm_mmu_set_ept_page_sve);
+
static bool rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
{
struct kvm_memory_slot *slot;
@@ -3171,6 +3206,9 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
spte |= (u64)pfn << PAGE_SHIFT;
+ if (kvm_page_track_is_active(vcpu, gfn, KVM_PAGE_TRACK_SVE))
+ spte &= ~VMX_EPT_SUPPRESS_VE_BIT;
+
if (pte_access & ACC_WRITE_MASK) {
spte |= PT_WRITABLE_MASK | SPTE_MMU_WRITEABLE;
@@ -125,6 +125,9 @@ void kvm_slot_page_track_add_page(struct kvm *kvm,
} else if (mode == KVM_PAGE_TRACK_PREEXEC) {
if (kvm_mmu_slot_gfn_exec_protect(kvm, slot, gfn, view))
kvm_flush_remote_tlbs(kvm);
+ } else if (mode == KVM_PAGE_TRACK_SVE) {
+ if (kvm_mmu_set_ept_page_sve(kvm, slot, gfn, view, false))
+ kvm_flush_remote_tlbs(kvm);
}
}
EXPORT_SYMBOL_GPL(kvm_slot_page_track_add_page);
@@ -151,6 +154,10 @@ void kvm_slot_page_track_remove_page(struct kvm *kvm,
update_gfn_track(slot, gfn, mode, -1, view);
+ if (mode == KVM_PAGE_TRACK_SVE)
+ if (kvm_mmu_set_ept_page_sve(kvm, slot, gfn, view, true))
+ kvm_flush_remote_tlbs(kvm);
+
/*
* allow large page mapping for the tracked page
* after the tracker is gone.