Skip to content

Commit faaf05b

Browse files
Ben Gardonbonzini
Ben Gardon
authored andcommitted
kvm: x86/mmu: Support zapping SPTEs in the TDP MMU
Add functions to zap SPTEs to the TDP MMU. These are needed to tear down TDP MMU roots properly and implement other MMU functions which require tearing down mappings. Future patches will add functions to populate the page tables, but as for this patch there will not be any work for these functions to do. 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 9e9eb22 commit faaf05b

File tree

5 files changed

+136
-0
lines changed

5 files changed

+136
-0
lines changed

arch/x86/kvm/mmu/mmu.c

+15
Original file line numberDiff line numberDiff line change
@@ -5371,6 +5371,10 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm)
53715371
kvm_reload_remote_mmus(kvm);
53725372

53735373
kvm_zap_obsolete_pages(kvm);
5374+
5375+
if (kvm->arch.tdp_mmu_enabled)
5376+
kvm_tdp_mmu_zap_all(kvm);
5377+
53745378
spin_unlock(&kvm->mmu_lock);
53755379
}
53765380

@@ -5411,6 +5415,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
54115415
struct kvm_memslots *slots;
54125416
struct kvm_memory_slot *memslot;
54135417
int i;
5418+
bool flush;
54145419

54155420
spin_lock(&kvm->mmu_lock);
54165421
for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
@@ -5430,6 +5435,12 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
54305435
}
54315436
}
54325437

5438+
if (kvm->arch.tdp_mmu_enabled) {
5439+
flush = kvm_tdp_mmu_zap_gfn_range(kvm, gfn_start, gfn_end);
5440+
if (flush)
5441+
kvm_flush_remote_tlbs(kvm);
5442+
}
5443+
54335444
spin_unlock(&kvm->mmu_lock);
54345445
}
54355446

@@ -5596,6 +5607,10 @@ void kvm_mmu_zap_all(struct kvm *kvm)
55965607
}
55975608

55985609
kvm_mmu_commit_zap_page(kvm, &invalid_list);
5610+
5611+
if (kvm->arch.tdp_mmu_enabled)
5612+
kvm_tdp_mmu_zap_all(kvm);
5613+
55995614
spin_unlock(&kvm->mmu_lock);
56005615
}
56015616

arch/x86/kvm/mmu/tdp_iter.c

+5
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,8 @@ void tdp_iter_refresh_walk(struct tdp_iter *iter)
175175
iter->root_level, iter->min_level, goal_gfn);
176176
}
177177

178+
u64 *tdp_iter_root_pt(struct tdp_iter *iter)
179+
{
180+
return iter->pt_path[iter->root_level - 1];
181+
}
182+

arch/x86/kvm/mmu/tdp_iter.h

+1
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,6 @@ void tdp_iter_start(struct tdp_iter *iter, u64 *root_pt, int root_level,
5252
int min_level, gfn_t goal_gfn);
5353
void tdp_iter_next(struct tdp_iter *iter);
5454
void tdp_iter_refresh_walk(struct tdp_iter *iter);
55+
u64 *tdp_iter_root_pt(struct tdp_iter *iter);
5556

5657
#endif /* __KVM_X86_MMU_TDP_ITER_H */

arch/x86/kvm/mmu/tdp_mmu.c

+113
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,22 @@ bool is_tdp_mmu_root(struct kvm *kvm, hpa_t hpa)
4949
return sp->tdp_mmu_page && sp->root_count;
5050
}
5151

52+
static bool zap_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root,
53+
gfn_t start, gfn_t end);
54+
5255
void kvm_tdp_mmu_free_root(struct kvm *kvm, struct kvm_mmu_page *root)
5356
{
57+
gfn_t max_gfn = 1ULL << (boot_cpu_data.x86_phys_bits - PAGE_SHIFT);
58+
5459
lockdep_assert_held(&kvm->mmu_lock);
5560

5661
WARN_ON(root->root_count);
5762
WARN_ON(!root->tdp_mmu_page);
5863

5964
list_del(&root->link);
6065

66+
zap_gfn_range(kvm, root, 0, max_gfn);
67+
6168
free_page((unsigned long)root->spt);
6269
kmem_cache_free(mmu_page_header_cache, root);
6370
}
@@ -135,6 +142,11 @@ hpa_t kvm_tdp_mmu_get_vcpu_root_hpa(struct kvm_vcpu *vcpu)
135142
static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn,
136143
u64 old_spte, u64 new_spte, int level);
137144

