KVM: x86/mmu: move remaining permission fields to struct kvm_pagewalk

As promised, this removes the remaining instances of
container_of(w, struct kvm_mmu, w), meaning that struct
kvm_pagewalk's definition is pretty much complete.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2026-04-05 08:45:01 +02:00
parent 173777d428
commit 7c70bf8f93
3 changed files with 51 additions and 54 deletions

View File

@ -527,6 +527,21 @@ struct kvm_pagewalk {
struct x86_exception *exception);
union kvm_cpu_role cpu_role;
struct rsvd_bits_validate guest_rsvd_check;
/*
* The pkru_mask indicates if protection key checks are needed. It
* consists of 16 domains indexed by page fault error code bits [4:1],
* with PFEC.RSVD replaced by ACC_USER_MASK from the page tables.
* Each domain has 2 bits which are ANDed with AD and WD from PKRU.
*/
u32 pkru_mask;
/*
* Bitmap; bit set = permission fault
* Array index: page fault error code [4:1]
* Bit index: pte permissions in ACC_* format
*/
u16 permissions[16];
};
struct kvm_mmu {
@ -539,23 +554,8 @@ struct kvm_mmu {
hpa_t mirror_root_hpa;
union kvm_mmu_page_role root_role;
/*
* The pkru_mask indicates if protection key checks are needed. It
* consists of 16 domains indexed by page fault error code bits [4:1],
* with PFEC.RSVD replaced by ACC_USER_MASK from the page tables.
* Each domain has 2 bits which are ANDed with AD and WD from PKRU.
*/
u32 pkru_mask;
struct kvm_mmu_root_info prev_roots[KVM_MMU_NUM_PREV_ROOTS];
/*
* Bitmap; bit set = permission fault
* Byte index: page fault error code [4:1]
* Bit index: pte permissions in ACC_* format
*/
u16 permissions[16];
u64 *pae_root;
u64 *pml4_root;
u64 *pml5_root;

View File

@ -163,7 +163,7 @@ bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu);
int kvm_handle_page_fault(struct kvm_vcpu *vcpu, u64 error_code,
u64 fault_address, char *insn, int insn_len);
void __kvm_mmu_refresh_passthrough_bits(struct kvm_vcpu *vcpu,
struct kvm_mmu *mmu);
struct kvm_pagewalk *pw);
int kvm_mmu_load(struct kvm_vcpu *vcpu);
void kvm_mmu_unload(struct kvm_vcpu *vcpu);
@ -260,8 +260,7 @@ static inline void kvm_mmu_refresh_passthrough_bits(struct kvm_vcpu *vcpu,
if (!tdp_enabled || w == &vcpu->arch.guest_mmu.w)
return;
__kvm_mmu_refresh_passthrough_bits(vcpu,
container_of(w, struct kvm_mmu, w));
__kvm_mmu_refresh_passthrough_bits(vcpu, w);
}
/*
@ -276,8 +275,6 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_pagewalk *w,
unsigned pte_access, unsigned pte_pkey,
u64 access)
{
struct kvm_mmu *mmu = container_of(w, struct kvm_mmu, w);
/* strip nested paging fault error codes */
unsigned int pfec = access;
unsigned long rflags = kvm_x86_call(get_rflags)(vcpu);
@ -302,10 +299,10 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_pagewalk *w,
kvm_mmu_refresh_passthrough_bits(vcpu, w);
fault = (mmu->permissions[index] >> pte_access) & 1;
fault = (w->permissions[index] >> pte_access) & 1;
WARN_ON_ONCE(pfec & (PFERR_PK_MASK | PFERR_SS_MASK | PFERR_RSVD_MASK));
if (unlikely(mmu->pkru_mask)) {
if (unlikely(w->pkru_mask)) {
u32 pkru_bits, offset;
/*
@ -319,7 +316,7 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_pagewalk *w,
/* clear present bit, replace PFEC.RSVD with ACC_USER_MASK. */
offset = (pfec & ~1) | ((pte_access & PT_USER_MASK) ? PFERR_RSVD_MASK : 0);
pkru_bits &= mmu->pkru_mask >> offset;
pkru_bits &= w->pkru_mask >> offset;
errcode |= -pkru_bits & PFERR_PK_MASK;
fault |= (pkru_bits != 0);
}

View File

@ -5474,13 +5474,13 @@ static void __reset_rsvds_bits_mask(struct rsvd_bits_validate *rsvd_check,
}
static void reset_guest_rsvds_bits_mask(struct kvm_vcpu *vcpu,
struct kvm_mmu *context)
struct kvm_pagewalk *w)
{
__reset_rsvds_bits_mask(&context->w.guest_rsvd_check,
__reset_rsvds_bits_mask(&w->guest_rsvd_check,
vcpu->arch.reserved_gpa_bits,
context->w.cpu_role.base.level, is_efer_nx(&context->w),
w->cpu_role.base.level, is_efer_nx(w),
guest_cpu_cap_has(vcpu, X86_FEATURE_GBPAGES),
is_cr4_pse(&context->w),
is_cr4_pse(w),
guest_cpuid_is_amd_compatible(vcpu));
}
@ -5655,17 +5655,17 @@ reset_ept_shadow_zero_bits_mask(struct kvm_mmu *context, bool execonly)
(14 & (access) ? 1 << 14 : 0) | \
(15 & (access) ? 1 << 15 : 0))
static void update_permission_bitmask(struct kvm_mmu *mmu, bool tdp, bool ept)
static void update_permission_bitmask(struct kvm_pagewalk *pw, bool tdp, bool ept)
{
unsigned index;
const u16 w = ACC_BITS_MASK(ACC_WRITE_MASK);
const u16 r = ACC_BITS_MASK(ACC_READ_MASK);
bool cr4_smep = is_cr4_smep(&mmu->w);
bool cr4_smap = is_cr4_smap(&mmu->w);
bool cr0_wp = is_cr0_wp(&mmu->w);
bool efer_nx = is_efer_nx(&mmu->w);
bool cr4_smep = is_cr4_smep(pw);
bool cr4_smap = is_cr4_smap(pw);
bool cr0_wp = is_cr0_wp(pw);
bool efer_nx = is_efer_nx(pw);
/*
* In hardware, page fault error codes are generated (as the name
@ -5679,7 +5679,7 @@ static void update_permission_bitmask(struct kvm_mmu *mmu, bool tdp, bool ept)
* permission_fault() to indicate accesses that are *not* subject to
* SMAP restrictions.
*/
for (index = 0; index < ARRAY_SIZE(mmu->permissions); ++index) {
for (index = 0; index < ARRAY_SIZE(pw->permissions); ++index) {
unsigned pfec = index << 1;
/*
@ -5753,7 +5753,7 @@ static void update_permission_bitmask(struct kvm_mmu *mmu, bool tdp, bool ept)
smapf = (pfec & (PFERR_RSVD_MASK|PFERR_FETCH_MASK)) ? 0 : kf;
}
mmu->permissions[index] = ff | uf | wf | rf | smapf;
pw->permissions[index] = ff | uf | wf | rf | smapf;
}
}
@ -5781,19 +5781,19 @@ static void update_permission_bitmask(struct kvm_mmu *mmu, bool tdp, bool ept)
* away both AD and WD. For all reads or if the last condition holds, WD
* only will be masked away.
*/
static void update_pkru_bitmask(struct kvm_mmu *mmu)
static void update_pkru_bitmask(struct kvm_pagewalk *w)
{
unsigned bit;
bool wp;
mmu->pkru_mask = 0;
w->pkru_mask = 0;
if (!is_cr4_pke(&mmu->w))
if (!is_cr4_pke(w))
return;
wp = is_cr0_wp(&mmu->w);
wp = is_cr0_wp(w);
for (bit = 0; bit < ARRAY_SIZE(mmu->permissions); ++bit) {
for (bit = 0; bit < ARRAY_SIZE(w->permissions); ++bit) {
unsigned pfec, pkey_bits;
bool check_pkey, check_write, ff, uf, wf, pte_user;
@ -5821,19 +5821,19 @@ static void update_pkru_bitmask(struct kvm_mmu *mmu)
/* PKRU.WD stops write access. */
pkey_bits |= (!!check_write) << 1;
mmu->pkru_mask |= (pkey_bits & 3) << pfec;
w->pkru_mask |= (pkey_bits & 3) << pfec;
}
}
static void reset_guest_paging_metadata(struct kvm_vcpu *vcpu,
struct kvm_mmu *mmu)
struct kvm_pagewalk *w)
{
if (!is_cr0_pg(&mmu->w))
if (!is_cr0_pg(w))
return;
reset_guest_rsvds_bits_mask(vcpu, mmu);
update_permission_bitmask(mmu, mmu == &vcpu->arch.guest_mmu, false);
update_pkru_bitmask(mmu);
reset_guest_rsvds_bits_mask(vcpu, w);
update_permission_bitmask(w, w == &vcpu->arch.guest_mmu.w, false);
update_pkru_bitmask(w);
}
static void paging64_init_context(struct kvm_mmu *context)
@ -5892,18 +5892,18 @@ static union kvm_cpu_role kvm_calc_cpu_role(struct kvm_vcpu *vcpu,
}
void __kvm_mmu_refresh_passthrough_bits(struct kvm_vcpu *vcpu,
struct kvm_mmu *mmu)
struct kvm_pagewalk *w)
{
const bool cr0_wp = kvm_is_cr0_bit_set(vcpu, X86_CR0_WP);
BUILD_BUG_ON((KVM_MMU_CR0_ROLE_BITS & KVM_POSSIBLE_CR0_GUEST_BITS) != X86_CR0_WP);
BUILD_BUG_ON((KVM_MMU_CR4_ROLE_BITS & KVM_POSSIBLE_CR4_GUEST_BITS));
if (is_cr0_wp(&mmu->w) == cr0_wp)
if (is_cr0_wp(w) == cr0_wp)
return;
mmu->w.cpu_role.base.cr0_wp = cr0_wp;
reset_guest_paging_metadata(vcpu, mmu);
w->cpu_role.base.cr0_wp = cr0_wp;
reset_guest_paging_metadata(vcpu, w);
}
static inline int kvm_mmu_get_tdp_level(struct kvm_vcpu *vcpu)
@ -5981,7 +5981,7 @@ static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu,
else
context->w.gva_to_gpa = paging32_gva_to_gpa;
reset_guest_paging_metadata(vcpu, context);
reset_guest_paging_metadata(vcpu, &context->w);
reset_tdp_shadow_zero_bits_mask(context);
}
@ -6003,7 +6003,7 @@ static void shadow_mmu_init_context(struct kvm_vcpu *vcpu, struct kvm_mmu *conte
else
paging32_init_context(context);
reset_guest_paging_metadata(vcpu, context);
reset_guest_paging_metadata(vcpu, &context->w);
reset_shadow_zero_bits_mask(vcpu, context);
}
@ -6104,8 +6104,8 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly,
context->w.gva_to_gpa = ept_gva_to_gpa;
context->sync_spte = ept_sync_spte;
update_permission_bitmask(context, true, true);
context->pkru_mask = 0;
update_permission_bitmask(&context->w, true, true);
context->w.pkru_mask = 0;
reset_rsvds_bits_mask_ept(vcpu, context, execonly, huge_page_level);
reset_ept_shadow_zero_bits_mask(context, execonly);
}
@ -6162,7 +6162,7 @@ static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu,
else
g_context->w.gva_to_gpa = paging32_gva_to_gpa;
reset_guest_paging_metadata(vcpu, g_context);
reset_guest_paging_metadata(vcpu, &g_context->w);
}
void kvm_init_mmu(struct kvm_vcpu *vcpu)