Messages in this thread Patch in this message | | | From | "Kirill A. Shutemov" <> | Subject | [PATCHv2 22/29] x86/tdx: Make pages shared in ioremap() | Date | Mon, 24 Jan 2022 18:02:08 +0300 |
| |
In TDX guests, guest memory is protected from host access. If a guest performs I/O, it needs to explicitly share the I/O memory with the host.
Make all ioremap()ed pages that are not backed by normal memory (IORES_DESC_NONE or IORES_DESC_RESERVED) mapped as shared.
Since TDX memory encryption support is similar to AMD SEV architecture, reuse the infrastructure from AMD SEV code.
Add tdx_shared_mask() interface to get the TDX guest shared bitmask.
pgprot_decrypted() is used by drivers (i915, virtio_gpu, vfio). Export both pgprot_encrypted() and pgprot_decrypted().
Co-developed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> Reviewed-by: Andi Kleen <ak@linux.intel.com> Reviewed-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> --- arch/x86/include/asm/pgtable.h | 19 +++++++++++++------ arch/x86/include/asm/tdx.h | 4 ++++ arch/x86/kernel/cc_platform.c | 23 +++++++++++++++++++++++ arch/x86/kernel/tdx.c | 9 +++++++++ arch/x86/mm/ioremap.c | 5 +++++ 5 files changed, 54 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 8a9432fb3802..40e22db48319 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -15,12 +15,6 @@ cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS))) \ : (prot)) -/* - * Macros to add or remove encryption attribute - */ -#define pgprot_encrypted(prot) __pgprot(__sme_set(pgprot_val(prot))) -#define pgprot_decrypted(prot) __pgprot(__sme_clr(pgprot_val(prot))) - #ifndef __ASSEMBLY__ #include <linux/spinlock.h> #include <asm/x86_init.h> @@ -38,6 +32,19 @@ void ptdump_walk_pgd_level_debugfs(struct seq_file *m, struct mm_struct *mm, void ptdump_walk_pgd_level_checkwx(void); void ptdump_walk_user_pgd_level_checkwx(void); +/* + * Macros to add or remove encryption attribute + */ +#ifdef CONFIG_ARCH_HAS_CC_PLATFORM +pgprot_t pgprot_encrypted(pgprot_t prot); +pgprot_t pgprot_decrypted(pgprot_t prot); +#define pgprot_encrypted(prot) pgprot_encrypted(prot) +#define pgprot_decrypted(prot) pgprot_decrypted(prot) +#else +#define pgprot_encrypted(prot) (prot) +#define pgprot_decrypted(prot) (prot) +#endif + #ifdef CONFIG_DEBUG_WX #define debug_checkwx() ptdump_walk_pgd_level_checkwx() #define debug_checkwx_user() ptdump_walk_user_pgd_level_checkwx() diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 4bcaadf21dc6..c6a279e67dff 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -55,6 +55,8 @@ void tdx_safe_halt(void); bool tdx_early_handle_ve(struct pt_regs *regs); +phys_addr_t tdx_shared_mask(void); + #else static inline void tdx_early_init(void) { }; @@ -63,6 +65,8 @@ static inline void tdx_safe_halt(void) { }; static inline bool tdx_early_handle_ve(struct pt_regs *regs) { return false; } +static inline phys_addr_t tdx_shared_mask(void) { return 0; } + #endif /* CONFIG_INTEL_TDX_GUEST */ #if defined(CONFIG_KVM_GUEST) && defined(CONFIG_INTEL_TDX_GUEST) diff --git a/arch/x86/kernel/cc_platform.c b/arch/x86/kernel/cc_platform.c index dcb31d6a7554..be8722ad4792 100644 --- a/arch/x86/kernel/cc_platform.c +++ b/arch/x86/kernel/cc_platform.c @@ -12,6 +12,7 @@ #include <linux/mem_encrypt.h> #include <asm/mshyperv.h> +#include <asm/pgtable.h> #include <asm/processor.h> #include <asm/tdx.h> @@ -90,3 +91,25 @@ bool cc_platform_has(enum cc_attr attr) return false; } EXPORT_SYMBOL_GPL(cc_platform_has); + +pgprot_t pgprot_encrypted(pgprot_t prot) +{ + if (sme_me_mask) + return __pgprot(__sme_set(pgprot_val(prot))); + else if (is_tdx_guest()) + return __pgprot(pgprot_val(prot) & ~tdx_shared_mask()); + + return prot; +} +EXPORT_SYMBOL_GPL(pgprot_encrypted); + +pgprot_t pgprot_decrypted(pgprot_t prot) +{ + if (sme_me_mask) + return __pgprot(__sme_clr(pgprot_val(prot))); + else if (is_tdx_guest()) + return __pgprot(pgprot_val(prot) | tdx_shared_mask()); + + return prot; +} +EXPORT_SYMBOL_GPL(pgprot_decrypted); diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c index beeaf61934bc..3bf6621eae7d 100644 --- a/arch/x86/kernel/tdx.c +++ b/arch/x86/kernel/tdx.c @@ -66,6 +66,15 @@ long tdx_kvm_hypercall(unsigned int nr, unsigned long p1, unsigned long p2, EXPORT_SYMBOL_GPL(tdx_kvm_hypercall); #endif +/* + * The highest bit of a guest physical address is the "sharing" bit. + * Set it for shared pages and clear it for private pages. + */ +phys_addr_t tdx_shared_mask(void) +{ + return BIT_ULL(td_info.gpa_width - 1); +} + static void tdx_get_info(void) { struct tdx_module_output out; diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 026031b3b782..a5d4ec1afca2 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -242,10 +242,15 @@ __ioremap_caller(resource_size_t phys_addr, unsigned long size, * If the page being mapped is in memory and SEV is active then * make sure the memory encryption attribute is enabled in the * resulting mapping. + * In TDX guests, memory is marked private by default. If encryption + * is not requested (using encrypted), explicitly set decrypt + * attribute in all IOREMAPPED memory. */ prot = PAGE_KERNEL_IO; if ((io_desc.flags & IORES_MAP_ENCRYPTED) || encrypted) prot = pgprot_encrypted(prot); + else + prot = pgprot_decrypted(prot); switch (pcm) { case _PAGE_CACHE_MODE_UC: -- 2.34.1
| |