FAILED: patch "[PATCH] KVM: SEV: Forcefully invalidate SNP VMSA if its backing gmem" failed to apply to 7.1-stable tree
Subsystems (5)
[email protected]
maintainerThe patch below does not apply to the 7.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-7.1.y
git checkout FETCH_HEAD
git cherry-pick -x d1a3c216233413f57f5341a9b878b7e2dde7e785
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026083159-request-customs-f573@gregkh' --subject-prefix 'PATCH 7.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From d1a3c216233413f57f5341a9b878b7e2dde7e785 Mon Sep 17 00:00:00 2001
From: Sean Christopherson <[email protected]>
Date: Thu, 9 Jul 2026 13:49:40 -0700
Subject: [PATCH] KVM: SEV: Forcefully invalidate SNP VMSA if its backing gmem
page is zapped
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Wire up a gmem_invalidate_range() call for SNP VMs, and use it to force vCPUs to reload/recheck their guest-provided VMSA if the backing gmem page is being invalidated, e.g. is being PUNCH_HOLE'd. Use the same core logic to handle invalidations as VMX does for the APIC-access page, as the two concepts are nearly identical: shove the physical address of a page into the vCPU's control structure:
1. Snapshot the invalidation sequence counter
2. Grab the pfn (from guest_memfd in this case)
3. Acquire mmu_lock for read
4. Re-request reload if retry is needed, otherwise commit the change.
Note, the re-request action in #4 is necessary as KVM's retry logic is fuzzy, i.e. can get false positives. If the guest_memfd page has been dropped, at some point a subsequent reload will fail to get a PFN from guest_memfd, and KVM will fail KVM_RUN. If the retry was due to a false positive, KVM will retry until there are no relevant MMU notifier events (and will retry in the "outer" loop, i.e. will drop locks and resched as needed).
Note #2! Take care to invalidate the VMSA when a relevant memslot is DELETED or MOVED, as invalidations in response to PUNCH_HOLE are predicated on memslot bindings (KVM doesn't know what GFN range(s) to invalidate without a binding). And more importantly, the VMSA mapping requires a memslot, i.e. must be invalidated if its memslots disappears, regardless of the state of the underlying guest_memfd inode.
Failure to invalidate the vCPU's control.vmsa_pa (which is checked by pre_sev_run()) can prevent KVM from properly freeing the page as firmware will reject the RMPUPDATE to reclaim the page with FAIL_INUSE if the vCPU is actively running, i.e. if VMSA page is in-use. That in turn leads to an RMP #PF on the next use, as the page will still be assigned to the SNP VM.
SEV-SNP: RMPUPDATE failed for PFN 78d198, pg_level: 1, ret: 3
SEV-SNP: PFN 0x78d198, RMP entry: [0xfff0000000144001 - 0x000000000000000f]
CPU: 3 UID: 0 PID: 31345 Comm: sev_snp_vmsa_pu Tainted: G U O Tainted: [U]=USER, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 34.86.0-102 01/25/2026 Call Trace: <TASK> dump_stack_lvl+0x54/0x70 rmpupdate+0x12c/0x140 rmp_make_shared+0x3b/0x60 sev_gmem_invalidate+0xe0/0x170 [kvm_amd] delete_from_page_cache_batch+0x1d8/0x220 truncate_inode_pages_range+0x120/0x3d0 kvm_gmem_fallocate+0x19a/0x270 [kvm] vfs_fallocate+0x1bc/0x1f0 __x64_sys_fallocate+0x48/0x70 do_syscall_64+0x10a/0x480 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x496c7e </TASK> ------------[ cut here ]------------ SEV: Failed to update RMP entry for PFN 0x78d198 error -14 WARNING: arch/x86/kvm/svm/sev.c:5160 at sev_gmem_invalidate+0x126/0x170 [kvm_amd], CPU#3: sev_snp_vmsa_pu/31345 CPU: 3 UID: 0 PID: 31345 Comm: sev_snp_vmsa_pu Tainted: G U O Tainted: [U]=USER, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 34.86.0-102 01/25/2026 RIP: 0010:sev_gmem_invalidate+0x12b/0x170 [kvm_amd] Call Trace: <TASK> delete_from_page_cache_batch+0x1d8/0x220 truncate_inode_pages_range+0x120/0x3d0 kvm_gmem_fallocate+0x19a/0x270 [kvm] vfs_fallocate+0x1bc/0x1f0 __x64_sys_fallocate+0x48/0x70 do_syscall_64+0x10a/0x480 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x496c7e </TASK> irq event stamp: 20689 hardirqs last enabled at (20699): [<ffffffff8e76092c>] __console_unlock+0x5c/0x60 hardirqs last disabled at (20708): [<ffffffff8e760911>] __console_unlock+0x41/0x60 softirqs last enabled at (20722): [<ffffffff8e6cd74e>] __irq_exit_rcu+0x7e/0x140 softirqs last disabled at (20717): [<ffffffff8e6cd74e>] __irq_exit_rcu+0x7e/0x140 ---[ end trace 0000000000000000 ]--- BUG: unable to handle page fault for address: ffff99a64d198000 #PF: supervisor write access in kernel mode #PF: error_code(0x80000003) - RMP violation PGD 13eb001067 P4D 13eb001067 PUD 78d1d1063 PMD 1184e0063 PTE 800000078d198163 SEV-SNP: PFN 0x78d198, RMP entry: [0x6030000000144001 - 0x000000000000000f] Oops: Oops: 0003 [#1] SMP CPU: 3 UID: 0 PID: 31407 Comm: highlanderd_hea Tainted: G U W O Tainted: [U]=USER, [W]=WARN, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 34.86.0-102 01/25/2026 RIP: 0010:prep_new_page+0x67/0x220 Call Trace: <TASK> get_page_from_freelist+0x1c40/0x1c70 __alloc_frozen_pages_noprof+0xca/0x1f0 alloc_pages_mpol+0x10b/0x1b0 alloc_pages_noprof+0x81/0x90 pte_alloc_one+0x1b/0xd0 do_pte_missing+0xdf/0x1020 handle_mm_fault+0x7c7/0xb20 do_user_addr_fault+0x268/0x6b0 exc_page_fault+0x67/0xa0 asm_exc_page_fault+0x26/0x30 RIP: 0033:0x4a6b1e </TASK> gsmi: Log Shutdown Reason 0x03 CR2: ffff99a64d198000 ---[ end trace 0000000000000000 ]--- RIP: 0010:prep_new_page+0x67/0x220
Drop the pseudo-TODO comment about needing to pin the page if guest_memfd every supports migration, as integrating with invalidations events means KVM will Just Work if/when page migration is ever supported (assuming SNP hardware supports migrating VMSA pages).
Note #3, invalidate() and invalidate_range() have _completely_ different semantics; the new invalidate_range() is a true invalidation, whereas the existing invalidate() is really a "make shared" operation. Ignore the confusing naming and poor Kconfig bundling for the moment to minimize the delta for LTS kernels, the mess will be cleaned up shortly.
arch/x86/include/asm/kvm-x86-ops.h +4 -0
@@ -134,6 +134,7 @@ KVM_X86_OP_OPTIONAL(mem_enc_unregister_region) KVM_X86_OP_OPTIONAL(vm_copy_enc_context_from) KVM_X86_OP_OPTIONAL(vm_move_enc_context_from) KVM_X86_OP_OPTIONAL(guest_memory_reclaimed) +KVM_X86_OP_OPTIONAL(reload_vmsa) KVM_X86_OP(get_feature_msr) KVM_X86_OP(check_emulate_instruction) KVM_X86_OP(apic_init_signal_blocked)
@@ -148,6 +149,9 @@ KVM_X86_OP_OPTIONAL(alloc_apic_backing_page) KVM_X86_OP_OPTIONAL_RET0(gmem_prepare) KVM_X86_OP_OPTIONAL_RET0(gmem_max_mapping_level) KVM_X86_OP_OPTIONAL(gmem_invalidate) +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE +KVM_X86_OP_OPTIONAL(gmem_invalidate_range) +#endif #endif #undef KVM_X86_OP
arch/x86/include/asm/kvm_host.h +6 -0
@@ -122,6 +122,8 @@ KVM_ARCH_REQ_FLAGS(31, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)#define KVM_REQ_HV_TLB_FLUSH \ KVM_ARCH_REQ_FLAGS(32, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) +#define KVM_REQ_VMSA_PAGE_RELOAD \ + KVM_ARCH_REQ_FLAGS(33, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)#define KVM_REQ_UPDATE_PROTECTED_GUEST_STATE \ KVM_ARCH_REQ_FLAGS(34, KVM_REQUEST_WAIT)
@@ -1878,6 +1880,7 @@ struct kvm_x86_ops {int (*vm_copy_enc_context_from)(struct kvm *kvm,unsigned int source_fd);int (*vm_move_enc_context_from)(struct kvm *kvm,unsigned int source_fd);void (*guest_memory_reclaimed)(struct kvm *kvm); +void (*reload_vmsa)(struct kvm_vcpu *vcpu);int (*get_feature_msr)(u32 msr,u64 *data);
@@ -1902,6 +1905,9 @@ struct kvm_x86_ops {void *(*alloc_apic_backing_page)(struct kvm_vcpu *vcpu);int (*gmem_prepare)(struct kvm *kvm,kvm_pfn_t pfn,gfn_t gfn,int max_order);void (*gmem_invalidate)(kvm_pfn_t start,kvm_pfn_t end); +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE +void (*gmem_invalidate_range)(struct kvm *kvm,struct kvm_gfn_range *range); +#endif int (*gmem_max_mapping_level)(struct kvm *kvm,kvm_pfn_t pfn,bool is_private); };
arch/x86/kvm/mmu/mmu.c +5 -0
@@ -7589,6 +7589,11 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,write_lock (&kvm->mmu_lock); +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE +if (slot->gmem.file) +kvm_arch_gmem_invalidate_range (kvm, &range); +#endif +if (zap_all) {__kvm_mmu_zap_all_fast_front_half (kvm); }else {
arch/x86/kvm/svm/sev.c +69 -11
128 lines not on this page · raw message
arch/x86/kvm/svm/svm.c +2 -0
@@ -5445,12 +5445,14 @@ struct kvm_x86_ops svm_x86_ops __initdata = { .mem_enc_register_region = sev_mem_enc_register_region, .mem_enc_unregister_region = sev_mem_enc_unregister_region, .guest_memory_reclaimed = sev_guest_memory_reclaimed, + .reload_vmsa = sev_snp_reload_vmsa, .vm_copy_enc_context_from = sev_vm_copy_enc_context_from, .vm_move_enc_context_from = sev_vm_move_enc_context_from, .gmem_prepare = sev_gmem_prepare, .gmem_invalidate = sev_gmem_invalidate, + .gmem_invalidate_range = sev_gmem_invalidate_range, .gmem_max_mapping_level = sev_gmem_max_mapping_level, #endif .check_emulate_instruction = svm_check_emulate_instruction,
arch/x86/kvm/svm/svm.h +2 -0
@@ -996,6 +996,7 @@ static inline struct page *snp_safe_alloc_page(void) {return snp_safe_alloc_page_node (numa_node_id (),GFP_KERNEL_ACCOUNT ); } +void sev_snp_reload_vmsa (struct kvm_vcpu *vcpu);int sev_vcpu_create (struct kvm_vcpu *vcpu);void sev_free_vcpu (struct kvm_vcpu *vcpu);
@@ -1010,6 +1011,7 @@ extern unsigned int max_sev_asid;void sev_handle_rmp_fault (struct kvm_vcpu *vcpu,gpa_t gpa,u64 error_code);int sev_gmem_prepare (struct kvm *kvm,kvm_pfn_t pfn,gfn_t gfn,int max_order);void sev_gmem_invalidate (kvm_pfn_t start,kvm_pfn_t end); +void sev_gmem_invalidate_range (struct kvm *kvm,struct kvm_gfn_range *range);int sev_gmem_max_mapping_level (struct kvm *kvm,kvm_pfn_t pfn,bool is_private);struct vmcb_save_area *sev_decrypt_vmsa (struct kvm_vcpu *vcpu);void sev_free_decrypted_vmsa (struct kvm_vcpu *vcpu,struct vmcb_save_area *vmsa);
arch/x86/kvm/x86.c +6 -0
@@ -8170,6 +8170,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) goto out; } } +if (kvm_check_request (KVM_REQ_VMSA_PAGE_RELOAD , vcpu)) +kvm_x86_call (reload_vmsa)(vcpu); } if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win ||
@@ -10599,6 +10601,10 @@ void kvm_arch_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end) {kvm_x86_call (gmem_invalidate)(start, end); } +void kvm_arch_gmem_invalidate_range (struct kvm *kvm,struct kvm_gfn_range *range) +{ +kvm_x86_call (gmem_invalidate_range)(kvm, range); +}#endif #endif
include/linux/kvm_host.h +1 -0
@@ -2608,6 +2608,7 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src,#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE void kvm_arch_gmem_invalidate (kvm_pfn_t start,kvm_pfn_t end); +void kvm_arch_gmem_invalidate_range (struct kvm *kvm,struct kvm_gfn_range *range);#endif #ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY
virt/kvm/guest_memfd.c +4 -0
@@ -185,6 +185,10 @@ static void __kvm_gmem_invalidate_start(struct gmem_file *f, pgoff_t start, } flush |=kvm_mmu_unmap_gfn_range (kvm, &gfn_range); + +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE +kvm_arch_gmem_invalidate_range (kvm, &gfn_range); +#endif }if (flush)
Sasha Levin
maintainerPATCH 1/8 KVM: SEV: Track the GPA of the guest-controlled VMSA used for SNP guests
From: Sean Christopherson <[email protected]>
[ Upstream commit 42a39ad5d592aec87a70527a4e694f6210694482 ]
Track the GPA of the guest-provided VMSA used after AP_CREATION events when running SNP guests, instead of simply tracking whether or not the vCPU is using a guest-provided VMSA. KVM needs to know the GPA of the VMSA that's actively being used so that it can react to MMU invalidation events, i.e. so that KVM can drop the VMSA if its backing guest_memfd page is punched out of existence.
Opportunistically rename snp_vmsa_gpa to clarify that it tracks the pending VMSA GPA, whereas snp_guest_vmsa_gpa now tracks the in-use VMSA GPA.
Note! Take care to track the GPA, not the GFN, as VALID_PAGE() won't behave correctly if an invalid GFN is converted to a GPA for checking.
Note #2! Keep snp_has_guest_vmsa so that switching to a guest-provided VMSA is sticky, even if the guest-provided VMSA becomes invalid.
No functional change intended.
Stable-dep-of: d1a3c2162334 ("KVM: SEV: Forcefully invalidate SNP VMSA if its backing gmem page is zapped")
--- arch/x86/kvm/svm/sev.c | 14 +++++++++----- arch/x86/kvm/svm/svm.h | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-)
arch/x86/kvm/svm/sev.c +9 -5
@@ -4105,6 +4105,7 @@ static void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu)/* Clear use of the VMSA */ svm->vmcb->control.vmsa_pa =INVALID_PAGE ; + svm->sev_es.snp_guest_vmsa_gpa =INVALID_PAGE ;/* * When replacing the VMSA during SEV-SNP AP creation,
@@ -4112,11 +4113,11 @@ static void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu)*/ vmcb_mark_all_dirty (svm->vmcb); -if (!VALID_PAGE (svm->sev_es.snp_vmsa_gpa)) +if (!VALID_PAGE (svm->sev_es.snp_pending_vmsa_gpa))return ; - gfn =gpa_to_gfn (svm->sev_es.snp_vmsa_gpa); - svm->sev_es.snp_vmsa_gpa =INVALID_PAGE ; + gfn =gpa_to_gfn (svm->sev_es.snp_pending_vmsa_gpa); + svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ; slot =gfn_to_memslot (vcpu->kvm, gfn);if (!slot)
@@ -4141,6 +4142,7 @@ static void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) svm->sev_es.snp_has_guest_vmsa = true;/* Use the new VMSA */ + svm->sev_es.snp_guest_vmsa_gpa =gfn_to_gpa (gfn); svm->vmcb->control.vmsa_pa =pfn_to_hpa (pfn);/* Mark the vCPU as runnable */
@@ -4207,10 +4209,10 @@ static int sev_snp_ap_creation(struct vcpu_svm *svm)return -EINVAL ; } - target_svm->sev_es.snp_vmsa_gpa = svm->vmcb->control.exit_info_2; + target_svm->sev_es.snp_pending_vmsa_gpa = svm->vmcb->control.exit_info_2;break ;case SVM_VMGEXIT_AP_DESTROY : - target_svm->sev_es.snp_vmsa_gpa =INVALID_PAGE ; + target_svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ;break ;default : vcpu_unimpl(vcpu, "vmgexit: invalid AP creation request [%#x] from guest\n",
@@ -4836,6 +4838,8 @@ int sev_vcpu_create(struct kvm_vcpu *vcpu)return -ENOMEM ; svm->sev_es.vmsa =page_address (vmsa_page); + svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ; + svm->sev_es.snp_guest_vmsa_gpa =INVALID_PAGE ; vcpu->arch.guest_tsc_protected =snp_is_secure_tsc_enabled (vcpu->kvm);
arch/x86/kvm/svm/svm.h +2 -1
@@ -268,7 +268,8 @@ struct vcpu_sev_es_state {u64 ghcb_registered_gpa;struct mutex snp_vmsa_mutex;/* Used to handle concurrent updates of VMSA. */ -gpa_t snp_vmsa_gpa; +gpa_t snp_pending_vmsa_gpa; +gpa_t snp_guest_vmsa_gpa;bool snp_ap_waiting_for_reset;bool snp_has_guest_vmsa; };
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/8 KVM: SEV: Extract loading of guest-provided VMSA to a separate helper
From: Sean Christopherson <[email protected]>
[ Upstream commit 0060569e4f18a7dee2dd8728595e909f19a23c24 ]
Extract the loading/retrieval of a guest-provided VMSA to a separate helper so that KVM can reuse the core logic when refreshing the VMSA after an MMU invalidation from guest_memfd.
No functional change intended.
Stable-dep-of: d1a3c2162334 ("KVM: SEV: Forcefully invalidate SNP VMSA if its backing gmem page is zapped")
--- arch/x86/kvm/svm/sev.c | 52 +++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 21 deletions(-)
arch/x86/kvm/svm/sev.c +31 -21
@@ -4081,29 +4081,17 @@ static int snp_begin_psc(struct vcpu_svm *svm)return snp_do_psc (svm); } -/* -* Invoked as part of svm_vcpu_reset() processing of an init event. -*/ -static void sev_snp_init_protected_guest_state (struct kvm_vcpu *vcpu) +static void sev_snp_reload_vmsa (struct kvm_vcpu *vcpu,gpa_t gpa) {struct vcpu_svm *svm =to_svm (vcpu);struct kvm_memory_slot *slot; +gfn_t gfn =gpa_to_gfn (gpa);struct page *page;kvm_pfn_t pfn; -gfn_t gfn; - -guard (mutex)(&svm->sev_es.snp_vmsa_mutex); - -if (!svm->sev_es.snp_ap_waiting_for_reset) -return ; - svm->sev_es.snp_ap_waiting_for_reset = false; - -/* Mark the vCPU as offline and not runnable */ - vcpu->arch.pv.pv_unhalted = false; -kvm_set_mp_state (vcpu,KVM_MP_STATE_HALTED ); +lockdep_assert_held (&svm->sev_es.snp_vmsa_mutex); -/* Clear use of the VMSA */ +/* Clear use of the VMSA. */ svm->vmcb->control.vmsa_pa =INVALID_PAGE ; svm->sev_es.snp_guest_vmsa_gpa =INVALID_PAGE ;
@@ -4113,12 +4101,9 @@ static void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu)*/ vmcb_mark_all_dirty (svm->vmcb); -if (!VALID_PAGE (svm->sev_es.snp_pending_vmsa_gpa)) +if (!VALID_PAGE (gpa))return ; - gfn =gpa_to_gfn (svm->sev_es.snp_pending_vmsa_gpa); - svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ; - slot =gfn_to_memslot (vcpu->kvm, gfn);if (!slot)return ;
@@ -4142,7 +4127,7 @@ static void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) svm->sev_es.snp_has_guest_vmsa = true;/* Use the new VMSA */ - svm->sev_es.snp_guest_vmsa_gpa =gfn_to_gpa (gfn); + svm->sev_es.snp_guest_vmsa_gpa = gpa; svm->vmcb->control.vmsa_pa =pfn_to_hpa (pfn);/* Mark the vCPU as runnable */
@@ -4156,6 +4141,31 @@ static void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu)kvm_release_page_clean (page); } +/* +* Invoked as part of svm_vcpu_reset() processing of an init event. +*/ +static void sev_snp_init_protected_guest_state (struct kvm_vcpu *vcpu) +{ +struct vcpu_svm *svm =to_svm (vcpu); +gpa_t gpa; + +guard (mutex)(&svm->sev_es.snp_vmsa_mutex); + +if (!svm->sev_es.snp_ap_waiting_for_reset) +return ; + + svm->sev_es.snp_ap_waiting_for_reset = false; + +/* Mark the vCPU as offline and not runnable */ + vcpu->arch.pv.pv_unhalted = false; +kvm_set_mp_state (vcpu,KVM_MP_STATE_HALTED ); + + gpa = svm->sev_es.snp_pending_vmsa_gpa; + svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ; + +sev_snp_reload_vmsa (vcpu, gpa); +} +static int sev_snp_ap_creation (struct vcpu_svm *svm) {struct kvm_sev_info *sev =to_kvm_sev_info (svm->vcpu.kvm);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/8 KVM: SEV: Mark vCPU RUNNABLE after AP_CREATE, even if VMSA is unusable
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit 98ade8c48c28c227fe2e80e545ff0c57cd4712a3 ]
Always mark the vCPU as RUNNABLE after responding to AP_CREATE, even if the guest-specified VMSA is unusable, e.g. isn't backed by a memslot or doesn't have a backing guest_memfd page. If the VMSA is unusable, leaving the vCPU in a non-running state will effectively hang the vCPU instead of reporting an error to userspace. This will also allow retrying the VMSA load in the future, to fix a bug where KVM doesn't honor guest_memfd invalidation events, e.g. if AP_CREATION races with PUNCH_HOLE.
Stable-dep-of: d1a3c2162334 ("KVM: SEV: Forcefully invalidate SNP VMSA if its backing gmem page is zapped")
--- arch/x86/kvm/svm/sev.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/x86/kvm/svm/sev.c +9 -3
@@ -4130,9 +4130,6 @@ static void sev_snp_reload_vmsa(struct kvm_vcpu *vcpu, gpa_t gpa) svm->sev_es.snp_guest_vmsa_gpa = gpa; svm->vmcb->control.vmsa_pa =pfn_to_hpa (pfn); -/* Mark the vCPU as runnable */ -kvm_set_mp_state (vcpu,KVM_MP_STATE_RUNNABLE ); -/* * gmem pages aren't currently migratable, but if this ever changes * then care should be taken to ensure svm->sev_es.vmsa is pinned
@@ -4164,6 +4161,15 @@ static void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) svm->sev_es.snp_pending_vmsa_gpa =INVALID_PAGE ;sev_snp_reload_vmsa (vcpu, gpa); + +/* +* Mark the vCPU as runnable for CREATE requests, indicated by a valid +* VMSA GPA, even if installing the VMSA failed, so that KVM_RUN will +* fail instead of blocking indefinitely and hanging the vCPU, e.g. if +* the backing guest_memfd page is unavailable. +*/ +if (VALID_PAGE (gpa)) +kvm_set_mp_state (vcpu,KVM_MP_STATE_RUNNABLE ); }static int sev_snp_ap_creation (struct vcpu_svm *svm)
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/8 KVM: SEV: Wire up kvm_x86_ops.gmem_xxx() if and only if CONFIG_KVM_AMD_SEV=y
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit 01a96ff30dde5127c37497f1e098e639e7ae152f ]
Wire up the SEV-SNP guest_memfd kvm_x86_ops hooks if and only if SEV is actually enabled, and drop the now-unnecessary stubs. Leaving the hooks NULL allows the static call infrastructure to elide the CALL+RET, and more importantly, referencing the hooks if and only if SEV support is enabled will allow conditionally definining the hooks using their corresponding HAVE_KVM_ARCH_GMEM_XXX Kconfig.
No functional change intended.
Stable-dep-of: d1a3c2162334 ("KVM: SEV: Forcefully invalidate SNP VMSA if its backing gmem page is zapped")
--- arch/x86/kvm/svm/svm.c | 8 ++++---- arch/x86/kvm/svm/svm.h | 10 ---------- 2 files changed, 4 insertions(+), 14 deletions(-)
arch/x86/kvm/svm/svm.c +4 -4
@@ -5400,6 +5400,10 @@ struct kvm_x86_ops svm_x86_ops __initdata = { .vm_copy_enc_context_from = sev_vm_copy_enc_context_from, .vm_move_enc_context_from = sev_vm_move_enc_context_from, + + .gmem_prepare = sev_gmem_prepare, + .gmem_invalidate = sev_gmem_invalidate, + .gmem_max_mapping_level = sev_gmem_max_mapping_level, #endif .check_emulate_instruction = svm_check_emulate_instruction,
@@ -5411,10 +5415,6 @@ struct kvm_x86_ops svm_x86_ops __initdata = { .vcpu_deliver_sipi_vector = svm_vcpu_deliver_sipi_vector, .vcpu_get_apicv_inhibit_reasons = avic_vcpu_get_apicv_inhibit_reasons, .alloc_apic_backing_page = svm_alloc_apic_backing_page, - - .gmem_prepare = sev_gmem_prepare, - .gmem_invalidate = sev_gmem_invalidate, - .gmem_max_mapping_level = sev_gmem_max_mapping_level, };/*
arch/x86/kvm/svm/svm.h +0 -10
@@ -993,16 +993,6 @@ static inline int sev_cpu_init(struct svm_cpu_data *sd) { return 0; }static inline int sev_dev_get_attr (u32 group,u64 attr,u64 *val) {return -ENXIO ; }#define max_sev_asid 0static inline void sev_handle_rmp_fault (struct kvm_vcpu *vcpu,gpa_t gpa,u64 error_code) {} -static inline int sev_gmem_prepare (struct kvm *kvm,kvm_pfn_t pfn,gfn_t gfn,int max_order) -{ -return 0 ; -} -static inline void sev_gmem_invalidate (kvm_pfn_t start,kvm_pfn_t end) {} -static inline int sev_gmem_max_mapping_level (struct kvm *kvm,kvm_pfn_t pfn,bool is_private) -{ -return 0 ; -} -static inline struct vmcb_save_area *sev_decrypt_vmsa (struct kvm_vcpu *vcpu) {return NULL ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/8 KVM: x86/mmu: Fold kvm_mmu_zap_memslot() into kvm_arch_flush_shadow_memslot()
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit 06d38eaa78fdac1cc889f261fa420eba8e9caa1a ]
Fold kvm_mmu_zap_memslot() into its sole caller so that its GFN range structure can be used to trigger guest_memfd invalidations regardless of whether KVM will do a partial or full zap of the MMU.
No functional change intended.
Stable-dep-of: d1a3c2162334 ("KVM: SEV: Forcefully invalidate SNP VMSA if its backing gmem page is zapped")
--- arch/x86/kvm/mmu/mmu.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-)
arch/x86/kvm/mmu/mmu.c +15 -20
@@ -7441,8 +7441,14 @@ static void kvm_mmu_zap_memslot_pages_and_flush(struct kvm *kvm,kvm_mmu_remote_flush_or_zap (kvm, &invalid_list, flush); } -static void kvm_mmu_zap_memslot (struct kvm *kvm, -struct kvm_memory_slot *slot) +static inline bool kvm_memslot_flush_zap_all (struct kvm *kvm) +{ +return kvm->arch.vm_type ==KVM_X86_DEFAULT_VM && +kvm_check_has_quirk (kvm,KVM_X86_QUIRK_SLOT_ZAP_ALL ); +} + +void kvm_arch_flush_shadow_memslot (struct kvm *kvm, +struct kvm_memory_slot *slot) {struct kvm_gfn_range range = { .slot = slot,
@@ -7453,25 +7459,14 @@ static void kvm_mmu_zap_memslot(struct kvm *kvm, };bool flush; -write_lock (&kvm->mmu_lock); - flush =kvm_unmap_gfn_range (kvm, &range); -kvm_mmu_zap_memslot_pages_and_flush (kvm, slot, flush); -write_unlock (&kvm->mmu_lock); -} - -static inline bool kvm_memslot_flush_zap_all (struct kvm *kvm) -{ -return kvm->arch.vm_type ==KVM_X86_DEFAULT_VM && -kvm_check_has_quirk (kvm,KVM_X86_QUIRK_SLOT_ZAP_ALL ); -} - -void kvm_arch_flush_shadow_memslot (struct kvm *kvm, -struct kvm_memory_slot *slot) -{ -if (kvm_memslot_flush_zap_all (kvm)) +if (kvm_memslot_flush_zap_all (kvm)) {kvm_mmu_zap_all_fast (kvm); -else -kvm_mmu_zap_memslot (kvm, slot); + }else { +write_lock (&kvm->mmu_lock); + flush =kvm_unmap_gfn_range (kvm, &range); +kvm_mmu_zap_memslot_pages_and_flush (kvm, slot, flush); +write_unlock (&kvm->mmu_lock); + } }void kvm_mmu_invalidate_mmio_sptes (struct kvm *kvm,u64 gen)
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 6/8 KVM: x86/mmu: Split kvm_mmu_zap_all_fast() into "front" and "back" halves
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit b27622c4eeb125814081baaefe9175191be5b94d ]
Split kvm_mmu_zap_all_fast() into a "front half" and a "back half", where the front half is everything that runs with mmu_lock held for write, and the back half is the code that runs outside of mmu_lock. This will allow putting more code inside kvm_arch_flush_shadow_memslot()'s critical section without having to take mmu_lock twice in quick succession.
No functional change intended.
Stable-dep-of: d1a3c2162334 ("KVM: SEV: Forcefully invalidate SNP VMSA if its backing gmem page is zapped")
--- arch/x86/kvm/mmu/mmu.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-)
arch/x86/kvm/mmu/mmu.c +25 -12
@@ -6802,20 +6802,11 @@ static void kvm_zap_obsolete_pages(struct kvm *kvm)kvm_mmu_commit_zap_page (kvm, &invalid_list); } -/* -* Fast invalidate all shadow pages and use lock-break technique -* to zap obsolete pages. -* -* It's required when memslot is being deleted or VM is being -* destroyed, in these cases, we should ensure that KVM MMU does -* not use any resource of the being-deleted slot or all slots -* after calling the function. -*/ -static void kvm_mmu_zap_all_fast (struct kvm *kvm) +static void __kvm_mmu_zap_all_fast_front_half (struct kvm *kvm) {lockdep_assert_held (&kvm->slots_lock); +lockdep_assert_held_write (&kvm->mmu_lock); -write_lock (&kvm->mmu_lock);trace_kvm_mmu_zap_all_fast (kvm);/*
@@ -6852,8 +6843,12 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm)kvm_make_all_cpus_request (kvm,KVM_REQ_MMU_FREE_OBSOLETE_ROOTS );kvm_zap_obsolete_pages (kvm); +} -write_unlock (&kvm->mmu_lock); +static void __kvm_mmu_zap_all_fast_back_half (struct kvm *kvm) +{ +lockdep_assert_held (&kvm->slots_lock); +lockdep_assert_not_held (&kvm->mmu_lock);/* * Zap the invalidated TDP MMU roots, all SPTEs must be dropped before
@@ -6867,6 +6862,24 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm)kvm_tdp_mmu_zap_invalidated_roots (kvm, true); } +/* +* Fast invalidate all shadow pages and use lock-break technique +* to zap obsolete pages. +* +* It's required when memslot is being deleted or VM is being +* destroyed, in these cases, we should ensure that KVM MMU does +* not use any resource of the being-deleted slot or all slots +* after calling the function. +*/ +static void kvm_mmu_zap_all_fast (struct kvm *kvm) +{ +write_lock (&kvm->mmu_lock); +__kvm_mmu_zap_all_fast_front_half (kvm); +write_unlock (&kvm->mmu_lock); + +__kvm_mmu_zap_all_fast_back_half (kvm); +} +int kvm_mmu_init_vm (struct kvm *kvm) {int r, i;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 7/8 KVM: x86/mmu: Use split "zap all fast" helpers when invalidating memslot
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit db095727ff5739f4f46ee641ee6ef450032886db ]
Manually invoke the front half and back half of the "zap all fast" flow when invalidating a memslot so that mmu_lock is acquired at function scope
in kvm_arch_flush_shadow_memslot(). This will allow putting more code
inside the critical section without having to take mmu_lock twice in quick succession.
Opportunistically open code checking whether or not to do the fast zap, to discourage removing the local "zap_all" in a future cleanup, i.e. to ensure the SLOT_ZAP_ALL quirk is queried exactly once. Processing the front half but not the back half of the fast zap (if SLOT_ZAP_ALL were disabled concurrently) would result in KVM unnecessarily keeping invalid TDP MMU roots until the VM is destroyed.
No functional change intended.
Stable-dep-of: d1a3c2162334 ("KVM: SEV: Forcefully invalidate SNP VMSA if its backing gmem page is zapped")
--- arch/x86/kvm/mmu/mmu.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
arch/x86/kvm/mmu/mmu.c +11 -10
@@ -7454,12 +7454,6 @@ static void kvm_mmu_zap_memslot_pages_and_flush(struct kvm *kvm,kvm_mmu_remote_flush_or_zap (kvm, &invalid_list, flush); } -static inline bool kvm_memslot_flush_zap_all (struct kvm *kvm) -{ -return kvm->arch.vm_type ==KVM_X86_DEFAULT_VM && -kvm_check_has_quirk (kvm,KVM_X86_QUIRK_SLOT_ZAP_ALL ); -} -void kvm_arch_flush_shadow_memslot (struct kvm *kvm,struct kvm_memory_slot *slot) {
@@ -7470,16 +7464,23 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm, .may_block = true, .attr_filter = KVM_FILTER_PRIVATE | KVM_FILTER_SHARED, }; +bool zap_all = kvm->arch.vm_type ==KVM_X86_DEFAULT_VM && +kvm_check_has_quirk (kvm,KVM_X86_QUIRK_SLOT_ZAP_ALL );bool flush; -if (kvm_memslot_flush_zap_all (kvm)) { -kvm_mmu_zap_all_fast (kvm); +write_lock (&kvm->mmu_lock); + +if (zap_all) { +__kvm_mmu_zap_all_fast_front_half (kvm); }else { -write_lock (&kvm->mmu_lock); flush =kvm_unmap_gfn_range (kvm, &range);kvm_mmu_zap_memslot_pages_and_flush (kvm, slot, flush); -write_unlock (&kvm->mmu_lock); } + +write_unlock (&kvm->mmu_lock); + +if (zap_all) +__kvm_mmu_zap_all_fast_back_half (kvm); }void kvm_mmu_invalidate_mmio_sptes (struct kvm *kvm,u64 gen)
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 8/8 KVM: SEV: Forcefully invalidate SNP VMSA if its backing gmem page is zapped
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit d1a3c216233413f57f5341a9b878b7e2dde7e785 ]
Wire up a gmem_invalidate_range() call for SNP VMs, and use it to force vCPUs to reload/recheck their guest-provided VMSA if the backing gmem page is being invalidated, e.g. is being PUNCH_HOLE'd. Use the same core logic to handle invalidations as VMX does for the APIC-access page, as the two concepts are nearly identical: shove the physical address of a page into the vCPU's control structure:
1. Snapshot the invalidation sequence counter
2. Grab the pfn (from guest_memfd in this case)
3. Acquire mmu_lock for read
4. Re-request reload if retry is needed, otherwise commit the change.
Note, the re-request action in #4 is necessary as KVM's retry logic is fuzzy, i.e. can get false positives. If the guest_memfd page has been dropped, at some point a subsequent reload will fail to get a PFN from guest_memfd, and KVM will fail KVM_RUN. If the retry was due to a false positive, KVM will retry until there are no relevant MMU notifier events (and will retry in the "outer" loop, i.e. will drop locks and resched as needed).
Note #2! Take care to invalidate the VMSA when a relevant memslot is DELETED or MOVED, as invalidations in response to PUNCH_HOLE are predicated on memslot bindings (KVM doesn't know what GFN range(s) to invalidate without a binding). And more importantly, the VMSA mapping requires a memslot, i.e. must be invalidated if its memslots disappears, regardless of the state of the underlying guest_memfd inode.
Failure to invalidate the vCPU's control.vmsa_pa (which is checked by pre_sev_run()) can prevent KVM from properly freeing the page as firmware will reject the RMPUPDATE to reclaim the page with FAIL_INUSE if the vCPU is actively running, i.e. if VMSA page is in-use. That in turn leads to an RMP #PF on the next use, as the page will still be assigned to the SNP VM.
SEV-SNP: RMPUPDATE failed for PFN 78d198, pg_level: 1, ret: 3
SEV-SNP: PFN 0x78d198, RMP entry: [0xfff0000000144001 - 0x000000000000000f]
CPU: 3 UID: 0 PID: 31345 Comm: sev_snp_vmsa_pu Tainted: G U O Tainted: [U]=USER, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 34.86.0-102 01/25/2026 Call Trace: <TASK> dump_stack_lvl+0x54/0x70 rmpupdate+0x12c/0x140 rmp_make_shared+0x3b/0x60 sev_gmem_invalidate+0xe0/0x170 [kvm_amd] delete_from_page_cache_batch+0x1d8/0x220 truncate_inode_pages_range+0x120/0x3d0 kvm_gmem_fallocate+0x19a/0x270 [kvm] vfs_fallocate+0x1bc/0x1f0 __x64_sys_fallocate+0x48/0x70 do_syscall_64+0x10a/0x480 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x496c7e </TASK> ------------[ cut here ]------------ SEV: Failed to update RMP entry for PFN 0x78d198 error -14 WARNING: arch/x86/kvm/svm/sev.c:5160 at sev_gmem_invalidate+0x126/0x170 [kvm_amd], CPU#3: sev_snp_vmsa_pu/31345 CPU: 3 UID: 0 PID: 31345 Comm: sev_snp_vmsa_pu Tainted: G U O Tainted: [U]=USER, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 34.86.0-102 01/25/2026 RIP: 0010:sev_gmem_invalidate+0x12b/0x170 [kvm_amd] Call Trace: <TASK> delete_from_page_cache_batch+0x1d8/0x220 truncate_inode_pages_range+0x120/0x3d0 kvm_gmem_fallocate+0x19a/0x270 [kvm] vfs_fallocate+0x1bc/0x1f0 __x64_sys_fallocate+0x48/0x70 do_syscall_64+0x10a/0x480 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x496c7e </TASK> irq event stamp: 20689 hardirqs last enabled at (20699): [<ffffffff8e76092c>] __console_unlock+0x5c/0x60 hardirqs last disabled at (20708): [<ffffffff8e760911>] __console_unlock+0x41/0x60 softirqs last enabled at (20722): [<ffffffff8e6cd74e>] __irq_exit_rcu+0x7e/0x140 softirqs last disabled at (20717): [<ffffffff8e6cd74e>] __irq_exit_rcu+0x7e/0x140 ---[ end trace 0000000000000000 ]--- BUG: unable to handle page fault for address: ffff99a64d198000 #PF: supervisor write access in kernel mode #PF: error_code(0x80000003) - RMP violation PGD 13eb001067 P4D 13eb001067 PUD 78d1d1063 PMD 1184e0063 PTE 800000078d198163 SEV-SNP: PFN 0x78d198, RMP entry: [0x6030000000144001 - 0x000000000000000f] Oops: Oops: 0003 [#1] SMP CPU: 3 UID: 0 PID: 31407 Comm: highlanderd_hea Tainted: G U W O Tainted: [U]=USER, [W]=WARN, [O]=OOT_MODULE Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 34.86.0-102 01/25/2026 RIP: 0010:prep_new_page+0x67/0x220 Call Trace: <TASK> get_page_from_freelist+0x1c40/0x1c70 __alloc_frozen_pages_noprof+0xca/0x1f0 alloc_pages_mpol+0x10b/0x1b0 alloc_pages_noprof+0x81/0x90 pte_alloc_one+0x1b/0xd0 do_pte_missing+0xdf/0x1020 handle_mm_fault+0x7c7/0xb20 do_user_addr_fault+0x268/0x6b0 exc_page_fault+0x67/0xa0 asm_exc_page_fault+0x26/0x30 RIP: 0033:0x4a6b1e </TASK> gsmi: Log Shutdown Reason 0x03 CR2: ffff99a64d198000 ---[ end trace 0000000000000000 ]--- RIP: 0010:prep_new_page+0x67/0x220
Drop the pseudo-TODO comment about needing to pin the page if guest_memfd every supports migration, as integrating with invalidations events means KVM will Just Work if/when page migration is ever supported (assuming SNP hardware supports migrating VMSA pages).
Note #3, invalidate() and invalidate_range() have _completely_ different semantics; the new invalidate_range() is a true invalidation, whereas the existing invalidate() is really a "make shared" operation. Ignore the confusing naming and poor Kconfig bundling for the moment to minimize the delta for LTS kernels, the mess will be cleaned up shortly.
--- arch/x86/include/asm/kvm-x86-ops.h | 4 ++ arch/x86/include/asm/kvm_host.h | 6 +++ arch/x86/kvm/mmu/mmu.c | 5 ++ arch/x86/kvm/svm/sev.c | 80 ++++++++++++++++++++++++++---- arch/x86/kvm/svm/svm.c | 2 + arch/x86/kvm/svm/svm.h | 2 + arch/x86/kvm/x86.c | 6 +++ include/linux/kvm_host.h | 1 + virt/kvm/guest_memfd.c | 4 ++ 9 files changed, 99 insertions(+), 11 deletions(-)
arch/x86/include/asm/kvm-x86-ops.h +4 -0
@@ -135,6 +135,7 @@ KVM_X86_OP_OPTIONAL(mem_enc_unregister_region) KVM_X86_OP_OPTIONAL(vm_copy_enc_context_from) KVM_X86_OP_OPTIONAL(vm_move_enc_context_from) KVM_X86_OP_OPTIONAL(guest_memory_reclaimed) +KVM_X86_OP_OPTIONAL(reload_vmsa) KVM_X86_OP(get_feature_msr) KVM_X86_OP(check_emulate_instruction) KVM_X86_OP(apic_init_signal_blocked)
@@ -149,6 +150,9 @@ KVM_X86_OP_OPTIONAL(alloc_apic_backing_page) KVM_X86_OP_OPTIONAL_RET0(gmem_prepare) KVM_X86_OP_OPTIONAL_RET0(gmem_max_mapping_level) KVM_X86_OP_OPTIONAL(gmem_invalidate) +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE +KVM_X86_OP_OPTIONAL(gmem_invalidate_range) +#endif #endif #undef KVM_X86_OP
arch/x86/include/asm/kvm_host.h +6 -0
@@ -128,6 +128,8 @@ KVM_ARCH_REQ_FLAGS(31, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)#define KVM_REQ_HV_TLB_FLUSH \ KVM_ARCH_REQ_FLAGS(32, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) +#define KVM_REQ_VMSA_PAGE_RELOAD \ + KVM_ARCH_REQ_FLAGS(33, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)#define KVM_REQ_UPDATE_PROTECTED_GUEST_STATE \ KVM_ARCH_REQ_FLAGS(34, KVM_REQUEST_WAIT)
@@ -1969,6 +1971,7 @@ struct kvm_x86_ops {int (*vm_copy_enc_context_from)(struct kvm *kvm,unsigned int source_fd);int (*vm_move_enc_context_from)(struct kvm *kvm,unsigned int source_fd);void (*guest_memory_reclaimed)(struct kvm *kvm); +void (*reload_vmsa)(struct kvm_vcpu *vcpu);int (*get_feature_msr)(u32 msr,u64 *data);
@@ -1993,6 +1996,9 @@ struct kvm_x86_ops {void *(*alloc_apic_backing_page)(struct kvm_vcpu *vcpu);int (*gmem_prepare)(struct kvm *kvm,kvm_pfn_t pfn,gfn_t gfn,int max_order);void (*gmem_invalidate)(kvm_pfn_t start,kvm_pfn_t end); +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE +void (*gmem_invalidate_range)(struct kvm *kvm,struct kvm_gfn_range *range); +#endif int (*gmem_max_mapping_level)(struct kvm *kvm,kvm_pfn_t pfn,bool is_private); };
arch/x86/kvm/mmu/mmu.c +5 -0
@@ -7470,6 +7470,11 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,write_lock (&kvm->mmu_lock); +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE +if (slot->gmem.file) +kvm_arch_gmem_invalidate_range (kvm, &range); +#endif +if (zap_all) {__kvm_mmu_zap_all_fast_front_half (kvm); }else {
arch/x86/kvm/svm/sev.c +69 -11
128 lines not on this page · raw message
arch/x86/kvm/svm/svm.c +2 -0
@@ -5397,12 +5397,14 @@ struct kvm_x86_ops svm_x86_ops __initdata = { .mem_enc_register_region = sev_mem_enc_register_region, .mem_enc_unregister_region = sev_mem_enc_unregister_region, .guest_memory_reclaimed = sev_guest_memory_reclaimed, + .reload_vmsa = sev_snp_reload_vmsa, .vm_copy_enc_context_from = sev_vm_copy_enc_context_from, .vm_move_enc_context_from = sev_vm_move_enc_context_from, .gmem_prepare = sev_gmem_prepare, .gmem_invalidate = sev_gmem_invalidate, + .gmem_invalidate_range = sev_gmem_invalidate_range, .gmem_max_mapping_level = sev_gmem_max_mapping_level, #endif .check_emulate_instruction = svm_check_emulate_instruction,
arch/x86/kvm/svm/svm.h +2 -0
@@ -954,6 +954,7 @@ static inline struct page *snp_safe_alloc_page(void) {return snp_safe_alloc_page_node (numa_node_id (),GFP_KERNEL_ACCOUNT ); } +void sev_snp_reload_vmsa (struct kvm_vcpu *vcpu);int sev_vcpu_create (struct kvm_vcpu *vcpu);void sev_free_vcpu (struct kvm_vcpu *vcpu);
@@ -968,6 +969,7 @@ extern unsigned int max_sev_asid;void sev_handle_rmp_fault (struct kvm_vcpu *vcpu,gpa_t gpa,u64 error_code);int sev_gmem_prepare (struct kvm *kvm,kvm_pfn_t pfn,gfn_t gfn,int max_order);void sev_gmem_invalidate (kvm_pfn_t start,kvm_pfn_t end); +void sev_gmem_invalidate_range (struct kvm *kvm,struct kvm_gfn_range *range);int sev_gmem_max_mapping_level (struct kvm *kvm,kvm_pfn_t pfn,bool is_private);struct vmcb_save_area *sev_decrypt_vmsa (struct kvm_vcpu *vcpu);void sev_free_decrypted_vmsa (struct kvm_vcpu *vcpu,struct vmcb_save_area *vmsa);
arch/x86/kvm/x86.c +6 -0
@@ -11309,6 +11309,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) goto out; } } +if (kvm_check_request (KVM_REQ_VMSA_PAGE_RELOAD , vcpu)) +kvm_x86_call (reload_vmsa)(vcpu); } if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win ||
@@ -14173,6 +14175,10 @@ void kvm_arch_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end) {kvm_x86_call (gmem_invalidate)(start, end); } +void kvm_arch_gmem_invalidate_range (struct kvm *kvm,struct kvm_gfn_range *range) +{ +kvm_x86_call (gmem_invalidate_range)(kvm, range); +}#endif #endif
include/linux/kvm_host.h +1 -0
@@ -2608,6 +2608,7 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src,#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE void kvm_arch_gmem_invalidate (kvm_pfn_t start,kvm_pfn_t end); +void kvm_arch_gmem_invalidate_range (struct kvm *kvm,struct kvm_gfn_range *range);#endif #ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY
virt/kvm/guest_memfd.c +4 -0
@@ -185,6 +185,10 @@ static void __kvm_gmem_invalidate_begin(struct gmem_file *f, pgoff_t start, } flush |=kvm_mmu_unmap_gfn_range (kvm, &gfn_range); + +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE +kvm_arch_gmem_invalidate_range (kvm, &gfn_range); +#endif }if (flush)
Signature · 1 line
2.53.0