Define a quirk to control whether nested SVM shares L1's PAT with L2
(legacy behavior) or gives L2 its own independent gPAT (correct behavior
per the APM).
When the quirk is enabled (default), L2 shares L1's PAT, preserving the
legacy KVM behavior. When userspace disables the quirk, KVM correctly
virtualizes the PAT for nested SVM guests, giving L2 a separate gPAT as
specified in the AMD architecture.
Signed-off-by: Jim Mattson <jmattson@google.com>
---
Documentation/virt/kvm/api.rst | 14 ++++++++++++++
arch/x86/include/asm/kvm_host.h | 3 ++-
arch/x86/include/uapi/asm/kvm.h | 1 +
arch/x86/kvm/svm/svm.h | 11 +++++++++++
4 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 032516783e96..2d56f17e3760 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -8551,6 +8551,20 @@ KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM By default, KVM relaxes the consisten
bit to be cleared. Note that the vmcs02
bit is still completely controlled by the
host, regardless of the quirk setting.
+
+KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT By default, KVM for nested SVM guests
+ shares the IA32_PAT MSR between L1 and
+ L2. This is legacy behavior and does
+ not match the AMD architecture
+ specification. When this quirk is
+ disabled and nested paging (NPT) is
+ enabled for L2, KVM correctly
+ virtualizes a separate guest PAT
+ register for L2, using the g_pat
+ field in the VMCB. When NPT is
+ disabled for L2, L1 and L2 continue
+ to share the IA32_PAT MSR regardless
+ of the quirk setting.
======================================== ================================================
7.32 KVM_CAP_MAX_VCPU_ID
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index d3bdc9828133..0b4ab141feae 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -2511,7 +2511,8 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages);
KVM_X86_QUIRK_SLOT_ZAP_ALL | \
KVM_X86_QUIRK_STUFF_FEATURE_MSRS | \
KVM_X86_QUIRK_IGNORE_GUEST_PAT | \
- KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM)
+ KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM | \
+ KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT)
#define KVM_X86_CONDITIONAL_QUIRKS \
(KVM_X86_QUIRK_CD_NW_CLEARED | \
diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index 5f2b30d0405c..3ada2fa9ca86 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -477,6 +477,7 @@ struct kvm_sync_regs {
#define KVM_X86_QUIRK_STUFF_FEATURE_MSRS (1 << 8)
#define KVM_X86_QUIRK_IGNORE_GUEST_PAT (1 << 9)
#define KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM (1 << 10)
+#define KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT (1 << 11)
#define KVM_STATE_NESTED_FORMAT_VMX 0
#define KVM_STATE_NESTED_FORMAT_SVM 1
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index ff1e4b4dc998..74014110b550 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -616,6 +616,17 @@ static inline bool nested_npt_enabled(struct vcpu_svm *svm)
return svm->nested.ctl.misc_ctl & SVM_MISC_ENABLE_NP;
}
+static inline bool l2_has_separate_pat(struct vcpu_svm *svm)
+{
+ /*
+ * If KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT is disabled while a vCPU
+ * is running, the L2 IA32_PAT semantics for that vCPU are undefined.
+ */
+ return nested_npt_enabled(svm) &&
+ !kvm_check_has_quirk(svm->vcpu.kvm,
+ KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT);
+}
+
static inline bool nested_vnmi_enabled(struct vcpu_svm *svm)
{
return guest_cpu_cap_has(&svm->vcpu, X86_FEATURE_VNMI) &&
--
2.53.0.1018.g2bb0e51243-goog
Hi Jim,
kernel test robot noticed the following build errors:
[auto build test ERROR on 3d6cdcc8883b5726513d245eef0e91cabfc397f7]
url: https://github.com/intel-lab-lkp/linux/commits/Jim-Mattson/KVM-x86-Define-KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT/20260328-110805
base: 3d6cdcc8883b5726513d245eef0e91cabfc397f7
patch link: https://lore.kernel.org/r/20260327234023.2659476-2-jmattson%40google.com
patch subject: [PATCH v7 1/9] KVM: x86: Define KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT
config: x86_64-randconfig-016-20260330 (https://download.01.org/0day-ci/archive/20260330/202603301501.N2sdlIQ9-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260330/202603301501.N2sdlIQ9-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603301501.N2sdlIQ9-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from arch/x86/kvm/svm/svm_onhyperv.c:11:
arch/x86/kvm/svm/svm.h: In function 'l2_has_separate_pat':
>> arch/x86/kvm/svm/svm.h:626:18: error: implicit declaration of function 'kvm_check_has_quirk'; did you mean 'kvm_check_request'? [-Wimplicit-function-declaration]
626 | !kvm_check_has_quirk(svm->vcpu.kvm,
| ^~~~~~~~~~~~~~~~~~~
| kvm_check_request
In file included from arch/x86/kvm/svm/svm_ops.h:7,
from arch/x86/kvm/svm/svm_onhyperv.c:12:
arch/x86/kvm/x86.h: At top level:
>> arch/x86/kvm/x86.h:429:20: error: conflicting types for 'kvm_check_has_quirk'; have 'bool(struct kvm *, u64)' {aka '_Bool(struct kvm *, long long unsigned int)'}
429 | static inline bool kvm_check_has_quirk(struct kvm *kvm, u64 quirk)
| ^~~~~~~~~~~~~~~~~~~
arch/x86/kvm/svm/svm.h:626:18: note: previous implicit declaration of 'kvm_check_has_quirk' with type 'int()'
626 | !kvm_check_has_quirk(svm->vcpu.kvm,
| ^~~~~~~~~~~~~~~~~~~
--
In file included from kvm/svm/svm_onhyperv.c:11:
kvm/svm/svm.h: In function 'l2_has_separate_pat':
kvm/svm/svm.h:626:18: error: implicit declaration of function 'kvm_check_has_quirk'; did you mean 'kvm_check_request'? [-Wimplicit-function-declaration]
626 | !kvm_check_has_quirk(svm->vcpu.kvm,
| ^~~~~~~~~~~~~~~~~~~
| kvm_check_request
In file included from kvm/svm/svm_ops.h:7,
from kvm/svm/svm_onhyperv.c:12:
arch/x86/kvm/x86.h: At top level:
>> arch/x86/kvm/x86.h:429:20: error: conflicting types for 'kvm_check_has_quirk'; have 'bool(struct kvm *, u64)' {aka '_Bool(struct kvm *, long long unsigned int)'}
429 | static inline bool kvm_check_has_quirk(struct kvm *kvm, u64 quirk)
| ^~~~~~~~~~~~~~~~~~~
kvm/svm/svm.h:626:18: note: previous implicit declaration of 'kvm_check_has_quirk' with type 'int()'
626 | !kvm_check_has_quirk(svm->vcpu.kvm,
| ^~~~~~~~~~~~~~~~~~~
vim +626 arch/x86/kvm/svm/svm.h
618
619 static inline bool l2_has_separate_pat(struct vcpu_svm *svm)
620 {
621 /*
622 * If KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT is disabled while a vCPU
623 * is running, the L2 IA32_PAT semantics for that vCPU are undefined.
624 */
625 return nested_npt_enabled(svm) &&
> 626 !kvm_check_has_quirk(svm->vcpu.kvm,
627 KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT);
628 }
629
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.