145+
static int kvm_mmu_page_as_id(struct kvm_mmu_page *sp)
146+
{
147+
return sp->role.smm ? 1 : 0;
148+
}
149+
138150
/**
139151
* handle_changed_spte - handle bookkeeping associated with an SPTE change
140152
* @kvm: kvm instance
@@ -242,3 +254,104 @@ static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn,
242254
{
243255
__handle_changed_spte(kvm, as_id, gfn, old_spte, new_spte, level);
244256
}
257+
258+
static inline void tdp_mmu_set_spte(struct kvm *kvm, struct tdp_iter *iter,
259+
u64 new_spte)
260+
{
261+
u64 *root_pt = tdp_iter_root_pt(iter);
262+
struct kvm_mmu_page *root = sptep_to_sp(root_pt);
263+
int as_id = kvm_mmu_page_as_id(root);
264+
265+
*iter->sptep = new_spte;
266+
267+
handle_changed_spte(kvm, as_id, iter->gfn, iter->old_spte, new_spte,
268+
iter->level);
269+
}
270+
271+
#define tdp_root_for_each_pte(_iter, _root, _start, _end) \
272+
for_each_tdp_pte(_iter, _root->spt, _root->role.level, _start, _end)
273+
274+
/*
275+
* Flush the TLB if the process should drop kvm->mmu_lock.
276+
* Return whether the caller still needs to flush the tlb.
277+
*/
278+
static bool tdp_mmu_iter_flush_cond_resched(struct kvm *kvm, struct tdp_iter *iter)
279+
{
280+
if (need_resched() || spin_needbreak(&kvm->mmu_lock)) {
281+
kvm_flush_remote_tlbs(kvm);
282+
cond_resched_lock(&kvm->mmu_lock);
283+
tdp_iter_refresh_walk(iter);
284+
return false;
285+
} else {
286+
return true;
287+
}
288+
}
289+
290+
/*
291+
* Tears down the mappings for the range of gfns, [start, end), and frees the
292+
* non-root pages mapping GFNs strictly within that range. Returns true if
293+
* SPTEs have been cleared and a TLB flush is needed before releasing the
294+
* MMU lock.
295+
*/
296+
static bool zap_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root,
297+
gfn_t start, gfn_t end)
298+
{
299+
struct tdp_iter iter;
300+
bool flush_needed = false;
301+
302+
tdp_root_for_each_pte(iter, root, start, end) {
303+
if (!is_shadow_present_pte(iter.old_spte))
304+
continue;
305+
306+
/*
307+
* If this is a non-last-level SPTE that covers a larger range
308+
* than should be zapped, continue, and zap the mappings at a
309+
* lower level.
310+
*/
311+
if ((iter.gfn < start ||
312+
iter.gfn + KVM_PAGES_PER_HPAGE(iter.level) > end) &&
313+
!is_last_spte(iter.old_spte, iter.level))
314+
continue;
315+
316+
tdp_mmu_set_spte(kvm, &iter, 0);
317+
318+
flush_needed = tdp_mmu_iter_flush_cond_resched(kvm, &iter);
319+
}
320+
return flush_needed;
321+
}
322+
323+
/*
324+
* Tears down the mappings for the range of gfns, [start, end), and frees the
325+
* non-root pages mapping GFNs strictly within that range. Returns true if
326+
* SPTEs have been cleared and a TLB flush is needed before releasing the
327+
* MMU lock.
328+
*/
329+
bool kvm_tdp_mmu_zap_gfn_range(struct kvm *kvm, gfn_t start, gfn_t end)
330+
{
331+
struct kvm_mmu_page *root;
332+
bool flush = false;
333+
334+
for_each_tdp_mmu_root(kvm, root) {
335+
/*
336+
* Take a reference on the root so that it cannot be freed if
337+
* this thread releases the MMU lock and yields in this loop.
338+
*/
339+
kvm_mmu_get_root(kvm, root);
340+
341+
flush |= zap_gfn_range(kvm, root, start, end);
342+
343+
kvm_mmu_put_root(kvm, root);
344+
}
345+
346+
return flush;
347+
}
348+
349+
void kvm_tdp_mmu_zap_all(struct kvm *kvm)
350+
{
351+
gfn_t max_gfn = 1ULL << (boot_cpu_data.x86_phys_bits - PAGE_SHIFT);
352+
bool flush;
353+
354+
flush = kvm_tdp_mmu_zap_gfn_range(kvm, 0, max_gfn);
355+
if (flush)
356+
kvm_flush_remote_tlbs(kvm);
357+
}

arch/x86/kvm/mmu/tdp_mmu.h

+2
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ bool is_tdp_mmu_root(struct kvm *kvm, hpa_t root);
1212
hpa_t kvm_tdp_mmu_get_vcpu_root_hpa(struct kvm_vcpu *vcpu);
1313
void kvm_tdp_mmu_free_root(struct kvm *kvm, struct kvm_mmu_page *root);
1414

15+
bool kvm_tdp_mmu_zap_gfn_range(struct kvm *kvm, gfn_t start, gfn_t end);
16+
void kvm_tdp_mmu_zap_all(struct kvm *kvm);
1517
#endif /* __KVM_X86_MMU_TDP_MMU_H */

0 commit comments

Comments
 (0)