mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-04 02:02:28 +09:00
KVM: x86/mmu: Use a dedicated bit to track shadow/MMU-present SPTEs
Introduce MMU_PRESENT to explicitly track which SPTEs are "present" from the MMU's perspective. Checking for shadow-present SPTEs is a very common operation for the MMU, particularly in hot paths such as page faults. With the addition of "removed" SPTEs for the TDP MMU, identifying shadow-present SPTEs is quite costly especially since it requires checking multiple 64-bit values. On 64-bit KVM, this reduces the footprint of kvm.ko's .text by ~2k bytes. On 32-bit KVM, this increases the footprint by ~200 bytes, but only because gcc now inlines several more MMU helpers, e.g. drop_parent_pte(). We now need to drop bit 11, used for the MMU_PRESENT flag, from the set of bits used to store the generation number in MMIO SPTEs. Otherwise MMIO SPTEs with bit 11 set would get false positives for is_shadow_present_spte() and lead to a variety of fireworks, from oopses to likely hangs of the host kernel. Signed-off-by: Sean Christopherson <seanjc@google.com> Message-Id: <20210225204749.1512652-21-seanjc@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
committed by
Paolo Bonzini
parent
613a3f3797
commit
edea7c4fc2
@@ -94,7 +94,7 @@ int make_spte(struct kvm_vcpu *vcpu, unsigned int pte_access, int level,
|
||||
bool can_unsync, bool host_writable, bool ad_disabled,
|
||||
u64 *new_spte)
|
||||
{
|
||||
u64 spte = 0;
|
||||
u64 spte = SPTE_MMU_PRESENT_MASK;
|
||||
int ret = 0;
|
||||
|
||||
if (ad_disabled)
|
||||
@@ -183,10 +183,10 @@ out:
|
||||
|
||||
u64 make_nonleaf_spte(u64 *child_pt, bool ad_disabled)
|
||||
{
|
||||
u64 spte;
|
||||
u64 spte = SPTE_MMU_PRESENT_MASK;
|
||||
|
||||
spte = __pa(child_pt) | shadow_present_mask | PT_WRITABLE_MASK |
|
||||
shadow_user_mask | shadow_x_mask | shadow_me_mask;
|
||||
spte |= __pa(child_pt) | shadow_present_mask | PT_WRITABLE_MASK |
|
||||
shadow_user_mask | shadow_x_mask | shadow_me_mask;
|
||||
|
||||
if (ad_disabled)
|
||||
spte |= SPTE_TDP_AD_DISABLED_MASK;
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
|
||||
#include "mmu_internal.h"
|
||||
|
||||
/*
|
||||
* A MMU present SPTE is backed by actual memory and may or may not be present
|
||||
* in hardware. E.g. MMIO SPTEs are not considered present. Use bit 11, as it
|
||||
* is ignored by all flavors of SPTEs and checking a low bit often generates
|
||||
* better code than for a high bit, e.g. 56+. MMU present checks are pervasive
|
||||
* enough that the improved code generation is noticeable in KVM's footprint.
|
||||
*/
|
||||
#define SPTE_MMU_PRESENT_MASK BIT_ULL(11)
|
||||
|
||||
/*
|
||||
* TDP SPTES (more specifically, EPT SPTEs) may not have A/D bits, and may also
|
||||
* be restricted to using write-protection (for L2 when CPU dirty logging, i.e.
|
||||
@@ -92,11 +101,11 @@ static_assert(!(EPT_SPTE_MMU_WRITABLE & SHADOW_ACC_TRACK_SAVED_MASK));
|
||||
#undef SHADOW_ACC_TRACK_SAVED_MASK
|
||||
|
||||
/*
|
||||
* Due to limited space in PTEs, the MMIO generation is a 20 bit subset of
|
||||
* Due to limited space in PTEs, the MMIO generation is a 19 bit subset of
|
||||
* the memslots generation and is derived as follows:
|
||||
*
|
||||
* Bits 0-8 of the MMIO generation are propagated to spte bits 3-11
|
||||
* Bits 9-19 of the MMIO generation are propagated to spte bits 52-62
|
||||
* Bits 0-7 of the MMIO generation are propagated to spte bits 3-10
|
||||
* Bits 8-18 of the MMIO generation are propagated to spte bits 52-62
|
||||
*
|
||||
* The KVM_MEMSLOT_GEN_UPDATE_IN_PROGRESS flag is intentionally not included in
|
||||
* the MMIO generation number, as doing so would require stealing a bit from
|
||||
@@ -107,7 +116,7 @@ static_assert(!(EPT_SPTE_MMU_WRITABLE & SHADOW_ACC_TRACK_SAVED_MASK));
|
||||
*/
|
||||
|
||||
#define MMIO_SPTE_GEN_LOW_START 3
|
||||
#define MMIO_SPTE_GEN_LOW_END 11
|
||||
#define MMIO_SPTE_GEN_LOW_END 10
|
||||
|
||||
#define MMIO_SPTE_GEN_HIGH_START 52
|
||||
#define MMIO_SPTE_GEN_HIGH_END 62
|
||||
@@ -116,12 +125,14 @@ static_assert(!(EPT_SPTE_MMU_WRITABLE & SHADOW_ACC_TRACK_SAVED_MASK));
|
||||
MMIO_SPTE_GEN_LOW_START)
|
||||
#define MMIO_SPTE_GEN_HIGH_MASK GENMASK_ULL(MMIO_SPTE_GEN_HIGH_END, \
|
||||
MMIO_SPTE_GEN_HIGH_START)
|
||||
static_assert(!(SPTE_MMU_PRESENT_MASK &
|
||||
(MMIO_SPTE_GEN_LOW_MASK | MMIO_SPTE_GEN_HIGH_MASK)));
|
||||
|
||||
#define MMIO_SPTE_GEN_LOW_BITS (MMIO_SPTE_GEN_LOW_END - MMIO_SPTE_GEN_LOW_START + 1)
|
||||
#define MMIO_SPTE_GEN_HIGH_BITS (MMIO_SPTE_GEN_HIGH_END - MMIO_SPTE_GEN_HIGH_START + 1)
|
||||
|
||||
/* remember to adjust the comment above as well if you change these */
|
||||
static_assert(MMIO_SPTE_GEN_LOW_BITS == 9 && MMIO_SPTE_GEN_HIGH_BITS == 11);
|
||||
static_assert(MMIO_SPTE_GEN_LOW_BITS == 8 && MMIO_SPTE_GEN_HIGH_BITS == 11);
|
||||
|
||||
#define MMIO_SPTE_GEN_LOW_SHIFT (MMIO_SPTE_GEN_LOW_START - 0)
|
||||
#define MMIO_SPTE_GEN_HIGH_SHIFT (MMIO_SPTE_GEN_HIGH_START - MMIO_SPTE_GEN_LOW_BITS)
|
||||
@@ -241,7 +252,7 @@ static inline bool is_access_track_spte(u64 spte)
|
||||
|
||||
static inline bool is_shadow_present_pte(u64 pte)
|
||||
{
|
||||
return (pte != 0) && !is_mmio_spte(pte) && !is_removed_spte(pte);
|
||||
return !!(pte & SPTE_MMU_PRESENT_MASK);
|
||||
}
|
||||
|
||||
static inline bool is_large_pte(u64 pte)
|
||||
|
||||
Reference in New Issue
Block a user