Message ID | 20250226181453.2311849-8-pbonzini@redhat.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | TDX initialization + vCPU/VM creation | expand |
On 2/27/2025 2:14 AM, Paolo Bonzini wrote: > From: Rick Edgecombe <rick.p.edgecombe@intel.com> > > Intel TDX protects guest VMs from malicious host and certain physical > attacks. The TDX module uses pages provided by the host for both control > structures and for TD guest pages. These pages are encrypted using the > MK-TME encryption engine, with its special requirements around cache > invalidation. For its own security, the TDX module ensures pages are > flushed properly and track which usage they are currently assigned. For > creating and tearing down TD VMs and vCPUs KVM will need to use the > TDH.PHYMEM.PAGE.RECLAIM, TDH.PHYMEM.CACHE.WB, and TDH.PHYMEM.PAGE.WBINVD > SEAMCALLs. > > Add tdh_phymem_page_reclaim() to enable KVM to call > TDH.PHYMEM.PAGE.RECLAIM to reclaim the page for use by the host kernel. > This effectively resets its state in the TDX module's page tracking > (PAMT), if the page is available to be reclaimed. This will be used by KVM > to reclaim the various types of pages owned by the TDX module. It will > have a small wrapper in KVM that retries in the case of a relevant error > code. Don't implement this wrapper in arch/x86 because KVM's solution > around retrying SEAMCALLs will be better located in a single place. > > Add tdh_phymem_cache_wb() to enable KVM to call TDH.PHYMEM.CACHE.WB to do > a cache write back in a way that the TDX module can verify, before it > allows a KeyID to be freed. The KVM code will use this to have a small > wrapper that handles retries. Since the TDH.PHYMEM.CACHE.WB operation is > interruptible, have tdh_phymem_cache_wb() take a resume argument to pass > this info to the TDX module for restarts. It is worth noting that this > SEAMCALL uses a SEAM specific MSR to do the write back in sections. In > this way it does export some new functionality that affects CPU state. > > Add tdh_phymem_page_wbinvd_tdr() to enable KVM to call > TDH.PHYMEM.PAGE.WBINVD to do a cache write back and invalidate of a TDR, > using the global KeyID. The underlying TDH.PHYMEM.PAGE.WBINVD SEAMCALL > requires the related KeyID to be encoded into the SEAMCALL args. Since the > global KeyID is not exposed to KVM, a dedicated wrapper is needed for TDR > focused TDH.PHYMEM.PAGE.WBINVD operations. > > Co-developed-by: Sean Christopherson <sean.j.christopherson@intel.com> > Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> > Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com> > Signed-off-by: Kai Huang <kai.huang@intel.com> > Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com> > Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com> > Reviewed-by: Yuan Yao <yuan.yao@intel.com> > Message-ID: <20241203010317.827803-5-rick.p.edgecombe@intel.com> > Acked-by: Dave Hansen <dave.hansen@linux.intel.com> > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> > --- > arch/x86/include/asm/tdx.h | 17 +++++++++++++++ > arch/x86/virt/vmx/tdx/tdx.c | 42 +++++++++++++++++++++++++++++++++++++ > arch/x86/virt/vmx/tdx/tdx.h | 3 +++ > 3 files changed, 62 insertions(+) > > diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h > index f783d5f1a0e1..ea26d79ec9d9 100644 > --- a/arch/x86/include/asm/tdx.h > +++ b/arch/x86/include/asm/tdx.h > @@ -33,6 +33,7 @@ > #ifndef __ASSEMBLY__ > > #include <uapi/asm/mce.h> > +#include <linux/pgtable.h> > > /* > * Used by the #VE exception handler to gather the #VE exception > @@ -140,6 +141,19 @@ struct tdx_vp { > struct page **tdcx_pages; > }; > > + > +static inline u64 mk_keyed_paddr(u16 hkid, struct page *page) > +{ > + u64 ret; > + > + ret = page_to_phys(page); We did "make allyesconfig" build test, and see the build error: ./arch/x86/include/asm/tdx.h: In function ‘mk_keyed_paddr’: ./include/asm-generic/memory_model.h:72:23: error: implicit declaration of function ‘pfn_valid’ [-Werror=implicit-function-declaration] 72 | WARN_ON_ONCE(!pfn_valid(__pfn)); \ | ^~~~~~~~~ ./include/asm-generic/bug.h:111:32: note: in definition of macro ‘WARN_ON_ONCE’ 111 | int __ret_warn_on = !!(condition); \ | ^~~~~~~~~ ./arch/x86/include/asm/tdx.h:155:15: note: in expansion of macro ‘page_to_phys’ 155 | ret = page_to_phys(page); | ^~~~~~~~~~~~ Maybe add the fix: diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 847252f520df..428243384696 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -5,6 +5,7 @@ #include <linux/init.h> #include <linux/bits.h> +#include <linux/mmzone.h> #include <asm/errno.h> #include <asm/ptrace.h> > + /* KeyID bits are just above the physical address bits: */ > + ret |= (u64)hkid << boot_cpu_data.x86_phys_bits; > + > + return ret; > + > +}
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index f783d5f1a0e1..ea26d79ec9d9 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -33,6 +33,7 @@ #ifndef __ASSEMBLY__ #include <uapi/asm/mce.h> +#include <linux/pgtable.h> /* * Used by the #VE exception handler to gather the #VE exception @@ -140,6 +141,19 @@ struct tdx_vp { struct page **tdcx_pages; }; + +static inline u64 mk_keyed_paddr(u16 hkid, struct page *page) +{ + u64 ret; + + ret = page_to_phys(page); + /* KeyID bits are just above the physical address bits: */ + ret |= (u64)hkid << boot_cpu_data.x86_phys_bits; + + return ret; + +} + u64 tdh_mng_addcx(struct tdx_td *td, struct page *tdcs_page); u64 tdh_vp_addcx(struct tdx_vp *vp, struct page *tdcx_page); u64 tdh_mng_key_config(struct tdx_td *td); @@ -148,6 +162,9 @@ u64 tdh_vp_create(struct tdx_td *td, struct tdx_vp *vp); u64 tdh_mng_key_freeid(struct tdx_td *td); u64 tdh_mng_init(struct tdx_td *td, u64 td_params, u64 *extended_err); u64 tdh_vp_init(struct tdx_vp *vp, u64 initial_rcx, u32 x2apicid); +u64 tdh_phymem_page_reclaim(struct page *page, u64 *tdx_pt, u64 *tdx_owner, u64 *tdx_size); +u64 tdh_phymem_cache_wb(bool resume); +u64 tdh_phymem_page_wbinvd_tdr(struct tdx_td *td); #else static inline void tdx_init(void) { } static inline int tdx_cpu_enable(void) { return -ENODEV; } diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index e55570575f22..2350d25b4ca3 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -1575,3 +1575,45 @@ u64 tdh_vp_init(struct tdx_vp *vp, u64 initial_rcx, u32 x2apicid) return seamcall(TDH_VP_INIT | (1ULL << TDX_VERSION_SHIFT), &args); } EXPORT_SYMBOL_GPL(tdh_vp_init); + +/* + * TDX ABI defines output operands as PT, OWNER and SIZE. These are TDX defined fomats. + * So despite the names, they must be interpted specially as described by the spec. Return + * them only for error reporting purposes. + */ +u64 tdh_phymem_page_reclaim(struct page *page, u64 *tdx_pt, u64 *tdx_owner, u64 *tdx_size) +{ + struct tdx_module_args args = { + .rcx = page_to_phys(page), + }; + u64 ret; + + ret = seamcall_ret(TDH_PHYMEM_PAGE_RECLAIM, &args); + + *tdx_pt = args.rcx; + *tdx_owner = args.rdx; + *tdx_size = args.r8; + + return ret; +} +EXPORT_SYMBOL_GPL(tdh_phymem_page_reclaim); + +u64 tdh_phymem_cache_wb(bool resume) +{ + struct tdx_module_args args = { + .rcx = resume ? 1 : 0, + }; + + return seamcall(TDH_PHYMEM_CACHE_WB, &args); +} +EXPORT_SYMBOL_GPL(tdh_phymem_cache_wb); + +u64 tdh_phymem_page_wbinvd_tdr(struct tdx_td *td) +{ + struct tdx_module_args args = {}; + + args.rcx = mk_keyed_paddr(tdx_global_keyid, td->tdr_page); + + return seamcall(TDH_PHYMEM_PAGE_WBINVD, &args); +} +EXPORT_SYMBOL_GPL(tdh_phymem_page_wbinvd_tdr); diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index f0464f7d9780..7a15c9afcdfa 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -24,11 +24,14 @@ #define TDH_MNG_INIT 21 #define TDH_VP_INIT 22 #define TDH_PHYMEM_PAGE_RDMD 24 +#define TDH_PHYMEM_PAGE_RECLAIM 28 #define TDH_SYS_KEY_CONFIG 31 #define TDH_SYS_INIT 33 #define TDH_SYS_RD 34 #define TDH_SYS_LP_INIT 35 #define TDH_SYS_TDMR_INIT 36 +#define TDH_PHYMEM_CACHE_WB 40 +#define TDH_PHYMEM_PAGE_WBINVD 41 #define TDH_SYS_CONFIG 45 /*