From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Splitting a huge S-EPT mapping requires the host to provide a new 4KB page,
which will be added as the S-EPT page to hold smaller mappings after the
splitting. Install Dynamic PAMT page pair for the new S-EPT page before
passing the S-EPT page to tdh_mem_page_demote(); Uninstall and free the
Dynamic PAMT page pair when tdh_mem_page_demote() fails.
When Dynamic PAMT is enabled and when there's no installed pair for the 2MB
physical range containing the new S-EPT page, tdx_pamt_get() dequeues a
pair of preallocated pages from the per-VM prealloc_split_cache and
installs them as the Dynamic PAMT page pair. Hold prealloc_split_cache_lock
when dequeuing from the per-VM prealloc_split_cache.
After tdh_mem_page_demote() fails, tdx_pamt_put() uninstalls and frees the
Dynamic PAMT page pair for the new S-EPT page if Dynamic PAMT is enabled,
and the new S-EPT page is the last page in 2MB physical range requiring the
Dynamic PAMT page pair.
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Co-developed-by: Yan Zhao <yan.y.zhao@intel.com>
Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
---
v3:
- Split out as a new patch.
- Add KVM_BUG_ON() after tdx_pamt_get() fails. (Vishal)
---
arch/x86/kvm/vmx/tdx.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 40cca273d480..ec47bd799274 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -1996,6 +1996,7 @@ static int tdx_sept_split_private_spte(struct kvm *kvm, gfn_t gfn, enum pg_level
struct kvm_tdx *kvm_tdx = to_kvm_tdx(kvm);
gpa_t gpa = gfn_to_gpa(gfn);
u64 err, entry, level_state;
+ int ret;
if (KVM_BUG_ON(kvm_tdx->state != TD_STATE_RUNNABLE ||
level != PG_LEVEL_2M, kvm))
@@ -2014,10 +2015,18 @@ static int tdx_sept_split_private_spte(struct kvm *kvm, gfn_t gfn, enum pg_level
tdx_track(kvm);
+ spin_lock(&kvm_tdx->prealloc_split_cache_lock);
+ ret = tdx_pamt_get(new_sept_page, &kvm_tdx->prealloc_split_cache);
+ spin_unlock(&kvm_tdx->prealloc_split_cache_lock);
+ if (KVM_BUG_ON(ret, kvm))
+ return -EIO;
+
err = tdh_do_no_vcpus(tdh_mem_page_demote, kvm, &kvm_tdx->td, gpa,
tdx_level, new_sept_page, &entry, &level_state);
- if (TDX_BUG_ON_2(err, TDH_MEM_PAGE_DEMOTE, entry, level_state, kvm))
+ if (TDX_BUG_ON_2(err, TDH_MEM_PAGE_DEMOTE, entry, level_state, kvm)) {
+ tdx_pamt_put(new_sept_page);
return -EIO;
+ }
return 0;
}
--
2.43.2