On Thu, Feb 16, 2017 at 09:43:58AM -0600, Tom Lendacky wrote: > Add support to be able to either encrypt or decrypt data in place during > the early stages of booting the kernel. This does not change the memory > encryption attribute - it is used for ensuring that data present in either > an encrypted or decrypted memory area is in the proper state (for example > the initrd will have been loaded by the boot loader and will not be > encrypted, but the memory that it resides in is marked as encrypted). > > The early_memmap support is enhanced to specify encrypted and decrypted > mappings with and without write-protection. The use of write-protection is > necessary when encrypting data "in place". The write-protect attribute is > considered cacheable for loads, but not stores. This implies that the > hardware will never give the core a dirty line with this memtype. > > Signed-off-by: Tom Lendacky <thomas.lendacky@xxxxxxx> > --- > arch/x86/include/asm/mem_encrypt.h | 15 +++++++ > arch/x86/mm/mem_encrypt.c | 79 ++++++++++++++++++++++++++++++++++++ > 2 files changed, 94 insertions(+) ... > diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c > index d71df97..ac3565c 100644 > --- a/arch/x86/mm/mem_encrypt.c > +++ b/arch/x86/mm/mem_encrypt.c > @@ -14,6 +14,9 @@ > #include <linux/init.h> > #include <linux/mm.h> > > +#include <asm/tlbflush.h> > +#include <asm/fixmap.h> > + > extern pmdval_t early_pmd_flags; > > /* > @@ -24,6 +27,82 @@ > unsigned long sme_me_mask __section(.data) = 0; > EXPORT_SYMBOL_GPL(sme_me_mask); > > +/* Buffer used for early in-place encryption by BSP, no locking needed */ > +static char sme_early_buffer[PAGE_SIZE] __aligned(PAGE_SIZE); > + > +/* > + * This routine does not change the underlying encryption setting of the > + * page(s) that map this memory. It assumes that eventually the memory is > + * meant to be accessed as either encrypted or decrypted but the contents > + * are currently not in the desired stated. state. > + * > + * This routine follows the steps outlined in the AMD64 Architecture > + * Programmer's Manual Volume 2, Section 7.10.8 Encrypt-in-Place. > + */ > +static void __init __sme_early_enc_dec(resource_size_t paddr, > + unsigned long size, bool enc) > +{ > + void *src, *dst; > + size_t len; > + > + if (!sme_me_mask) > + return; > + > + local_flush_tlb(); > + wbinvd(); > + > + /* > + * There are limited number of early mapping slots, so map (at most) > + * one page at time. > + */ > + while (size) { > + len = min_t(size_t, sizeof(sme_early_buffer), size); > + > + /* > + * Create write protected mappings for the current format write-protected > + * of the memory. > + */ > + src = enc ? early_memremap_decrypted_wp(paddr, len) : > + early_memremap_encrypted_wp(paddr, len); > + > + /* > + * Create mappings for the desired format of the memory. > + */ That comment can go - you already say that in the previous one. > + dst = enc ? early_memremap_encrypted(paddr, len) : > + early_memremap_decrypted(paddr, len); Btw, looking at this again, it seems to me that if you write it this way: if (enc) { src = early_memremap_decrypted_wp(paddr, len); dst = early_memremap_encrypted(paddr, len); } else { src = early_memremap_encrypted_wp(paddr, len); dst = early_memremap_decrypted(paddr, len); } it might become even more readable. Anyway, just an idea - your decision which is better. > + > + /* > + * If a mapping can't be obtained to perform the operation, > + * then eventual access of that area will in the desired s/will // > + * mode will cause a crash. > + */ > + BUG_ON(!src || !dst); > + > + /* > + * Use a temporary buffer, of cache-line multiple size, to > + * avoid data corruption as documented in the APM. > + */ > + memcpy(sme_early_buffer, src, len); > + memcpy(dst, sme_early_buffer, len); > + > + early_memunmap(dst, len); > + early_memunmap(src, len); > + > + paddr += len; > + size -= len; > + } > +} > + > +void __init sme_early_encrypt(resource_size_t paddr, unsigned long size) > +{ > + __sme_early_enc_dec(paddr, size, true); > +} > + > +void __init sme_early_decrypt(resource_size_t paddr, unsigned long size) > +{ > + __sme_early_enc_dec(paddr, size, false); > +} > + > void __init sme_early_init(void) > { > unsigned int i; > > -- Regards/Gruss, Boris. Good mailing practices for 400: avoid top-posting and trim the reply.