Re: [PATCH 04/28] KVM: x86/mmu: shuffle high bits of SPTEs in preparation for MBEC

From: mlevitsk

Date: Tue Jun 02 2026 - 10:30:36 EST


On Tue, 2026-05-05 at 21:52 +0200, Paolo Bonzini wrote:
> Access tracking will need to save bit 10 when MBEC is enabled.
> Right now it is simply shifting the R and X bits into bits 54 and 56,
> but bit 10 would not fit with the same scheme.  Reorganize the
> high bits so that access tracking will use bits 52, 54 and 62.
> As a side effect, the free bits are compacted slightly, with
> 56-59 still unused.

First of all thanks for documenting this black magic!

Minor nitpick:

There is a slight inconsistency between the commit message, which says that bit 62 
will be used, and the comment below, which states that 
bit 62 is unused  (although in following patches this comment is updated).

Also, although I'm not entirely sure this is worth mentioning that bit 62
just happens to be 10 bits away from bit 52,
so that we can still just copy the permission bits from EPT's SPTE as a single block,
even though between bits 52,53,54 and bit 63, there are other bits which
KVM uses for other purposes.

>
> Tested-by: David Riley <d.riley@xxxxxxxxxxx>
> Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
> ---
>  arch/x86/kvm/mmu/spte.h | 20 +++++++++++++++-----
>  1 file changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h
> index 4283cea3e66c..317b9cd1537c 100644
> --- a/arch/x86/kvm/mmu/spte.h
> +++ b/arch/x86/kvm/mmu/spte.h
> @@ -17,10 +17,20 @@
>   */
>  #define SPTE_MMU_PRESENT_MASK BIT_ULL(11)
>  
> +/*
> + * The ignored high bits are allocated as follows:
> + * - bits 52, 54: saved X-R bits for access tracking when EPT does not have A/D
> + * - bits 53 (EPT only): host writable
> + * - bits 55 (EPT only): MMU-writable
> + * - bits 56-59: unused
> + * - bits 60-61: type of A/D tracking
> + * - bits 62: unused
> + */
> +
>  /*
>   * 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.
> - * PML, is enabled).  Use bits 52 and 53 to hold the type of A/D tracking that
> + * PML, is enabled).  Use bits 60 and 61 to hold the type of A/D tracking that
>   * is must be employed for a given TDP SPTE.
>   *
>   * Note, the "enabled" mask must be '0', as bits 62:52 are _reserved_ for PAE
> @@ -29,7 +39,7 @@
>   * TDP with CPU dirty logging (PML).  If NPT ever gains PML-like support, it
>   * must be restricted to 64-bit KVM.
>   */
> -#define SPTE_TDP_AD_SHIFT 52
> +#define SPTE_TDP_AD_SHIFT 60
>  #define SPTE_TDP_AD_MASK (3ULL << SPTE_TDP_AD_SHIFT)
>  #define SPTE_TDP_AD_ENABLED (0ULL << SPTE_TDP_AD_SHIFT)
>  #define SPTE_TDP_AD_DISABLED (1ULL << SPTE_TDP_AD_SHIFT)
> @@ -65,7 +75,7 @@ static_assert(SPTE_TDP_AD_ENABLED == 0);
>   */
>  #define SHADOW_ACC_TRACK_SAVED_BITS_MASK (SPTE_EPT_READABLE_MASK | \
>     SPTE_EPT_EXECUTABLE_MASK)
> -#define SHADOW_ACC_TRACK_SAVED_BITS_SHIFT 54
> +#define SHADOW_ACC_TRACK_SAVED_BITS_SHIFT 52
>  #define SHADOW_ACC_TRACK_SAVED_MASK (SHADOW_ACC_TRACK_SAVED_BITS_MASK << \
>   SHADOW_ACC_TRACK_SAVED_BITS_SHIFT)
>  static_assert(!(SPTE_TDP_AD_MASK & SHADOW_ACC_TRACK_SAVED_MASK));
> @@ -84,8 +94,8 @@ static_assert(!(SPTE_TDP_AD_MASK & SHADOW_ACC_TRACK_SAVED_MASK));
>   * to not overlap the A/D type mask or the saved access bits of access-tracked
>   * SPTEs when A/D bits are disabled.
>   */
> -#define EPT_SPTE_HOST_WRITABLE BIT_ULL(57)
> -#define EPT_SPTE_MMU_WRITABLE BIT_ULL(58)
> +#define EPT_SPTE_HOST_WRITABLE BIT_ULL(53)
> +#define EPT_SPTE_MMU_WRITABLE BIT_ULL(55)
>  
>  static_assert(!(EPT_SPTE_HOST_WRITABLE & SPTE_TDP_AD_MASK));
>  static_assert(!(EPT_SPTE_MMU_WRITABLE & SPTE_TDP_AD_MASK));


Reviewed-by: Maxim Levitsky <mlevitsk@xxxxxxxxxx>
Best regards,
Maxim Levitsky