[PATCH 00/10] KVM: x86: nSVM: Improve PAT virtualization

Jim Mattson posted 10 patches 3 weeks, 4 days ago
There is a newer version of this series
arch/x86/include/uapi/asm/kvm.h               |   3 +
arch/x86/kvm/svm/nested.c                     |  74 +++-
arch/x86/kvm/svm/svm.c                        |  14 +-
arch/x86/kvm/svm/svm.h                        |   2 +-
tools/testing/selftests/kvm/Makefile.kvm      |   1 +
.../selftests/kvm/x86/svm_nested_pat_test.c   | 357 ++++++++++++++++++
6 files changed, 432 insertions(+), 19 deletions(-)
create mode 100644 tools/testing/selftests/kvm/x86/svm_nested_pat_test.c
[PATCH 00/10] KVM: x86: nSVM: Improve PAT virtualization
Posted by Jim Mattson 3 weeks, 4 days ago
KVM's implementation of nested SVM treats PAT the same way whether or
not nested NPT is enabled: L1 and L2 share a PAT.

This is correct when nested NPT is disabled, but incorrect when nested
NPT is enabled. When nested NPT is enabled, L1 and L2 have independent
PATs.

The architectural specification for this separation is unusual. There
is a "guest PAT register" that is accessed by references to the PAT
MSR in guest mode, but it is different from the (host) PAT MSR. Other
resources that have distinct host and guest values have a shared
storage location, and the values are swapped on VM-entry/VM-exit.

In
https://lore.kernel.org/kvm/20251107201151.3303170-1-jmattson@google.com/,
I proposed an implementation that adhered to the architectural
specification. It had a few warts. The worst was the necessity of
"fixing up" KVM_SET_MSRS when executing KVM_SET_NESTED_STATE if L2 was
active and nested NPT was enabled when a snapshot was taken. Aside
from Yosry's clarification, no one has responded. I will take silence
to imply rejection. That's okay; I wasn't fond of that implementation
myself.

The current series treats PAT just like any other resource with
distinct host and guest values. There is a single shared storage
location (vcpu->arch.pat), and the values are swapped on
VM-entry/VM-exit. Though this implementation doesn't precisely follow
the architectural specification, the guest visible behavior is the
same as architected.

The first three patches ensure that the vmcb01.g_pat value at VMRUN is
preserved through virtual SMM and serialization. When NPT is enabled,
this field holds the host (L1) hPAT value from emulated VMRUN to
emulated #VMEXIT.

The fourth patch restores (L1) hPAT value from vmcb01.g_pat at
emulated #VMEXIT. Note that this is not architected, but it is
required for this implementation, because hPAT and gPAT occupy the
same storage location.

The next three patches handle loading vmcb12.g_pat into the (L2) guest
PAT register at VMRUN. Most of this behavior is architected, but the
architectural specification states that the value is loaded into the
guest PAT register, leaving the hPAT register unchanged.

The eighth patch stores the (L2) guest PAT register into vmcb12_g_pat
on emulated #VMEXIT, as architected.

The ninth patch fixes the emulation of WRMSR(IA32_PAT) when nested NPT
is enabled.

The tenth patch introduces a new KVM selftest to validate virtualized
PAT behavior.

Jim Mattson (10):
  KVM: x86: nSVM: Add g_pat to fields copied by svm_copy_vmrun_state()
  KVM: x86: nSVM: Add VALID_GPAT flag to kvm_svm_nested_state_hdr
  KVM: x86: nSVM: Handle legacy SVM nested state in SET_NESTED_STATE
  KVM: x86: nSVM: Restore L1's PAT on emulated #VMEXIT from L2 to L1
  KVM: x86: nSVM: Cache g_pat in vmcb_save_area_cached
  KVM: x86: nSVM: Add validity check for VMCB12 g_pat
  KVM: x86: nSVM: Set vmcb02.g_pat correctly for nested NPT
  KVM: x86: nSVM: Save gPAT to vmcb12.g_pat on emulated #VMEXIT from L2
    to L1
  KVM: x86: nSVM: Fix assignment to IA32_PAT from L2
  KVM: selftests: nSVM: Add svm_nested_pat test

 arch/x86/include/uapi/asm/kvm.h               |   3 +
 arch/x86/kvm/svm/nested.c                     |  74 +++-
 arch/x86/kvm/svm/svm.c                        |  14 +-
 arch/x86/kvm/svm/svm.h                        |   2 +-
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 .../selftests/kvm/x86/svm_nested_pat_test.c   | 357 ++++++++++++++++++
 6 files changed, 432 insertions(+), 19 deletions(-)
 create mode 100644 tools/testing/selftests/kvm/x86/svm_nested_pat_test.c


base-commit: f62b64b970570c92fe22503b0cdc65be7ce7fc7c
-- 
2.52.0.457.g6b5491de43-goog
Re: [PATCH 00/10] KVM: x86: nSVM: Improve PAT virtualization
Posted by Sean Christopherson 3 weeks, 2 days ago
Trimmed the Cc.

Please adjust whatever script (or script invocation) you're using to generate
the Cc list.  AFAIK, Alex hasn't for SUSE for years, Radim hasn't worked for
Red Hat for years, and Avi hasn't worked on KVM at all for even longer :-)
Re: [PATCH 00/10] KVM: x86: nSVM: Improve PAT virtualization
Posted by Jim Mattson 3 weeks, 3 days ago
On Mon, Jan 12, 2026 at 4:30 PM Jim Mattson <jmattson@google.com> wrote:
>
> KVM's implementation of nested SVM treats PAT the same way whether or
> not nested NPT is enabled: L1 and L2 share a PAT.
>
> This is correct when nested NPT is disabled, but incorrect when nested
> NPT is enabled. When nested NPT is enabled, L1 and L2 have independent
> PATs.

Yosry points out that this series does not correctly handle saving a
checkpoint on a new kernel and restoring it on an old kernel. In that
scenario, KVM_SET_MSRS will restore the L2 PAT, and the old kernel
will not restore L1's PAT on emulated #VMEXIT.

I have also discovered that not all userspace VMMs restore MSRs before
nested state.

Ironically, I think the way to correctly deal with compatibility in
both directions is to go back to the architected separation of hPAT
and gPAT. Accesses to IA32_PAT from userspace will always have to
reference hPAT to properly restore a new checkpoint on an old kernel.

Cooking up v2...