Skip to content

Commit 1d8dd6b

Browse files
Ben Gardonbonzini
authored andcommitted
kvm: x86/mmu: Support changed pte notifier in tdp MMU
In order to interoperate correctly with the rest of KVM and other Linux subsystems, the TDP MMU must correctly handle various MMU notifiers. Add a hook and handle the change_pte MMU notifier. Tested by running kvm-unit-tests and KVM selftests on an Intel Haswell machine. This series introduced no new failures. This series can be viewed in Gerrit at: https://linux-review.googlesource.com/c/virt/kvm/kvm/+/2538 Signed-off-by: Ben Gardon <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent f8e1449 commit 1d8dd6b

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-1
lines changed

arch/x86/kvm/mmu/mmu.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1509,7 +1509,14 @@ int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
15091509

15101510
int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
15111511
{
1512-
return kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp);
1512+
int r;
1513+
1514+
r = kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp);
1515+
1516+
if (kvm->arch.tdp_mmu_enabled)
1517+
r |= kvm_tdp_mmu_set_spte_hva(kvm, hva, &pte);
1518+
1519+
return r;
15131520
}
15141521

15151522
static int kvm_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,

arch/x86/kvm/mmu/tdp_mmu.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,3 +671,59 @@ int kvm_tdp_mmu_test_age_hva(struct kvm *kvm, unsigned long hva)
671671
return kvm_tdp_mmu_handle_hva_range(kvm, hva, hva + 1, 0,
672672
test_age_gfn);
673673
}
674+
675+
/*
676+
* Handle the changed_pte MMU notifier for the TDP MMU.
677+
* data is a pointer to the new pte_t mapping the HVA specified by the MMU
678+
* notifier.
679+
* Returns non-zero if a flush is needed before releasing the MMU lock.
680+
*/
681+
static int set_tdp_spte(struct kvm *kvm, struct kvm_memory_slot *slot,
682+
struct kvm_mmu_page *root, gfn_t gfn, gfn_t unused,
683+
unsigned long data)
684+
{
685+
struct tdp_iter iter;
686+
pte_t *ptep = (pte_t *)data;
687+
kvm_pfn_t new_pfn;
688+
u64 new_spte;
689+
int need_flush = 0;
690+
691+
WARN_ON(pte_huge(*ptep));
692+
693+
new_pfn = pte_pfn(*ptep);
694+
695+
tdp_root_for_each_pte(iter, root, gfn, gfn + 1) {
696+
if (iter.level != PG_LEVEL_4K)
697+
continue;
698+
699+
if (!is_shadow_present_pte(iter.old_spte))
700+
break;
701+
702+
tdp_mmu_set_spte(kvm, &iter, 0);
703+
704+
kvm_flush_remote_tlbs_with_address(kvm, iter.gfn, 1);
705+
706+
if (!pte_write(*ptep)) {
707+
new_spte = kvm_mmu_changed_pte_notifier_make_spte(
708+
iter.old_spte, new_pfn);
709+
710+
tdp_mmu_set_spte(kvm, &iter, new_spte);
711+
}
712+
713+
need_flush = 1;
714+
}
715+
716+
if (need_flush)
717+
kvm_flush_remote_tlbs_with_address(kvm, gfn, 1);
718+
719+
return 0;
720+
}
721+
722+
int kvm_tdp_mmu_set_spte_hva(struct kvm *kvm, unsigned long address,
723+
pte_t *host_ptep)
724+
{
725+
return kvm_tdp_mmu_handle_hva_range(kvm, address, address + 1,
726+
(unsigned long)host_ptep,
727+
set_tdp_spte);
728+
}
729+

arch/x86/kvm/mmu/tdp_mmu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@ int kvm_tdp_mmu_zap_hva_range(struct kvm *kvm, unsigned long start,
2525
int kvm_tdp_mmu_age_hva_range(struct kvm *kvm, unsigned long start,
2626
unsigned long end);
2727
int kvm_tdp_mmu_test_age_hva(struct kvm *kvm, unsigned long hva);
28+
29+
int kvm_tdp_mmu_set_spte_hva(struct kvm *kvm, unsigned long address,
30+
pte_t *host_ptep);
2831
#endif /* __KVM_X86_MMU_TDP_MMU_H */

0 commit comments

Comments
 (0)