From: Xiaoyao Li Introduce SEAMCALL wrapper tdh_mem_page_demote() to invoke the SEAMCALL TDH_MEM_PAGE_DEMOTE, which demotes a huge leaf entry to a non-leaf entry in the S-EPT. SEAMCALL TDH_MEM_PAGE_DEMOTE supports the demotion of 2MB or 1GB huge leaf entries. The "gpa" and "level" parameters enable the SEAMCALL TDH_MEM_PAGE_DEMOTE to walk the S-EPT for the huge leaf entry that needs to be demoted. The "page" parameter specifies a 4KB page that will be used in the demotion operation to be added as a page table page in the S-EPT. Invoke tdx_clflush_page() on the 4KB page being added as a page table page. This function performs CLFLUSH operations on certain TDX-capable platforms, or conservatively on all TDX-capable platforms, to prevent dirty cache lines from writing back later and corrupting TD memory. tdh_mem_page_demote() may fail. Callers can check function return value and retrieve extended error info from the function output parameters "ext_err1" and "ext_err2". e.g., due to S-EPT walk error or arriving interrupts. The TDX module has many internal locks. To avoid staying in SEAM mode for too long, SEAMCALLs return a BUSY error code to the kernel instead of spinning on the locks. Depending on the specific SEAMCALL, the caller may need to handle this error in specific ways (e.g., retry). Therefore, return the SEAMCALL error code directly to the caller without attempting to handle it in the core kernel. Do not handle TDX_INTERRUPTED_RESTARTABLE because SEAMCALL TDH_MEM_PAGE_DEMOTE does not check interrupts (including NMIs) for basic TDX (with or without Dynamic PAMT). Signed-off-by: Xiaoyao Li Signed-off-by: Isaku Yamahata Co-developed-by: Yan Zhao Signed-off-by: Yan Zhao --- RFC v2: - Refine the patch log (Rick). - Do not handle TDX_INTERRUPTED_RESTARTABLE as the new TDX modules in planning do not check interrupts for basic TDX. RFC v1: - Rebased and split patch. Updated patch log. --- arch/x86/include/asm/tdx.h | 2 ++ arch/x86/virt/vmx/tdx/tdx.c | 20 ++++++++++++++++++++ arch/x86/virt/vmx/tdx/tdx.h | 1 + 3 files changed, 23 insertions(+) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index f968b736871a..d2cf48e273d5 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -178,6 +178,8 @@ u64 tdh_mng_key_config(struct tdx_td *td); u64 tdh_mng_create(struct tdx_td *td, u16 hkid); u64 tdh_vp_create(struct tdx_td *td, struct tdx_vp *vp); u64 tdh_mng_rd(struct tdx_td *td, u64 field, u64 *data); +u64 tdh_mem_page_demote(struct tdx_td *td, u64 gpa, int level, struct page *page, + u64 *ext_err1, u64 *ext_err2); u64 tdh_mr_extend(struct tdx_td *td, u64 gpa, u64 *ext_err1, u64 *ext_err2); u64 tdh_mr_finalize(struct tdx_td *td); u64 tdh_vp_flush(struct tdx_vp *vp); diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 580f14f64822..d941f083f741 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -1825,6 +1825,26 @@ u64 tdh_mng_rd(struct tdx_td *td, u64 field, u64 *data) } EXPORT_SYMBOL_GPL(tdh_mng_rd); +u64 tdh_mem_page_demote(struct tdx_td *td, u64 gpa, int level, struct page *page, + u64 *ext_err1, u64 *ext_err2) +{ + struct tdx_module_args args = { + .rcx = gpa | level, + .rdx = tdx_tdr_pa(td), + .r8 = page_to_phys(page), + }; + u64 ret; + + tdx_clflush_page(page); + ret = seamcall_ret(TDH_MEM_PAGE_DEMOTE, &args); + + *ext_err1 = args.rcx; + *ext_err2 = args.rdx; + + return ret; +} +EXPORT_SYMBOL_GPL(tdh_mem_page_demote); + u64 tdh_mr_extend(struct tdx_td *td, u64 gpa, u64 *ext_err1, u64 *ext_err2) { struct tdx_module_args args = { diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 096c78a1d438..a6c0fa53ece9 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -24,6 +24,7 @@ #define TDH_MNG_KEY_CONFIG 8 #define TDH_MNG_CREATE 9 #define TDH_MNG_RD 11 +#define TDH_MEM_PAGE_DEMOTE 15 #define TDH_MR_EXTEND 16 #define TDH_MR_FINALIZE 17 #define TDH_VP_FLUSH 18 -- 2.43.2