17ae089eeSArd Biesheuvel // SPDX-License-Identifier: GPL-2.0-only 27ae089eeSArd Biesheuvel /* 37ae089eeSArd Biesheuvel * AMD Memory Encryption Support 47ae089eeSArd Biesheuvel * 57ae089eeSArd Biesheuvel * Copyright (C) 2016 Advanced Micro Devices, Inc. 67ae089eeSArd Biesheuvel * 77ae089eeSArd Biesheuvel * Author: Tom Lendacky <thomas.lendacky@amd.com> 87ae089eeSArd Biesheuvel */ 97ae089eeSArd Biesheuvel 107ae089eeSArd Biesheuvel /* 117ae089eeSArd Biesheuvel * Since we're dealing with identity mappings, physical and virtual 127ae089eeSArd Biesheuvel * addresses are the same, so override these defines which are ultimately 137ae089eeSArd Biesheuvel * used by the headers in misc.h. 147ae089eeSArd Biesheuvel */ 157ae089eeSArd Biesheuvel #define __pa(x) ((unsigned long)(x)) 167ae089eeSArd Biesheuvel #define __va(x) ((void *)((unsigned long)(x))) 177ae089eeSArd Biesheuvel 187ae089eeSArd Biesheuvel /* 197ae089eeSArd Biesheuvel * Special hack: we have to be careful, because no indirections are 207ae089eeSArd Biesheuvel * allowed here, and paravirt_ops is a kind of one. As it will only run in 217ae089eeSArd Biesheuvel * baremetal anyway, we just keep it from happening. (This list needs to 227ae089eeSArd Biesheuvel * be extended when new paravirt and debugging variants are added.) 237ae089eeSArd Biesheuvel */ 247ae089eeSArd Biesheuvel #undef CONFIG_PARAVIRT 257ae089eeSArd Biesheuvel #undef CONFIG_PARAVIRT_XXL 267ae089eeSArd Biesheuvel #undef CONFIG_PARAVIRT_SPINLOCKS 277ae089eeSArd Biesheuvel 287ae089eeSArd Biesheuvel /* 297ae089eeSArd Biesheuvel * This code runs before CPU feature bits are set. By default, the 307ae089eeSArd Biesheuvel * pgtable_l5_enabled() function uses bit X86_FEATURE_LA57 to determine if 317ae089eeSArd Biesheuvel * 5-level paging is active, so that won't work here. USE_EARLY_PGTABLE_L5 327ae089eeSArd Biesheuvel * is provided to handle this situation and, instead, use a variable that 337ae089eeSArd Biesheuvel * has been set by the early boot code. 347ae089eeSArd Biesheuvel */ 357ae089eeSArd Biesheuvel #define USE_EARLY_PGTABLE_L5 367ae089eeSArd Biesheuvel 377ae089eeSArd Biesheuvel #include <linux/kernel.h> 387ae089eeSArd Biesheuvel #include <linux/mm.h> 397ae089eeSArd Biesheuvel #include <linux/mem_encrypt.h> 407ae089eeSArd Biesheuvel #include <linux/cc_platform.h> 417ae089eeSArd Biesheuvel 427ae089eeSArd Biesheuvel #include <asm/init.h> 437ae089eeSArd Biesheuvel #include <asm/setup.h> 447ae089eeSArd Biesheuvel #include <asm/sections.h> 457ae089eeSArd Biesheuvel #include <asm/coco.h> 467ae089eeSArd Biesheuvel #include <asm/sev.h> 477ae089eeSArd Biesheuvel 487ae089eeSArd Biesheuvel #define PGD_FLAGS _KERNPG_TABLE_NOENC 497ae089eeSArd Biesheuvel #define P4D_FLAGS _KERNPG_TABLE_NOENC 507ae089eeSArd Biesheuvel #define PUD_FLAGS _KERNPG_TABLE_NOENC 517ae089eeSArd Biesheuvel #define PMD_FLAGS _KERNPG_TABLE_NOENC 527ae089eeSArd Biesheuvel 537ae089eeSArd Biesheuvel #define PMD_FLAGS_LARGE (__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL) 547ae089eeSArd Biesheuvel 557ae089eeSArd Biesheuvel #define PMD_FLAGS_DEC PMD_FLAGS_LARGE 567ae089eeSArd Biesheuvel #define PMD_FLAGS_DEC_WP ((PMD_FLAGS_DEC & ~_PAGE_LARGE_CACHE_MASK) | \ 577ae089eeSArd Biesheuvel (_PAGE_PAT_LARGE | _PAGE_PWT)) 587ae089eeSArd Biesheuvel 597ae089eeSArd Biesheuvel #define PMD_FLAGS_ENC (PMD_FLAGS_LARGE | _PAGE_ENC) 607ae089eeSArd Biesheuvel 617ae089eeSArd Biesheuvel #define PTE_FLAGS (__PAGE_KERNEL_EXEC & ~_PAGE_GLOBAL) 627ae089eeSArd Biesheuvel 637ae089eeSArd Biesheuvel #define PTE_FLAGS_DEC PTE_FLAGS 647ae089eeSArd Biesheuvel #define PTE_FLAGS_DEC_WP ((PTE_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \ 657ae089eeSArd Biesheuvel (_PAGE_PAT | _PAGE_PWT)) 667ae089eeSArd Biesheuvel 677ae089eeSArd Biesheuvel #define PTE_FLAGS_ENC (PTE_FLAGS | _PAGE_ENC) 687ae089eeSArd Biesheuvel 697ae089eeSArd Biesheuvel struct sme_populate_pgd_data { 707ae089eeSArd Biesheuvel void *pgtable_area; 717ae089eeSArd Biesheuvel pgd_t *pgd; 727ae089eeSArd Biesheuvel 737ae089eeSArd Biesheuvel pmdval_t pmd_flags; 747ae089eeSArd Biesheuvel pteval_t pte_flags; 757ae089eeSArd Biesheuvel unsigned long paddr; 767ae089eeSArd Biesheuvel 777ae089eeSArd Biesheuvel unsigned long vaddr; 787ae089eeSArd Biesheuvel unsigned long vaddr_end; 797ae089eeSArd Biesheuvel }; 807ae089eeSArd Biesheuvel 817ae089eeSArd Biesheuvel /* 827ae089eeSArd Biesheuvel * This work area lives in the .init.scratch section, which lives outside of 837ae089eeSArd Biesheuvel * the kernel proper. It is sized to hold the intermediate copy buffer and 847ae089eeSArd Biesheuvel * more than enough pagetable pages. 857ae089eeSArd Biesheuvel * 867ae089eeSArd Biesheuvel * By using this section, the kernel can be encrypted in place and it 877ae089eeSArd Biesheuvel * avoids any possibility of boot parameters or initramfs images being 887ae089eeSArd Biesheuvel * placed such that the in-place encryption logic overwrites them. This 897ae089eeSArd Biesheuvel * section is 2MB aligned to allow for simple pagetable setup using only 907ae089eeSArd Biesheuvel * PMD entries (see vmlinux.lds.S). 917ae089eeSArd Biesheuvel */ 927ae089eeSArd Biesheuvel static char sme_workarea[2 * PMD_SIZE] __section(".init.scratch"); 937ae089eeSArd Biesheuvel 947ae089eeSArd Biesheuvel static void __head sme_clear_pgd(struct sme_populate_pgd_data *ppd) 957ae089eeSArd Biesheuvel { 967ae089eeSArd Biesheuvel unsigned long pgd_start, pgd_end, pgd_size; 977ae089eeSArd Biesheuvel pgd_t *pgd_p; 987ae089eeSArd Biesheuvel 997ae089eeSArd Biesheuvel pgd_start = ppd->vaddr & PGDIR_MASK; 1007ae089eeSArd Biesheuvel pgd_end = ppd->vaddr_end & PGDIR_MASK; 1017ae089eeSArd Biesheuvel 1027ae089eeSArd Biesheuvel pgd_size = (((pgd_end - pgd_start) / PGDIR_SIZE) + 1) * sizeof(pgd_t); 1037ae089eeSArd Biesheuvel 1047ae089eeSArd Biesheuvel pgd_p = ppd->pgd + pgd_index(ppd->vaddr); 1057ae089eeSArd Biesheuvel 1067ae089eeSArd Biesheuvel memset(pgd_p, 0, pgd_size); 1077ae089eeSArd Biesheuvel } 1087ae089eeSArd Biesheuvel 1097ae089eeSArd Biesheuvel static pud_t __head *sme_prepare_pgd(struct sme_populate_pgd_data *ppd) 1107ae089eeSArd Biesheuvel { 1117ae089eeSArd Biesheuvel pgd_t *pgd; 1127ae089eeSArd Biesheuvel p4d_t *p4d; 1137ae089eeSArd Biesheuvel pud_t *pud; 1147ae089eeSArd Biesheuvel pmd_t *pmd; 1157ae089eeSArd Biesheuvel 1167ae089eeSArd Biesheuvel pgd = ppd->pgd + pgd_index(ppd->vaddr); 1177ae089eeSArd Biesheuvel if (pgd_none(*pgd)) { 1187ae089eeSArd Biesheuvel p4d = ppd->pgtable_area; 1197ae089eeSArd Biesheuvel memset(p4d, 0, sizeof(*p4d) * PTRS_PER_P4D); 1207ae089eeSArd Biesheuvel ppd->pgtable_area += sizeof(*p4d) * PTRS_PER_P4D; 1217ae089eeSArd Biesheuvel set_pgd(pgd, __pgd(PGD_FLAGS | __pa(p4d))); 1227ae089eeSArd Biesheuvel } 1237ae089eeSArd Biesheuvel 1247ae089eeSArd Biesheuvel p4d = p4d_offset(pgd, ppd->vaddr); 1257ae089eeSArd Biesheuvel if (p4d_none(*p4d)) { 1267ae089eeSArd Biesheuvel pud = ppd->pgtable_area; 1277ae089eeSArd Biesheuvel memset(pud, 0, sizeof(*pud) * PTRS_PER_PUD); 1287ae089eeSArd Biesheuvel ppd->pgtable_area += sizeof(*pud) * PTRS_PER_PUD; 1297ae089eeSArd Biesheuvel set_p4d(p4d, __p4d(P4D_FLAGS | __pa(pud))); 1307ae089eeSArd Biesheuvel } 1317ae089eeSArd Biesheuvel 1327ae089eeSArd Biesheuvel pud = pud_offset(p4d, ppd->vaddr); 1337ae089eeSArd Biesheuvel if (pud_none(*pud)) { 1347ae089eeSArd Biesheuvel pmd = ppd->pgtable_area; 1357ae089eeSArd Biesheuvel memset(pmd, 0, sizeof(*pmd) * PTRS_PER_PMD); 1367ae089eeSArd Biesheuvel ppd->pgtable_area += sizeof(*pmd) * PTRS_PER_PMD; 1377ae089eeSArd Biesheuvel set_pud(pud, __pud(PUD_FLAGS | __pa(pmd))); 1387ae089eeSArd Biesheuvel } 1397ae089eeSArd Biesheuvel 1407ae089eeSArd Biesheuvel if (pud_leaf(*pud)) 1417ae089eeSArd Biesheuvel return NULL; 1427ae089eeSArd Biesheuvel 1437ae089eeSArd Biesheuvel return pud; 1447ae089eeSArd Biesheuvel } 1457ae089eeSArd Biesheuvel 1467ae089eeSArd Biesheuvel static void __head sme_populate_pgd_large(struct sme_populate_pgd_data *ppd) 1477ae089eeSArd Biesheuvel { 1487ae089eeSArd Biesheuvel pud_t *pud; 1497ae089eeSArd Biesheuvel pmd_t *pmd; 1507ae089eeSArd Biesheuvel 1517ae089eeSArd Biesheuvel pud = sme_prepare_pgd(ppd); 1527ae089eeSArd Biesheuvel if (!pud) 1537ae089eeSArd Biesheuvel return; 1547ae089eeSArd Biesheuvel 1557ae089eeSArd Biesheuvel pmd = pmd_offset(pud, ppd->vaddr); 1567ae089eeSArd Biesheuvel if (pmd_leaf(*pmd)) 1577ae089eeSArd Biesheuvel return; 1587ae089eeSArd Biesheuvel 1597ae089eeSArd Biesheuvel set_pmd(pmd, __pmd(ppd->paddr | ppd->pmd_flags)); 1607ae089eeSArd Biesheuvel } 1617ae089eeSArd Biesheuvel 1627ae089eeSArd Biesheuvel static void __head sme_populate_pgd(struct sme_populate_pgd_data *ppd) 1637ae089eeSArd Biesheuvel { 1647ae089eeSArd Biesheuvel pud_t *pud; 1657ae089eeSArd Biesheuvel pmd_t *pmd; 1667ae089eeSArd Biesheuvel pte_t *pte; 1677ae089eeSArd Biesheuvel 1687ae089eeSArd Biesheuvel pud = sme_prepare_pgd(ppd); 1697ae089eeSArd Biesheuvel if (!pud) 1707ae089eeSArd Biesheuvel return; 1717ae089eeSArd Biesheuvel 1727ae089eeSArd Biesheuvel pmd = pmd_offset(pud, ppd->vaddr); 1737ae089eeSArd Biesheuvel if (pmd_none(*pmd)) { 1747ae089eeSArd Biesheuvel pte = ppd->pgtable_area; 1757ae089eeSArd Biesheuvel memset(pte, 0, sizeof(*pte) * PTRS_PER_PTE); 1767ae089eeSArd Biesheuvel ppd->pgtable_area += sizeof(*pte) * PTRS_PER_PTE; 1777ae089eeSArd Biesheuvel set_pmd(pmd, __pmd(PMD_FLAGS | __pa(pte))); 1787ae089eeSArd Biesheuvel } 1797ae089eeSArd Biesheuvel 1807ae089eeSArd Biesheuvel if (pmd_leaf(*pmd)) 1817ae089eeSArd Biesheuvel return; 1827ae089eeSArd Biesheuvel 1837ae089eeSArd Biesheuvel pte = pte_offset_kernel(pmd, ppd->vaddr); 1847ae089eeSArd Biesheuvel if (pte_none(*pte)) 1857ae089eeSArd Biesheuvel set_pte(pte, __pte(ppd->paddr | ppd->pte_flags)); 1867ae089eeSArd Biesheuvel } 1877ae089eeSArd Biesheuvel 1887ae089eeSArd Biesheuvel static void __head __sme_map_range_pmd(struct sme_populate_pgd_data *ppd) 1897ae089eeSArd Biesheuvel { 1907ae089eeSArd Biesheuvel while (ppd->vaddr < ppd->vaddr_end) { 1917ae089eeSArd Biesheuvel sme_populate_pgd_large(ppd); 1927ae089eeSArd Biesheuvel 1937ae089eeSArd Biesheuvel ppd->vaddr += PMD_SIZE; 1947ae089eeSArd Biesheuvel ppd->paddr += PMD_SIZE; 1957ae089eeSArd Biesheuvel } 1967ae089eeSArd Biesheuvel } 1977ae089eeSArd Biesheuvel 1987ae089eeSArd Biesheuvel static void __head __sme_map_range_pte(struct sme_populate_pgd_data *ppd) 1997ae089eeSArd Biesheuvel { 2007ae089eeSArd Biesheuvel while (ppd->vaddr < ppd->vaddr_end) { 2017ae089eeSArd Biesheuvel sme_populate_pgd(ppd); 2027ae089eeSArd Biesheuvel 2037ae089eeSArd Biesheuvel ppd->vaddr += PAGE_SIZE; 2047ae089eeSArd Biesheuvel ppd->paddr += PAGE_SIZE; 2057ae089eeSArd Biesheuvel } 2067ae089eeSArd Biesheuvel } 2077ae089eeSArd Biesheuvel 2087ae089eeSArd Biesheuvel static void __head __sme_map_range(struct sme_populate_pgd_data *ppd, 2097ae089eeSArd Biesheuvel pmdval_t pmd_flags, pteval_t pte_flags) 2107ae089eeSArd Biesheuvel { 2117ae089eeSArd Biesheuvel unsigned long vaddr_end; 2127ae089eeSArd Biesheuvel 2137ae089eeSArd Biesheuvel ppd->pmd_flags = pmd_flags; 2147ae089eeSArd Biesheuvel ppd->pte_flags = pte_flags; 2157ae089eeSArd Biesheuvel 2167ae089eeSArd Biesheuvel /* Save original end value since we modify the struct value */ 2177ae089eeSArd Biesheuvel vaddr_end = ppd->vaddr_end; 2187ae089eeSArd Biesheuvel 2197ae089eeSArd Biesheuvel /* If start is not 2MB aligned, create PTE entries */ 2207ae089eeSArd Biesheuvel ppd->vaddr_end = ALIGN(ppd->vaddr, PMD_SIZE); 2217ae089eeSArd Biesheuvel __sme_map_range_pte(ppd); 2227ae089eeSArd Biesheuvel 2237ae089eeSArd Biesheuvel /* Create PMD entries */ 2247ae089eeSArd Biesheuvel ppd->vaddr_end = vaddr_end & PMD_MASK; 2257ae089eeSArd Biesheuvel __sme_map_range_pmd(ppd); 2267ae089eeSArd Biesheuvel 2277ae089eeSArd Biesheuvel /* If end is not 2MB aligned, create PTE entries */ 2287ae089eeSArd Biesheuvel ppd->vaddr_end = vaddr_end; 2297ae089eeSArd Biesheuvel __sme_map_range_pte(ppd); 2307ae089eeSArd Biesheuvel } 2317ae089eeSArd Biesheuvel 2327ae089eeSArd Biesheuvel static void __head sme_map_range_encrypted(struct sme_populate_pgd_data *ppd) 2337ae089eeSArd Biesheuvel { 2347ae089eeSArd Biesheuvel __sme_map_range(ppd, PMD_FLAGS_ENC, PTE_FLAGS_ENC); 2357ae089eeSArd Biesheuvel } 2367ae089eeSArd Biesheuvel 2377ae089eeSArd Biesheuvel static void __head sme_map_range_decrypted(struct sme_populate_pgd_data *ppd) 2387ae089eeSArd Biesheuvel { 2397ae089eeSArd Biesheuvel __sme_map_range(ppd, PMD_FLAGS_DEC, PTE_FLAGS_DEC); 2407ae089eeSArd Biesheuvel } 2417ae089eeSArd Biesheuvel 2427ae089eeSArd Biesheuvel static void __head sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd) 2437ae089eeSArd Biesheuvel { 2447ae089eeSArd Biesheuvel __sme_map_range(ppd, PMD_FLAGS_DEC_WP, PTE_FLAGS_DEC_WP); 2457ae089eeSArd Biesheuvel } 2467ae089eeSArd Biesheuvel 2477ae089eeSArd Biesheuvel static unsigned long __head sme_pgtable_calc(unsigned long len) 2487ae089eeSArd Biesheuvel { 2497ae089eeSArd Biesheuvel unsigned long entries = 0, tables = 0; 2507ae089eeSArd Biesheuvel 2517ae089eeSArd Biesheuvel /* 2527ae089eeSArd Biesheuvel * Perform a relatively simplistic calculation of the pagetable 2537ae089eeSArd Biesheuvel * entries that are needed. Those mappings will be covered mostly 2547ae089eeSArd Biesheuvel * by 2MB PMD entries so we can conservatively calculate the required 2557ae089eeSArd Biesheuvel * number of P4D, PUD and PMD structures needed to perform the 2567ae089eeSArd Biesheuvel * mappings. For mappings that are not 2MB aligned, PTE mappings 2577ae089eeSArd Biesheuvel * would be needed for the start and end portion of the address range 2587ae089eeSArd Biesheuvel * that fall outside of the 2MB alignment. This results in, at most, 2597ae089eeSArd Biesheuvel * two extra pages to hold PTE entries for each range that is mapped. 2607ae089eeSArd Biesheuvel * Incrementing the count for each covers the case where the addresses 2617ae089eeSArd Biesheuvel * cross entries. 2627ae089eeSArd Biesheuvel */ 2637ae089eeSArd Biesheuvel 2647ae089eeSArd Biesheuvel /* PGDIR_SIZE is equal to P4D_SIZE on 4-level machine. */ 2657ae089eeSArd Biesheuvel if (PTRS_PER_P4D > 1) 2667ae089eeSArd Biesheuvel entries += (DIV_ROUND_UP(len, PGDIR_SIZE) + 1) * sizeof(p4d_t) * PTRS_PER_P4D; 2677ae089eeSArd Biesheuvel entries += (DIV_ROUND_UP(len, P4D_SIZE) + 1) * sizeof(pud_t) * PTRS_PER_PUD; 2687ae089eeSArd Biesheuvel entries += (DIV_ROUND_UP(len, PUD_SIZE) + 1) * sizeof(pmd_t) * PTRS_PER_PMD; 2697ae089eeSArd Biesheuvel entries += 2 * sizeof(pte_t) * PTRS_PER_PTE; 2707ae089eeSArd Biesheuvel 2717ae089eeSArd Biesheuvel /* 2727ae089eeSArd Biesheuvel * Now calculate the added pagetable structures needed to populate 2737ae089eeSArd Biesheuvel * the new pagetables. 2747ae089eeSArd Biesheuvel */ 2757ae089eeSArd Biesheuvel 2767ae089eeSArd Biesheuvel if (PTRS_PER_P4D > 1) 2777ae089eeSArd Biesheuvel tables += DIV_ROUND_UP(entries, PGDIR_SIZE) * sizeof(p4d_t) * PTRS_PER_P4D; 2787ae089eeSArd Biesheuvel tables += DIV_ROUND_UP(entries, P4D_SIZE) * sizeof(pud_t) * PTRS_PER_PUD; 2797ae089eeSArd Biesheuvel tables += DIV_ROUND_UP(entries, PUD_SIZE) * sizeof(pmd_t) * PTRS_PER_PMD; 2807ae089eeSArd Biesheuvel 2817ae089eeSArd Biesheuvel return entries + tables; 2827ae089eeSArd Biesheuvel } 2837ae089eeSArd Biesheuvel 2847ae089eeSArd Biesheuvel void __head sme_encrypt_kernel(struct boot_params *bp) 2857ae089eeSArd Biesheuvel { 2867ae089eeSArd Biesheuvel unsigned long workarea_start, workarea_end, workarea_len; 2877ae089eeSArd Biesheuvel unsigned long execute_start, execute_end, execute_len; 2887ae089eeSArd Biesheuvel unsigned long kernel_start, kernel_end, kernel_len; 2897ae089eeSArd Biesheuvel unsigned long initrd_start, initrd_end, initrd_len; 2907ae089eeSArd Biesheuvel struct sme_populate_pgd_data ppd; 2917ae089eeSArd Biesheuvel unsigned long pgtable_area_len; 2927ae089eeSArd Biesheuvel unsigned long decrypted_base; 2937ae089eeSArd Biesheuvel 2947ae089eeSArd Biesheuvel /* 2957ae089eeSArd Biesheuvel * This is early code, use an open coded check for SME instead of 2967ae089eeSArd Biesheuvel * using cc_platform_has(). This eliminates worries about removing 2977ae089eeSArd Biesheuvel * instrumentation or checking boot_cpu_data in the cc_platform_has() 2987ae089eeSArd Biesheuvel * function. 2997ae089eeSArd Biesheuvel */ 300bee174b2SArd Biesheuvel if (!sme_get_me_mask() || sev_status & MSR_AMD64_SEV_ENABLED) 3017ae089eeSArd Biesheuvel return; 3027ae089eeSArd Biesheuvel 3037ae089eeSArd Biesheuvel /* 3047ae089eeSArd Biesheuvel * Prepare for encrypting the kernel and initrd by building new 3057ae089eeSArd Biesheuvel * pagetables with the necessary attributes needed to encrypt the 3067ae089eeSArd Biesheuvel * kernel in place. 3077ae089eeSArd Biesheuvel * 3087ae089eeSArd Biesheuvel * One range of virtual addresses will map the memory occupied 3097ae089eeSArd Biesheuvel * by the kernel and initrd as encrypted. 3107ae089eeSArd Biesheuvel * 3117ae089eeSArd Biesheuvel * Another range of virtual addresses will map the memory occupied 3127ae089eeSArd Biesheuvel * by the kernel and initrd as decrypted and write-protected. 3137ae089eeSArd Biesheuvel * 3147ae089eeSArd Biesheuvel * The use of write-protect attribute will prevent any of the 3157ae089eeSArd Biesheuvel * memory from being cached. 3167ae089eeSArd Biesheuvel */ 3177ae089eeSArd Biesheuvel 3187ae089eeSArd Biesheuvel kernel_start = (unsigned long)rip_rel_ptr(_text); 3197ae089eeSArd Biesheuvel kernel_end = ALIGN((unsigned long)rip_rel_ptr(_end), PMD_SIZE); 3207ae089eeSArd Biesheuvel kernel_len = kernel_end - kernel_start; 3217ae089eeSArd Biesheuvel 3227ae089eeSArd Biesheuvel initrd_start = 0; 3237ae089eeSArd Biesheuvel initrd_end = 0; 3247ae089eeSArd Biesheuvel initrd_len = 0; 3257ae089eeSArd Biesheuvel #ifdef CONFIG_BLK_DEV_INITRD 3267ae089eeSArd Biesheuvel initrd_len = (unsigned long)bp->hdr.ramdisk_size | 3277ae089eeSArd Biesheuvel ((unsigned long)bp->ext_ramdisk_size << 32); 3287ae089eeSArd Biesheuvel if (initrd_len) { 3297ae089eeSArd Biesheuvel initrd_start = (unsigned long)bp->hdr.ramdisk_image | 3307ae089eeSArd Biesheuvel ((unsigned long)bp->ext_ramdisk_image << 32); 3317ae089eeSArd Biesheuvel initrd_end = PAGE_ALIGN(initrd_start + initrd_len); 3327ae089eeSArd Biesheuvel initrd_len = initrd_end - initrd_start; 3337ae089eeSArd Biesheuvel } 3347ae089eeSArd Biesheuvel #endif 3357ae089eeSArd Biesheuvel 3367ae089eeSArd Biesheuvel /* 3377ae089eeSArd Biesheuvel * Calculate required number of workarea bytes needed: 3387ae089eeSArd Biesheuvel * executable encryption area size: 3397ae089eeSArd Biesheuvel * stack page (PAGE_SIZE) 3407ae089eeSArd Biesheuvel * encryption routine page (PAGE_SIZE) 3417ae089eeSArd Biesheuvel * intermediate copy buffer (PMD_SIZE) 3427ae089eeSArd Biesheuvel * pagetable structures for the encryption of the kernel 3437ae089eeSArd Biesheuvel * pagetable structures for workarea (in case not currently mapped) 3447ae089eeSArd Biesheuvel */ 3457ae089eeSArd Biesheuvel execute_start = workarea_start = (unsigned long)rip_rel_ptr(sme_workarea); 3467ae089eeSArd Biesheuvel execute_end = execute_start + (PAGE_SIZE * 2) + PMD_SIZE; 3477ae089eeSArd Biesheuvel execute_len = execute_end - execute_start; 3487ae089eeSArd Biesheuvel 3497ae089eeSArd Biesheuvel /* 3507ae089eeSArd Biesheuvel * One PGD for both encrypted and decrypted mappings and a set of 3517ae089eeSArd Biesheuvel * PUDs and PMDs for each of the encrypted and decrypted mappings. 3527ae089eeSArd Biesheuvel */ 3537ae089eeSArd Biesheuvel pgtable_area_len = sizeof(pgd_t) * PTRS_PER_PGD; 3547ae089eeSArd Biesheuvel pgtable_area_len += sme_pgtable_calc(execute_end - kernel_start) * 2; 3557ae089eeSArd Biesheuvel if (initrd_len) 3567ae089eeSArd Biesheuvel pgtable_area_len += sme_pgtable_calc(initrd_len) * 2; 3577ae089eeSArd Biesheuvel 3587ae089eeSArd Biesheuvel /* PUDs and PMDs needed in the current pagetables for the workarea */ 3597ae089eeSArd Biesheuvel pgtable_area_len += sme_pgtable_calc(execute_len + pgtable_area_len); 3607ae089eeSArd Biesheuvel 3617ae089eeSArd Biesheuvel /* 3627ae089eeSArd Biesheuvel * The total workarea includes the executable encryption area and 3637ae089eeSArd Biesheuvel * the pagetable area. The start of the workarea is already 2MB 3647ae089eeSArd Biesheuvel * aligned, align the end of the workarea on a 2MB boundary so that 3657ae089eeSArd Biesheuvel * we don't try to create/allocate PTE entries from the workarea 3667ae089eeSArd Biesheuvel * before it is mapped. 3677ae089eeSArd Biesheuvel */ 3687ae089eeSArd Biesheuvel workarea_len = execute_len + pgtable_area_len; 3697ae089eeSArd Biesheuvel workarea_end = ALIGN(workarea_start + workarea_len, PMD_SIZE); 3707ae089eeSArd Biesheuvel 3717ae089eeSArd Biesheuvel /* 3727ae089eeSArd Biesheuvel * Set the address to the start of where newly created pagetable 3737ae089eeSArd Biesheuvel * structures (PGDs, PUDs and PMDs) will be allocated. New pagetable 3747ae089eeSArd Biesheuvel * structures are created when the workarea is added to the current 3757ae089eeSArd Biesheuvel * pagetables and when the new encrypted and decrypted kernel 3767ae089eeSArd Biesheuvel * mappings are populated. 3777ae089eeSArd Biesheuvel */ 3787ae089eeSArd Biesheuvel ppd.pgtable_area = (void *)execute_end; 3797ae089eeSArd Biesheuvel 3807ae089eeSArd Biesheuvel /* 3817ae089eeSArd Biesheuvel * Make sure the current pagetable structure has entries for 3827ae089eeSArd Biesheuvel * addressing the workarea. 3837ae089eeSArd Biesheuvel */ 3847ae089eeSArd Biesheuvel ppd.pgd = (pgd_t *)native_read_cr3_pa(); 3857ae089eeSArd Biesheuvel ppd.paddr = workarea_start; 3867ae089eeSArd Biesheuvel ppd.vaddr = workarea_start; 3877ae089eeSArd Biesheuvel ppd.vaddr_end = workarea_end; 3887ae089eeSArd Biesheuvel sme_map_range_decrypted(&ppd); 3897ae089eeSArd Biesheuvel 3907ae089eeSArd Biesheuvel /* Flush the TLB - no globals so cr3 is enough */ 3917ae089eeSArd Biesheuvel native_write_cr3(__native_read_cr3()); 3927ae089eeSArd Biesheuvel 3937ae089eeSArd Biesheuvel /* 3947ae089eeSArd Biesheuvel * A new pagetable structure is being built to allow for the kernel 3957ae089eeSArd Biesheuvel * and initrd to be encrypted. It starts with an empty PGD that will 3967ae089eeSArd Biesheuvel * then be populated with new PUDs and PMDs as the encrypted and 3977ae089eeSArd Biesheuvel * decrypted kernel mappings are created. 3987ae089eeSArd Biesheuvel */ 3997ae089eeSArd Biesheuvel ppd.pgd = ppd.pgtable_area; 4007ae089eeSArd Biesheuvel memset(ppd.pgd, 0, sizeof(pgd_t) * PTRS_PER_PGD); 4017ae089eeSArd Biesheuvel ppd.pgtable_area += sizeof(pgd_t) * PTRS_PER_PGD; 4027ae089eeSArd Biesheuvel 4037ae089eeSArd Biesheuvel /* 4047ae089eeSArd Biesheuvel * A different PGD index/entry must be used to get different 4057ae089eeSArd Biesheuvel * pagetable entries for the decrypted mapping. Choose the next 4067ae089eeSArd Biesheuvel * PGD index and convert it to a virtual address to be used as 4077ae089eeSArd Biesheuvel * the base of the mapping. 4087ae089eeSArd Biesheuvel */ 4097ae089eeSArd Biesheuvel decrypted_base = (pgd_index(workarea_end) + 1) & (PTRS_PER_PGD - 1); 4107ae089eeSArd Biesheuvel if (initrd_len) { 4117ae089eeSArd Biesheuvel unsigned long check_base; 4127ae089eeSArd Biesheuvel 4137ae089eeSArd Biesheuvel check_base = (pgd_index(initrd_end) + 1) & (PTRS_PER_PGD - 1); 4147ae089eeSArd Biesheuvel decrypted_base = max(decrypted_base, check_base); 4157ae089eeSArd Biesheuvel } 4167ae089eeSArd Biesheuvel decrypted_base <<= PGDIR_SHIFT; 4177ae089eeSArd Biesheuvel 4187ae089eeSArd Biesheuvel /* Add encrypted kernel (identity) mappings */ 4197ae089eeSArd Biesheuvel ppd.paddr = kernel_start; 4207ae089eeSArd Biesheuvel ppd.vaddr = kernel_start; 4217ae089eeSArd Biesheuvel ppd.vaddr_end = kernel_end; 4227ae089eeSArd Biesheuvel sme_map_range_encrypted(&ppd); 4237ae089eeSArd Biesheuvel 4247ae089eeSArd Biesheuvel /* Add decrypted, write-protected kernel (non-identity) mappings */ 4257ae089eeSArd Biesheuvel ppd.paddr = kernel_start; 4267ae089eeSArd Biesheuvel ppd.vaddr = kernel_start + decrypted_base; 4277ae089eeSArd Biesheuvel ppd.vaddr_end = kernel_end + decrypted_base; 4287ae089eeSArd Biesheuvel sme_map_range_decrypted_wp(&ppd); 4297ae089eeSArd Biesheuvel 4307ae089eeSArd Biesheuvel if (initrd_len) { 4317ae089eeSArd Biesheuvel /* Add encrypted initrd (identity) mappings */ 4327ae089eeSArd Biesheuvel ppd.paddr = initrd_start; 4337ae089eeSArd Biesheuvel ppd.vaddr = initrd_start; 4347ae089eeSArd Biesheuvel ppd.vaddr_end = initrd_end; 4357ae089eeSArd Biesheuvel sme_map_range_encrypted(&ppd); 4367ae089eeSArd Biesheuvel /* 4377ae089eeSArd Biesheuvel * Add decrypted, write-protected initrd (non-identity) mappings 4387ae089eeSArd Biesheuvel */ 4397ae089eeSArd Biesheuvel ppd.paddr = initrd_start; 4407ae089eeSArd Biesheuvel ppd.vaddr = initrd_start + decrypted_base; 4417ae089eeSArd Biesheuvel ppd.vaddr_end = initrd_end + decrypted_base; 4427ae089eeSArd Biesheuvel sme_map_range_decrypted_wp(&ppd); 4437ae089eeSArd Biesheuvel } 4447ae089eeSArd Biesheuvel 4457ae089eeSArd Biesheuvel /* Add decrypted workarea mappings to both kernel mappings */ 4467ae089eeSArd Biesheuvel ppd.paddr = workarea_start; 4477ae089eeSArd Biesheuvel ppd.vaddr = workarea_start; 4487ae089eeSArd Biesheuvel ppd.vaddr_end = workarea_end; 4497ae089eeSArd Biesheuvel sme_map_range_decrypted(&ppd); 4507ae089eeSArd Biesheuvel 4517ae089eeSArd Biesheuvel ppd.paddr = workarea_start; 4527ae089eeSArd Biesheuvel ppd.vaddr = workarea_start + decrypted_base; 4537ae089eeSArd Biesheuvel ppd.vaddr_end = workarea_end + decrypted_base; 4547ae089eeSArd Biesheuvel sme_map_range_decrypted(&ppd); 4557ae089eeSArd Biesheuvel 4567ae089eeSArd Biesheuvel /* Perform the encryption */ 4577ae089eeSArd Biesheuvel sme_encrypt_execute(kernel_start, kernel_start + decrypted_base, 4587ae089eeSArd Biesheuvel kernel_len, workarea_start, (unsigned long)ppd.pgd); 4597ae089eeSArd Biesheuvel 4607ae089eeSArd Biesheuvel if (initrd_len) 4617ae089eeSArd Biesheuvel sme_encrypt_execute(initrd_start, initrd_start + decrypted_base, 4627ae089eeSArd Biesheuvel initrd_len, workarea_start, 4637ae089eeSArd Biesheuvel (unsigned long)ppd.pgd); 4647ae089eeSArd Biesheuvel 4657ae089eeSArd Biesheuvel /* 4667ae089eeSArd Biesheuvel * At this point we are running encrypted. Remove the mappings for 4677ae089eeSArd Biesheuvel * the decrypted areas - all that is needed for this is to remove 4687ae089eeSArd Biesheuvel * the PGD entry/entries. 4697ae089eeSArd Biesheuvel */ 4707ae089eeSArd Biesheuvel ppd.vaddr = kernel_start + decrypted_base; 4717ae089eeSArd Biesheuvel ppd.vaddr_end = kernel_end + decrypted_base; 4727ae089eeSArd Biesheuvel sme_clear_pgd(&ppd); 4737ae089eeSArd Biesheuvel 4747ae089eeSArd Biesheuvel if (initrd_len) { 4757ae089eeSArd Biesheuvel ppd.vaddr = initrd_start + decrypted_base; 4767ae089eeSArd Biesheuvel ppd.vaddr_end = initrd_end + decrypted_base; 4777ae089eeSArd Biesheuvel sme_clear_pgd(&ppd); 4787ae089eeSArd Biesheuvel } 4797ae089eeSArd Biesheuvel 4807ae089eeSArd Biesheuvel ppd.vaddr = workarea_start + decrypted_base; 4817ae089eeSArd Biesheuvel ppd.vaddr_end = workarea_end + decrypted_base; 4827ae089eeSArd Biesheuvel sme_clear_pgd(&ppd); 4837ae089eeSArd Biesheuvel 4847ae089eeSArd Biesheuvel /* Flush the TLB - no globals so cr3 is enough */ 4857ae089eeSArd Biesheuvel native_write_cr3(__native_read_cr3()); 4867ae089eeSArd Biesheuvel } 4877ae089eeSArd Biesheuvel 4887ae089eeSArd Biesheuvel void __head sme_enable(struct boot_params *bp) 4897ae089eeSArd Biesheuvel { 4907ae089eeSArd Biesheuvel unsigned int eax, ebx, ecx, edx; 4917ae089eeSArd Biesheuvel unsigned long feature_mask; 4927ae089eeSArd Biesheuvel unsigned long me_mask; 4937ae089eeSArd Biesheuvel bool snp_en; 4947ae089eeSArd Biesheuvel u64 msr; 4957ae089eeSArd Biesheuvel 4967ae089eeSArd Biesheuvel snp_en = snp_init(bp); 4977ae089eeSArd Biesheuvel 4987ae089eeSArd Biesheuvel /* Check for the SME/SEV support leaf */ 4997ae089eeSArd Biesheuvel eax = 0x80000000; 5007ae089eeSArd Biesheuvel ecx = 0; 5017ae089eeSArd Biesheuvel native_cpuid(&eax, &ebx, &ecx, &edx); 5027ae089eeSArd Biesheuvel if (eax < 0x8000001f) 5037ae089eeSArd Biesheuvel return; 5047ae089eeSArd Biesheuvel 5057ae089eeSArd Biesheuvel #define AMD_SME_BIT BIT(0) 5067ae089eeSArd Biesheuvel #define AMD_SEV_BIT BIT(1) 5077ae089eeSArd Biesheuvel 5087ae089eeSArd Biesheuvel /* 5097ae089eeSArd Biesheuvel * Check for the SME/SEV feature: 5107ae089eeSArd Biesheuvel * CPUID Fn8000_001F[EAX] 5117ae089eeSArd Biesheuvel * - Bit 0 - Secure Memory Encryption support 5127ae089eeSArd Biesheuvel * - Bit 1 - Secure Encrypted Virtualization support 5137ae089eeSArd Biesheuvel * CPUID Fn8000_001F[EBX] 5147ae089eeSArd Biesheuvel * - Bits 5:0 - Pagetable bit position used to indicate encryption 5157ae089eeSArd Biesheuvel */ 5167ae089eeSArd Biesheuvel eax = 0x8000001f; 5177ae089eeSArd Biesheuvel ecx = 0; 5187ae089eeSArd Biesheuvel native_cpuid(&eax, &ebx, &ecx, &edx); 5197ae089eeSArd Biesheuvel /* Check whether SEV or SME is supported */ 5207ae089eeSArd Biesheuvel if (!(eax & (AMD_SEV_BIT | AMD_SME_BIT))) 5217ae089eeSArd Biesheuvel return; 5227ae089eeSArd Biesheuvel 5237ae089eeSArd Biesheuvel me_mask = 1UL << (ebx & 0x3f); 5247ae089eeSArd Biesheuvel 5257ae089eeSArd Biesheuvel /* Check the SEV MSR whether SEV or SME is enabled */ 526*1f82e8e1SIngo Molnar sev_status = msr = native_rdmsrq(MSR_AMD64_SEV); 5277ae089eeSArd Biesheuvel feature_mask = (msr & MSR_AMD64_SEV_ENABLED) ? AMD_SEV_BIT : AMD_SME_BIT; 5287ae089eeSArd Biesheuvel 5297ae089eeSArd Biesheuvel /* 5307ae089eeSArd Biesheuvel * Any discrepancies between the presence of a CC blob and SNP 5317ae089eeSArd Biesheuvel * enablement abort the guest. 5327ae089eeSArd Biesheuvel */ 5337ae089eeSArd Biesheuvel if (snp_en ^ !!(msr & MSR_AMD64_SEV_SNP_ENABLED)) 5347ae089eeSArd Biesheuvel snp_abort(); 5357ae089eeSArd Biesheuvel 5367ae089eeSArd Biesheuvel /* Check if memory encryption is enabled */ 5377ae089eeSArd Biesheuvel if (feature_mask == AMD_SME_BIT) { 5387ae089eeSArd Biesheuvel if (!(bp->hdr.xloadflags & XLF_MEM_ENCRYPTION)) 5397ae089eeSArd Biesheuvel return; 5407ae089eeSArd Biesheuvel 5417ae089eeSArd Biesheuvel /* 5427ae089eeSArd Biesheuvel * No SME if Hypervisor bit is set. This check is here to 5437ae089eeSArd Biesheuvel * prevent a guest from trying to enable SME. For running as a 5447ae089eeSArd Biesheuvel * KVM guest the MSR_AMD64_SYSCFG will be sufficient, but there 5457ae089eeSArd Biesheuvel * might be other hypervisors which emulate that MSR as non-zero 5467ae089eeSArd Biesheuvel * or even pass it through to the guest. 5477ae089eeSArd Biesheuvel * A malicious hypervisor can still trick a guest into this 5487ae089eeSArd Biesheuvel * path, but there is no way to protect against that. 5497ae089eeSArd Biesheuvel */ 5507ae089eeSArd Biesheuvel eax = 1; 5517ae089eeSArd Biesheuvel ecx = 0; 5527ae089eeSArd Biesheuvel native_cpuid(&eax, &ebx, &ecx, &edx); 5537ae089eeSArd Biesheuvel if (ecx & BIT(31)) 5547ae089eeSArd Biesheuvel return; 5557ae089eeSArd Biesheuvel 5567ae089eeSArd Biesheuvel /* For SME, check the SYSCFG MSR */ 557*1f82e8e1SIngo Molnar msr = native_rdmsrq(MSR_AMD64_SYSCFG); 5587ae089eeSArd Biesheuvel if (!(msr & MSR_AMD64_SYSCFG_MEM_ENCRYPT)) 5597ae089eeSArd Biesheuvel return; 5607ae089eeSArd Biesheuvel } 5617ae089eeSArd Biesheuvel 562bee174b2SArd Biesheuvel sme_me_mask = me_mask; 563bee174b2SArd Biesheuvel physical_mask &= ~me_mask; 564bee174b2SArd Biesheuvel cc_vendor = CC_VENDOR_AMD; 5657ae089eeSArd Biesheuvel cc_set_mask(me_mask); 5667ae089eeSArd Biesheuvel } 5675297886fSArd Biesheuvel 5685297886fSArd Biesheuvel #ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION 5695297886fSArd Biesheuvel /* Local version for startup code, which never operates on user page tables */ 5705297886fSArd Biesheuvel __weak 5715297886fSArd Biesheuvel pgd_t __pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd) 5725297886fSArd Biesheuvel { 5735297886fSArd Biesheuvel return pgd; 5745297886fSArd Biesheuvel } 5755297886fSArd Biesheuvel #endif 576