Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/coco: Add API to handle encryption mask

AMD SME/SEV uses a bit in the page table entries to indicate that the
page is encrypted and not accessible to the VMM.

TDX uses a similar approach, but the polarity of the mask is opposite to
AMD: if the bit is set the page is accessible to VMM.

Provide vendor-neutral API to deal with the mask: cc_mkenc() and
cc_mkdec() modify given address to make it encrypted/decrypted. It can
be applied to phys_addr_t, pgprotval_t or page table entry value.

pgprot_encrypted() and pgprot_decrypted() reimplemented using new
helpers.

The implementation will be extended to cover TDX.

pgprot_decrypted() is used by drivers (i915, virtio_gpu, vfio).
cc_mkdec() called by pgprot_decrypted(). Export cc_mkdec().

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Link: https://lore.kernel.org/r/20220222185740.26228-5-kirill.shutemov@linux.intel.com

authored by

Kirill A. Shutemov and committed by
Borislav Petkov
b577f542 655a0fa3

+56 -8
+27
arch/x86/coco/core.c
··· 14 14 #include <asm/processor.h> 15 15 16 16 static enum cc_vendor vendor __ro_after_init; 17 + static u64 cc_mask __ro_after_init; 17 18 18 19 static bool intel_cc_platform_has(enum cc_attr attr) 19 20 { ··· 85 84 } 86 85 EXPORT_SYMBOL_GPL(cc_platform_has); 87 86 87 + u64 cc_mkenc(u64 val) 88 + { 89 + switch (vendor) { 90 + case CC_VENDOR_AMD: 91 + return val | cc_mask; 92 + default: 93 + return val; 94 + } 95 + } 96 + 97 + u64 cc_mkdec(u64 val) 98 + { 99 + switch (vendor) { 100 + case CC_VENDOR_AMD: 101 + return val & ~cc_mask; 102 + default: 103 + return val; 104 + } 105 + } 106 + EXPORT_SYMBOL_GPL(cc_mkdec); 107 + 88 108 __init void cc_set_vendor(enum cc_vendor v) 89 109 { 90 110 vendor = v; 111 + } 112 + 113 + __init void cc_set_mask(u64 mask) 114 + { 115 + cc_mask = mask; 91 116 }
+18
arch/x86/include/asm/coco.h
··· 2 2 #ifndef _ASM_X86_COCO_H 3 3 #define _ASM_X86_COCO_H 4 4 5 + #include <asm/types.h> 6 + 5 7 enum cc_vendor { 6 8 CC_VENDOR_NONE, 7 9 CC_VENDOR_AMD, ··· 12 10 }; 13 11 14 12 void cc_set_vendor(enum cc_vendor v); 13 + void cc_set_mask(u64 mask); 14 + 15 + #ifdef CONFIG_ARCH_HAS_CC_PLATFORM 16 + u64 cc_mkenc(u64 val); 17 + u64 cc_mkdec(u64 val); 18 + #else 19 + static inline u64 cc_mkenc(u64 val) 20 + { 21 + return val; 22 + } 23 + 24 + static inline u64 cc_mkdec(u64 val) 25 + { 26 + return val; 27 + } 28 + #endif 15 29 16 30 #endif /* _ASM_X86_COCO_H */
+7 -6
arch/x86/include/asm/pgtable.h
··· 15 15 cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS))) \ 16 16 : (prot)) 17 17 18 - /* 19 - * Macros to add or remove encryption attribute 20 - */ 21 - #define pgprot_encrypted(prot) __pgprot(__sme_set(pgprot_val(prot))) 22 - #define pgprot_decrypted(prot) __pgprot(__sme_clr(pgprot_val(prot))) 23 - 24 18 #ifndef __ASSEMBLY__ 25 19 #include <linux/spinlock.h> 26 20 #include <asm/x86_init.h> 27 21 #include <asm/pkru.h> 28 22 #include <asm/fpu/api.h> 23 + #include <asm/coco.h> 29 24 #include <asm-generic/pgtable_uffd.h> 30 25 #include <linux/page_table_check.h> 31 26 ··· 32 37 bool user); 33 38 void ptdump_walk_pgd_level_checkwx(void); 34 39 void ptdump_walk_user_pgd_level_checkwx(void); 40 + 41 + /* 42 + * Macros to add or remove encryption attribute 43 + */ 44 + #define pgprot_encrypted(prot) __pgprot(cc_mkenc(pgprot_val(prot))) 45 + #define pgprot_decrypted(prot) __pgprot(cc_mkdec(pgprot_val(prot))) 35 46 36 47 #ifdef CONFIG_DEBUG_WX 37 48 #define debug_checkwx() ptdump_walk_pgd_level_checkwx()
+1
arch/x86/mm/mem_encrypt_identity.c
··· 604 604 if (sme_me_mask) { 605 605 physical_mask &= ~sme_me_mask; 606 606 cc_set_vendor(CC_VENDOR_AMD); 607 + cc_set_mask(sme_me_mask); 607 608 } 608 609 }
+3 -2
arch/x86/mm/pat/set_memory.c
··· 1989 1989 */ 1990 1990 static int __set_memory_enc_pgtable(unsigned long addr, int numpages, bool enc) 1991 1991 { 1992 + pgprot_t empty = __pgprot(0); 1992 1993 struct cpa_data cpa; 1993 1994 int ret; 1994 1995 ··· 2000 1999 memset(&cpa, 0, sizeof(cpa)); 2001 2000 cpa.vaddr = &addr; 2002 2001 cpa.numpages = numpages; 2003 - cpa.mask_set = enc ? __pgprot(_PAGE_ENC) : __pgprot(0); 2004 - cpa.mask_clr = enc ? __pgprot(0) : __pgprot(_PAGE_ENC); 2002 + cpa.mask_set = enc ? pgprot_encrypted(empty) : pgprot_decrypted(empty); 2003 + cpa.mask_clr = enc ? pgprot_decrypted(empty) : pgprot_encrypted(empty); 2005 2004 cpa.pgd = init_mm.pgd; 2006 2005 2007 2006 /* Must avoid aliasing mappings in the highmem code */