18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AMD Memory Encryption Support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Advanced Micro Devices, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Tom Lendacky <thomas.lendacky@amd.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/linkage.h> 118c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 128c2ecf20Sopenharmony_ci#include <asm/page.h> 138c2ecf20Sopenharmony_ci#include <asm/processor-flags.h> 148c2ecf20Sopenharmony_ci#include <asm/msr-index.h> 158c2ecf20Sopenharmony_ci#include <asm/nospec-branch.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci .text 188c2ecf20Sopenharmony_ci .code64 198c2ecf20Sopenharmony_ciSYM_FUNC_START(sme_encrypt_execute) 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* 228c2ecf20Sopenharmony_ci * Entry parameters: 238c2ecf20Sopenharmony_ci * RDI - virtual address for the encrypted mapping 248c2ecf20Sopenharmony_ci * RSI - virtual address for the decrypted mapping 258c2ecf20Sopenharmony_ci * RDX - length to encrypt 268c2ecf20Sopenharmony_ci * RCX - virtual address of the encryption workarea, including: 278c2ecf20Sopenharmony_ci * - stack page (PAGE_SIZE) 288c2ecf20Sopenharmony_ci * - encryption routine page (PAGE_SIZE) 298c2ecf20Sopenharmony_ci * - intermediate copy buffer (PMD_PAGE_SIZE) 308c2ecf20Sopenharmony_ci * R8 - physcial address of the pagetables to use for encryption 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci push %rbp 348c2ecf20Sopenharmony_ci movq %rsp, %rbp /* RBP now has original stack pointer */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* Set up a one page stack in the non-encrypted memory area */ 378c2ecf20Sopenharmony_ci movq %rcx, %rax /* Workarea stack page */ 388c2ecf20Sopenharmony_ci leaq PAGE_SIZE(%rax), %rsp /* Set new stack pointer */ 398c2ecf20Sopenharmony_ci addq $PAGE_SIZE, %rax /* Workarea encryption routine */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci push %r12 428c2ecf20Sopenharmony_ci movq %rdi, %r10 /* Encrypted area */ 438c2ecf20Sopenharmony_ci movq %rsi, %r11 /* Decrypted area */ 448c2ecf20Sopenharmony_ci movq %rdx, %r12 /* Area length */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* Copy encryption routine into the workarea */ 478c2ecf20Sopenharmony_ci movq %rax, %rdi /* Workarea encryption routine */ 488c2ecf20Sopenharmony_ci leaq __enc_copy(%rip), %rsi /* Encryption routine */ 498c2ecf20Sopenharmony_ci movq $(.L__enc_copy_end - __enc_copy), %rcx /* Encryption routine length */ 508c2ecf20Sopenharmony_ci rep movsb 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* Setup registers for call */ 538c2ecf20Sopenharmony_ci movq %r10, %rdi /* Encrypted area */ 548c2ecf20Sopenharmony_ci movq %r11, %rsi /* Decrypted area */ 558c2ecf20Sopenharmony_ci movq %r8, %rdx /* Pagetables used for encryption */ 568c2ecf20Sopenharmony_ci movq %r12, %rcx /* Area length */ 578c2ecf20Sopenharmony_ci movq %rax, %r8 /* Workarea encryption routine */ 588c2ecf20Sopenharmony_ci addq $PAGE_SIZE, %r8 /* Workarea intermediate copy buffer */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci ANNOTATE_RETPOLINE_SAFE 618c2ecf20Sopenharmony_ci call *%rax /* Call the encryption routine */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci pop %r12 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci movq %rbp, %rsp /* Restore original stack pointer */ 668c2ecf20Sopenharmony_ci pop %rbp 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Offset to __x86_return_thunk would be wrong here */ 698c2ecf20Sopenharmony_ci ANNOTATE_UNRET_SAFE 708c2ecf20Sopenharmony_ci ret 718c2ecf20Sopenharmony_ci int3 728c2ecf20Sopenharmony_ciSYM_FUNC_END(sme_encrypt_execute) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciSYM_FUNC_START(__enc_copy) 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * Routine used to encrypt memory in place. 778c2ecf20Sopenharmony_ci * This routine must be run outside of the kernel proper since 788c2ecf20Sopenharmony_ci * the kernel will be encrypted during the process. So this 798c2ecf20Sopenharmony_ci * routine is defined here and then copied to an area outside 808c2ecf20Sopenharmony_ci * of the kernel where it will remain and run decrypted 818c2ecf20Sopenharmony_ci * during execution. 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * On entry the registers must be: 848c2ecf20Sopenharmony_ci * RDI - virtual address for the encrypted mapping 858c2ecf20Sopenharmony_ci * RSI - virtual address for the decrypted mapping 868c2ecf20Sopenharmony_ci * RDX - address of the pagetables to use for encryption 878c2ecf20Sopenharmony_ci * RCX - length of area 888c2ecf20Sopenharmony_ci * R8 - intermediate copy buffer 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * RAX - points to this routine 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * The area will be encrypted by copying from the non-encrypted 938c2ecf20Sopenharmony_ci * memory space to an intermediate buffer and then copying from the 948c2ecf20Sopenharmony_ci * intermediate buffer back to the encrypted memory space. The physical 958c2ecf20Sopenharmony_ci * addresses of the two mappings are the same which results in the area 968c2ecf20Sopenharmony_ci * being encrypted "in place". 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci /* Enable the new page tables */ 998c2ecf20Sopenharmony_ci mov %rdx, %cr3 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Flush any global TLBs */ 1028c2ecf20Sopenharmony_ci mov %cr4, %rdx 1038c2ecf20Sopenharmony_ci andq $~X86_CR4_PGE, %rdx 1048c2ecf20Sopenharmony_ci mov %rdx, %cr4 1058c2ecf20Sopenharmony_ci orq $X86_CR4_PGE, %rdx 1068c2ecf20Sopenharmony_ci mov %rdx, %cr4 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci push %r15 1098c2ecf20Sopenharmony_ci push %r12 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci movq %rcx, %r9 /* Save area length */ 1128c2ecf20Sopenharmony_ci movq %rdi, %r10 /* Save encrypted area address */ 1138c2ecf20Sopenharmony_ci movq %rsi, %r11 /* Save decrypted area address */ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* Set the PAT register PA5 entry to write-protect */ 1168c2ecf20Sopenharmony_ci movl $MSR_IA32_CR_PAT, %ecx 1178c2ecf20Sopenharmony_ci rdmsr 1188c2ecf20Sopenharmony_ci mov %rdx, %r15 /* Save original PAT value */ 1198c2ecf20Sopenharmony_ci andl $0xffff00ff, %edx /* Clear PA5 */ 1208c2ecf20Sopenharmony_ci orl $0x00000500, %edx /* Set PA5 to WP */ 1218c2ecf20Sopenharmony_ci wrmsr 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci wbinvd /* Invalidate any cache entries */ 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* Copy/encrypt up to 2MB at a time */ 1268c2ecf20Sopenharmony_ci movq $PMD_PAGE_SIZE, %r12 1278c2ecf20Sopenharmony_ci1: 1288c2ecf20Sopenharmony_ci cmpq %r12, %r9 1298c2ecf20Sopenharmony_ci jnb 2f 1308c2ecf20Sopenharmony_ci movq %r9, %r12 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci2: 1338c2ecf20Sopenharmony_ci movq %r11, %rsi /* Source - decrypted area */ 1348c2ecf20Sopenharmony_ci movq %r8, %rdi /* Dest - intermediate copy buffer */ 1358c2ecf20Sopenharmony_ci movq %r12, %rcx 1368c2ecf20Sopenharmony_ci rep movsb 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci movq %r8, %rsi /* Source - intermediate copy buffer */ 1398c2ecf20Sopenharmony_ci movq %r10, %rdi /* Dest - encrypted area */ 1408c2ecf20Sopenharmony_ci movq %r12, %rcx 1418c2ecf20Sopenharmony_ci rep movsb 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci addq %r12, %r11 1448c2ecf20Sopenharmony_ci addq %r12, %r10 1458c2ecf20Sopenharmony_ci subq %r12, %r9 /* Kernel length decrement */ 1468c2ecf20Sopenharmony_ci jnz 1b /* Kernel length not zero? */ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Restore PAT register */ 1498c2ecf20Sopenharmony_ci movl $MSR_IA32_CR_PAT, %ecx 1508c2ecf20Sopenharmony_ci rdmsr 1518c2ecf20Sopenharmony_ci mov %r15, %rdx /* Restore original PAT value */ 1528c2ecf20Sopenharmony_ci wrmsr 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci pop %r12 1558c2ecf20Sopenharmony_ci pop %r15 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* Offset to __x86_return_thunk would be wrong here */ 1588c2ecf20Sopenharmony_ci ANNOTATE_UNRET_SAFE 1598c2ecf20Sopenharmony_ci ret 1608c2ecf20Sopenharmony_ci int3 1618c2ecf20Sopenharmony_ci.L__enc_copy_end: 1628c2ecf20Sopenharmony_ciSYM_FUNC_END(__enc_copy) 163