Skip to content

Commit cae7ed3

Browse files
Sean Christophersonbonzini
Sean Christopherson
authored andcommitted
KVM: x86: Refactor the MMIO SPTE generation handling
The code to propagate the memslots generation number into MMIO sptes is a bit convoluted. The "what" is relatively straightfoward, e.g. the comment explaining which bits go where is quite readable, but the "how" requires a lot of staring to understand what is happening. For example, 'MMIO_GEN_LOW_SHIFT' is actually used to calculate the high bits of the spte, while 'MMIO_SPTE_GEN_LOW_SHIFT' is used to calculate the low bits. Refactor the code to: - use #defines whose values align with the bits defined in the comment - use consistent code for both the high and low mask - explicitly highlight the handling of bit 0 (update in-progress flag) - explicitly call out that the defines are for MMIO sptes (to avoid confusion with the per-vCPU MMIO cache, which uses the full memslots generation) In addition to making the code a little less magical, this paves the way for moving the update in-progress flag to bit 63 without having to simultaneously rewrite all of the MMIO spte code. Signed-off-by: Sean Christopherson <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 5192f9b commit cae7ed3

File tree

1 file changed

+43
-33
lines changed

1 file changed

+43
-33
lines changed

arch/x86/kvm/mmu.c

+43-33
Original file line numberDiff line numberDiff line change
@@ -332,30 +332,41 @@ static inline bool is_access_track_spte(u64 spte)
332332
}
333333

334334
/*
335-
* the low bit of the generation number is always presumed to be zero.
336-
* This disables mmio caching during memslot updates. The concept is
337-
* similar to a seqcount but instead of retrying the access we just punt
338-
* and ignore the cache.
335+
* Due to limited space in PTEs, the MMIO generation is a 19 bit subset of
336+
* the memslots generation and is derived as follows:
339337
*
340-
* spte bits 3-11 are used as bits 1-9 of the generation number,
341-
* the bits 52-61 are used as bits 10-19 of the generation number.
338+
* Bits 1-9 of the memslot generation are propagated to spte bits 3-11
339+
* Bits 10-19 of the memslot generation are propagated to spte bits 52-61
340+
*
341+
* The MMIO generation starts at bit 1 of the memslots generation in order to
342+
* skip over bit 0, the KVM_MEMSLOT_GEN_UPDATE_IN_PROGRESS flag. Including
343+
* the flag would require stealing a bit from the "real" generation number and
344+
* thus effectively halve the maximum number of MMIO generations that can be
345+
* handled before encountering a wrap (which requires a full MMU zap). The
346+
* flag is instead explicitly queried when checking for MMIO spte cache hits.
342347
*/
343-
#define MMIO_SPTE_GEN_LOW_SHIFT 2
344-
#define MMIO_SPTE_GEN_HIGH_SHIFT 52
345-
346-
#define MMIO_GEN_SHIFT 20
347-
#define MMIO_GEN_LOW_SHIFT 10
348-
#define MMIO_GEN_LOW_MASK ((1 << MMIO_GEN_LOW_SHIFT) - 2)
349-
#define MMIO_GEN_MASK ((1 << MMIO_GEN_SHIFT) - 1)
350-
348+
#define MMIO_SPTE_GEN_MASK GENMASK_ULL(19, 1)
349+
#define MMIO_SPTE_GEN_SHIFT 1
350+
351+
#define MMIO_SPTE_GEN_LOW_START 3
352+
#define MMIO_SPTE_GEN_LOW_END 11
353+
#define MMIO_SPTE_GEN_LOW_MASK GENMASK_ULL(MMIO_SPTE_GEN_LOW_END, \
354+
MMIO_SPTE_GEN_LOW_START)
355+
356+
#define MMIO_SPTE_GEN_HIGH_START 52
357+
#define MMIO_SPTE_GEN_HIGH_END 61
358+
#define MMIO_SPTE_GEN_HIGH_MASK GENMASK_ULL(MMIO_SPTE_GEN_HIGH_END, \
359+
MMIO_SPTE_GEN_HIGH_START)
351360
static u64 generation_mmio_spte_mask(u64 gen)
352361
{
353362
u64 mask;
354363

355-
WARN_ON(gen & ~MMIO_GEN_MASK);
364+
WARN_ON(gen & ~MMIO_SPTE_GEN_MASK);
356365

357-
mask = (gen & MMIO_GEN_LOW_MASK) << MMIO_SPTE_GEN_LOW_SHIFT;
358-
mask |= (gen >> MMIO_GEN_LOW_SHIFT) << MMIO_SPTE_GEN_HIGH_SHIFT;
366+
gen >>= MMIO_SPTE_GEN_SHIFT;
367+
368+
mask = (gen << MMIO_SPTE_GEN_LOW_START) & MMIO_SPTE_GEN_LOW_MASK;
369+
mask |= (gen << MMIO_SPTE_GEN_HIGH_START) & MMIO_SPTE_GEN_HIGH_MASK;
359370
return mask;
360371
}
361372

