On Thu, Jan 15, 2026 at 3:22 PM Jim Mattson <[email protected]> wrote: > > When the vCPU is in guest mode with nested NPT enabled, guest accesses to > IA32_PAT are redirected to the gPAT register, which is stored in > vmcb02->save.g_pat. > > Non-guest accesses (e.g. from userspace) to IA32_PAT are always redirected > to hPAT, which is stored in vcpu->arch.pat. > > This is architected behavior. It also makes it possible to restore a new > checkpoint on an old kernel with reasonable semantics. After the restore, > gPAT will be lost, and L2 will run on L1's PAT. Note that the old kernel > would have always run L2 on L1's PAT. > > Signed-off-by: Jim Mattson <[email protected]> > --- > arch/x86/kvm/svm/svm.c | 31 ++++++++++++++++++++++++------- > 1 file changed, 24 insertions(+), 7 deletions(-) > > diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c > index 7041498a8091..3f8581adf0c1 100644 > --- a/arch/x86/kvm/svm/svm.c > +++ b/arch/x86/kvm/svm/svm.c > @@ -2846,6 +2846,13 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct > msr_data *msr_info) > case MSR_AMD64_DE_CFG: > msr_info->data = svm->msr_decfg; > break; > + case MSR_IA32_CR_PAT: > + if (!msr_info->host_initiated && is_guest_mode(vcpu) && > + nested_npt_enabled(svm)) > + msr_info->data = svm->vmcb->save.g_pat; /* gPAT */ > + else > + msr_info->data = vcpu->arch.pat; /* hPAT */ > + break; > default: > return kvm_get_msr_common(vcpu, msr_info); > } > @@ -2929,14 +2936,24 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct > msr_data *msr) > > break; > case MSR_IA32_CR_PAT: > - ret = kvm_set_msr_common(vcpu, msr); > - if (ret) > - break; > + if (!kvm_pat_valid(data)) > + return 1; > > - svm->vmcb01.ptr->save.g_pat = data; > - if (is_guest_mode(vcpu)) > - nested_vmcb02_compute_g_pat(svm); > - vmcb_mark_dirty(svm->vmcb, VMCB_NPT); > + if (!msr->host_initiated && is_guest_mode(vcpu) && > + nested_npt_enabled(svm)) { > + svm->vmcb->save.g_pat = data; /* gPAT */ > + vmcb_mark_dirty(svm->vmcb, VMCB_NPT); > + } else { > + vcpu->arch.pat = data; /* hPAT */ > + if (npt_enabled) { > + svm->vmcb01.ptr->save.g_pat = data; > + vmcb_mark_dirty(svm->vmcb01.ptr, VMCB_NPT); > + if (is_guest_mode(vcpu)) {
Oops. That should be "is_guest_mode(vcpu) && !nested_npt_enabled(svm)". > + svm->vmcb->save.g_pat = data; > + vmcb_mark_dirty(svm->vmcb, VMCB_NPT); > + } > + } > + } > break; > case MSR_IA32_SPEC_CTRL: > if (!msr->host_initiated && > -- > 2.52.0.457.g6b5491de43-goog >

