]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - arch/x86/mm/mem_encrypt.c
x86/mm: Insure that boot memory areas are mapped properly
[mirror_ubuntu-bionic-kernel.git] / arch / x86 / mm / mem_encrypt.c
CommitLineData
7744ccdb
TL
1/*
2 * AMD Memory Encryption Support
3 *
4 * Copyright (C) 2016 Advanced Micro Devices, Inc.
5 *
6 * Author: Tom Lendacky <thomas.lendacky@amd.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/linkage.h>
5868f365 14#include <linux/init.h>
21729f81 15#include <linux/mm.h>
7744ccdb 16
7f8b7e7f
TL
17#include <asm/tlbflush.h>
18#include <asm/fixmap.h>
b9d05200
TL
19#include <asm/setup.h>
20#include <asm/bootparam.h>
7f8b7e7f 21
7744ccdb
TL
22/*
23 * Since SME related variables are set early in the boot process they must
24 * reside in the .data section so as not to be zeroed out when the .bss
25 * section is later cleared.
26 */
27unsigned long sme_me_mask __section(.data) = 0;
28EXPORT_SYMBOL_GPL(sme_me_mask);
5868f365 29
7f8b7e7f
TL
30/* Buffer used for early in-place encryption by BSP, no locking needed */
31static char sme_early_buffer[PAGE_SIZE] __aligned(PAGE_SIZE);
32
33/*
34 * This routine does not change the underlying encryption setting of the
35 * page(s) that map this memory. It assumes that eventually the memory is
36 * meant to be accessed as either encrypted or decrypted but the contents
37 * are currently not in the desired state.
38 *
39 * This routine follows the steps outlined in the AMD64 Architecture
40 * Programmer's Manual Volume 2, Section 7.10.8 Encrypt-in-Place.
41 */
42static void __init __sme_early_enc_dec(resource_size_t paddr,
43 unsigned long size, bool enc)
44{
45 void *src, *dst;
46 size_t len;
47
48 if (!sme_me_mask)
49 return;
50
51 local_flush_tlb();
52 wbinvd();
53
54 /*
55 * There are limited number of early mapping slots, so map (at most)
56 * one page at time.
57 */
58 while (size) {
59 len = min_t(size_t, sizeof(sme_early_buffer), size);
60
61 /*
62 * Create mappings for the current and desired format of
63 * the memory. Use a write-protected mapping for the source.
64 */
65 src = enc ? early_memremap_decrypted_wp(paddr, len) :
66 early_memremap_encrypted_wp(paddr, len);
67
68 dst = enc ? early_memremap_encrypted(paddr, len) :
69 early_memremap_decrypted(paddr, len);
70
71 /*
72 * If a mapping can't be obtained to perform the operation,
73 * then eventual access of that area in the desired mode
74 * will cause a crash.
75 */
76 BUG_ON(!src || !dst);
77
78 /*
79 * Use a temporary buffer, of cache-line multiple size, to
80 * avoid data corruption as documented in the APM.
81 */
82 memcpy(sme_early_buffer, src, len);
83 memcpy(dst, sme_early_buffer, len);
84
85 early_memunmap(dst, len);
86 early_memunmap(src, len);
87
88 paddr += len;
89 size -= len;
90 }
91}
92
93void __init sme_early_encrypt(resource_size_t paddr, unsigned long size)
94{
95 __sme_early_enc_dec(paddr, size, true);
96}
97
98void __init sme_early_decrypt(resource_size_t paddr, unsigned long size)
99{
100 __sme_early_enc_dec(paddr, size, false);
101}
102
b9d05200
TL
103static void __init __sme_early_map_unmap_mem(void *vaddr, unsigned long size,
104 bool map)
105{
106 unsigned long paddr = (unsigned long)vaddr - __PAGE_OFFSET;
107 pmdval_t pmd_flags, pmd;
108
109 /* Use early_pmd_flags but remove the encryption mask */
110 pmd_flags = __sme_clr(early_pmd_flags);
111
112 do {
113 pmd = map ? (paddr & PMD_MASK) + pmd_flags : 0;
114 __early_make_pgtable((unsigned long)vaddr, pmd);
115
116 vaddr += PMD_SIZE;
117 paddr += PMD_SIZE;
118 size = (size <= PMD_SIZE) ? 0 : size - PMD_SIZE;
119 } while (size);
120
121 __native_flush_tlb();
122}
123
124void __init sme_unmap_bootdata(char *real_mode_data)
125{
126 struct boot_params *boot_data;
127 unsigned long cmdline_paddr;
128
129 if (!sme_active())
130 return;
131
132 /* Get the command line address before unmapping the real_mode_data */
133 boot_data = (struct boot_params *)real_mode_data;
134 cmdline_paddr = boot_data->hdr.cmd_line_ptr | ((u64)boot_data->ext_cmd_line_ptr << 32);
135
136 __sme_early_map_unmap_mem(real_mode_data, sizeof(boot_params), false);
137
138 if (!cmdline_paddr)
139 return;
140
141 __sme_early_map_unmap_mem(__va(cmdline_paddr), COMMAND_LINE_SIZE, false);
142}
143
144void __init sme_map_bootdata(char *real_mode_data)
145{
146 struct boot_params *boot_data;
147 unsigned long cmdline_paddr;
148
149 if (!sme_active())
150 return;
151
152 __sme_early_map_unmap_mem(real_mode_data, sizeof(boot_params), true);
153
154 /* Get the command line address after mapping the real_mode_data */
155 boot_data = (struct boot_params *)real_mode_data;
156 cmdline_paddr = boot_data->hdr.cmd_line_ptr | ((u64)boot_data->ext_cmd_line_ptr << 32);
157
158 if (!cmdline_paddr)
159 return;
160
161 __sme_early_map_unmap_mem(__va(cmdline_paddr), COMMAND_LINE_SIZE, true);
162}
163
21729f81
TL
164void __init sme_early_init(void)
165{
166 unsigned int i;
167
168 if (!sme_me_mask)
169 return;
170
171 early_pmd_flags = __sme_set(early_pmd_flags);
172
173 __supported_pte_mask = __sme_set(__supported_pte_mask);
174
175 /* Update the protection map with memory encryption mask */
176 for (i = 0; i < ARRAY_SIZE(protection_map); i++)
177 protection_map[i] = pgprot_encrypted(protection_map[i]);
178}
179
5868f365
TL
180void __init sme_encrypt_kernel(void)
181{
182}
183
184void __init sme_enable(void)
185{
186}