@@ -365,20 +376,15 @@ static u64 get_mmio_spte_generation(u64 spte)
365376

366377
spte &= ~shadow_mmio_mask;
367378

368-
gen = (spte >> MMIO_SPTE_GEN_LOW_SHIFT) & MMIO_GEN_LOW_MASK;
369-
gen |= (spte >> MMIO_SPTE_GEN_HIGH_SHIFT) << MMIO_GEN_LOW_SHIFT;
370-
return gen;
371-
}
372-
373-
static u64 kvm_current_mmio_generation(struct kvm_vcpu *vcpu)
374-
{
375-
return kvm_vcpu_memslots(vcpu)->generation & MMIO_GEN_MASK;
379+
gen = (spte & MMIO_SPTE_GEN_LOW_MASK) >> MMIO_SPTE_GEN_LOW_START;
380+
gen |= (spte & MMIO_SPTE_GEN_HIGH_MASK) >> MMIO_SPTE_GEN_HIGH_START;
381+
return gen << MMIO_SPTE_GEN_SHIFT;
376382
}
377383

378384
static void mark_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 gfn,
379385
unsigned access)
380386
{
381-
u64 gen = kvm_current_mmio_generation(vcpu);
387+
u64 gen = kvm_vcpu_memslots(vcpu)->generation & MMIO_SPTE_GEN_MASK;
382388
u64 mask = generation_mmio_spte_mask(gen);
383389
u64 gpa = gfn << PAGE_SHIFT;
384390

@@ -409,7 +415,7 @@ static gfn_t get_mmio_spte_gfn(u64 spte)
409415

410416
static unsigned get_mmio_spte_access(u64 spte)
411417
{
412-
u64 mask = generation_mmio_spte_mask(MMIO_GEN_MASK) | shadow_mmio_mask;
418+
u64 mask = generation_mmio_spte_mask(MMIO_SPTE_GEN_MASK) | shadow_mmio_mask;
413419
return (spte & ~mask) & ~PAGE_MASK;
414420
}
415421

@@ -426,9 +432,13 @@ static bool set_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn,
426432

427433
static bool check_mmio_spte(struct kvm_vcpu *vcpu, u64 spte)
428434
{
429-
u64 kvm_gen, spte_gen;
435+
u64 kvm_gen, spte_gen, gen;
436+
437+
gen = kvm_vcpu_memslots(vcpu)->generation;
438+
if (unlikely(gen & KVM_MEMSLOT_GEN_UPDATE_IN_PROGRESS))
439+
return false;
430440

431-
kvm_gen = kvm_current_mmio_generation(vcpu);
441+
kvm_gen = gen & MMIO_SPTE_GEN_MASK;
432442
spte_gen = get_mmio_spte_generation(spte);
433443

434444
trace_check_mmio_spte(spte, kvm_gen, spte_gen);
@@ -5895,13 +5905,13 @@ static bool kvm_has_zapped_obsolete_pages(struct kvm *kvm)
58955905

58965906
void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen)
58975907
{
5898-
gen &= MMIO_GEN_MASK;
5908+
gen &= MMIO_SPTE_GEN_MASK;
58995909

59005910
/*
5901-
* Shift to eliminate the "update in-progress" flag, which isn't
5902-
* included in the spte's generation number.
5911+
* Shift to adjust for the "update in-progress" flag, which isn't
5912+
* included in the MMIO generation number.
59035913
*/
5904-
gen >>= 1;
5914+
gen >>= MMIO_SPTE_GEN_SHIFT;
59055915

59065916
/*
59075917
* Generation numbers are incremented in multiples of the number of

0 commit comments

Comments
 (0)