KVM: SVM: enable GMET and set it in MMU role

Set the GMET bit in the nested control field.  This has effectively
no impact as long as NPT page tables are changed to have U=0.

Tested-by: David Riley <d.riley@proxmox.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2026-04-08 11:42:15 -04:00
parent 3129c6b81c
commit fe080f58de
4 changed files with 28 additions and 4 deletions

View File

@ -5855,7 +5855,6 @@ kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu,
{
union kvm_mmu_page_role role = {0};
role.access = ACC_ALL;
role.cr0_wp = true;
role.cr4_smep = kvm_x86_call(tdp_has_smep)(vcpu->kvm);
role.efer_nx = true;
@ -5866,6 +5865,11 @@ kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu,
role.direct = true;
role.has_4_byte_gpte = false;
/* All TDP pages are supervisor-executable */
role.access = ACC_ALL;
if (role.cr4_smep && shadow_user_mask)
role.access &= ~ACC_USER_MASK;
return role;
}

View File

@ -858,7 +858,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm)
* the latter, L1 runs L2 with shadow page tables that translate L2 GVAs
* to L1 GPAs, so the same NPTs can be used for L1 and L2.
*/
vmcb02->control.misc_ctl = vmcb01->control.misc_ctl & SVM_MISC_ENABLE_NP;
vmcb02->control.misc_ctl = vmcb01->control.misc_ctl & (SVM_MISC_ENABLE_NP | SVM_MISC_ENABLE_GMET);
vmcb02->control.iopm_base_pa = vmcb01->control.iopm_base_pa;
vmcb02->control.msrpm_base_pa = vmcb01->control.msrpm_base_pa;
vmcb_mark_dirty(vmcb02, VMCB_PERM_MAP);
@ -895,9 +895,12 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm)
/* Also overwritten later if necessary. */
vmcb02->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
/* nested_cr3. */
if (nested_npt_enabled(svm))
/* Use vmcb01 MMU and format if guest does not use nNPT */
if (nested_npt_enabled(svm)) {
vmcb02->control.misc_ctl &= ~SVM_MISC_ENABLE_GMET;
nested_svm_init_mmu_context(vcpu);
}
vcpu->arch.tsc_offset = kvm_calc_nested_tsc_offset(vcpu->arch.l1_tsc_offset,
vmcb12_ctrl->tsc_offset,

View File

@ -138,6 +138,9 @@ module_param(pause_filter_count_max, ushort, 0444);
bool __ro_after_init npt_enabled = true;
module_param_named(npt, npt_enabled, bool, 0444);
bool gmet_enabled = true;
module_param_named(gmet, gmet_enabled, bool, 0444);
/* allow nested virtualization in KVM/SVM */
static int __ro_after_init nested = true;
module_param(nested, int, 0444);
@ -1209,6 +1212,10 @@ static void init_vmcb(struct kvm_vcpu *vcpu, bool init_event)
save->g_pat = vcpu->arch.pat;
save->cr3 = 0;
}
if (gmet_enabled)
control->misc_ctl |= SVM_MISC_ENABLE_GMET;
svm->current_vmcb->asid_generation = 0;
svm->asid = 0;
@ -4612,6 +4619,11 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
hypercall[2] = 0xd9;
}
static bool svm_tdp_has_smep(struct kvm *kvm)
{
return gmet_enabled;
}
/*
* The kvm parameter can be NULL (module initialization, or invocation before
* VM creation). Be sure to check the kvm parameter before using it.
@ -5355,6 +5367,7 @@ struct kvm_x86_ops svm_x86_ops __initdata = {
.write_tsc_multiplier = svm_write_tsc_multiplier,
.load_mmu_pgd = svm_load_mmu_pgd,
.tdp_has_smep = svm_tdp_has_smep,
.check_intercept = svm_check_intercept,
.handle_exit_irqoff = svm_handle_exit_irqoff,
@ -5588,6 +5601,9 @@ static __init int svm_hardware_setup(void)
if (!boot_cpu_has(X86_FEATURE_NPT))
npt_enabled = false;
if (!npt_enabled || !boot_cpu_has(X86_FEATURE_GMET))
gmet_enabled = false;
/* Force VM NPT level equal to the host's paging level */
kvm_configure_mmu(npt_enabled, get_npt_level(),
get_npt_level(), PG_LEVEL_1G);

View File

@ -44,6 +44,7 @@ static inline struct page *__sme_pa_to_page(unsigned long pa)
#define IOPM_SIZE PAGE_SIZE * 3
#define MSRPM_SIZE PAGE_SIZE * 2
extern bool gmet_enabled;
extern bool npt_enabled;
extern int nrips;
extern int vgif;