x86/mm, kexec: Fix memory corruption with SME on successive kexecs

After issuing successive kexecs it was found that the SHA hash failed
verification when booting the kexec'd kernel. When SME is enabled, the
change from using pages that were marked encrypted to now being marked as
not encrypted (through new identify mapped page tables) results in memory
corruption if there are any cache entries for the previously encrypted
pages. This is because separate cache entries can exist for the same
physical location but tagged both with and without the encryption bit.

To prevent this, issue a wbinvd if SME is active before copying the pages
from the source location to the destination location to clear any possible
cache entry conflicts.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Cc: <kexec@lists.infradead.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/e7fb8610af3a93e8f8ae6f214cd9249adc0df2b4.1501186516.git.thomas.lendacky@amd.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Tom Lendacky and committed by
Ingo Molnar
4e237903 f90e2d9a

+18 -2
+2 -1
arch/x86/include/asm/kexec.h
··· 147 147 relocate_kernel(unsigned long indirection_page, 148 148 unsigned long page_list, 149 149 unsigned long start_address, 150 - unsigned int preserve_context); 150 + unsigned int preserve_context, 151 + unsigned int sme_active); 151 152 #endif 152 153 153 154 #define ARCH_HAS_KIMAGE_ARCH
+2 -1
arch/x86/kernel/machine_kexec_64.c
··· 335 335 image->start = relocate_kernel((unsigned long)image->head, 336 336 (unsigned long)page_list, 337 337 image->start, 338 - image->preserve_context); 338 + image->preserve_context, 339 + sme_active()); 339 340 340 341 #ifdef CONFIG_KEXEC_JUMP 341 342 if (image->preserve_context)
+14
arch/x86/kernel/relocate_kernel_64.S
··· 47 47 * %rsi page_list 48 48 * %rdx start address 49 49 * %rcx preserve_context 50 + * %r8 sme_active 50 51 */ 51 52 52 53 /* Save the CPU context, used for jumping back */ ··· 71 70 /* zero out flags, and disable interrupts */ 72 71 pushq $0 73 72 popfq 73 + 74 + /* Save SME active flag */ 75 + movq %r8, %r12 74 76 75 77 /* 76 78 * get physical address of control page now ··· 135 131 136 132 /* Flush the TLB (needed?) */ 137 133 movq %r9, %cr3 134 + 135 + /* 136 + * If SME is active, there could be old encrypted cache line 137 + * entries that will conflict with the now unencrypted memory 138 + * used by kexec. Flush the caches before copying the kernel. 139 + */ 140 + testq %r12, %r12 141 + jz 1f 142 + wbinvd 143 + 1: 138 144 139 145 movq %rcx, %r11 140 146 call swap_pages