diff options
Diffstat (limited to 'arch/x86/platform/efi/quirks.c')
-rw-r--r-- | arch/x86/platform/efi/quirks.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c new file mode 100644 index 000000000000..7e3099c610dd --- /dev/null +++ b/arch/x86/platform/efi/quirks.c | |||
@@ -0,0 +1,267 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/string.h> | ||
4 | #include <linux/time.h> | ||
5 | #include <linux/types.h> | ||
6 | #include <linux/efi.h> | ||
7 | #include <linux/slab.h> | ||
8 | #include <linux/memblock.h> | ||
9 | #include <linux/bootmem.h> | ||
10 | #include <asm/efi.h> | ||
11 | #include <asm/uv/uv.h> | ||
12 | |||
13 | #define EFI_MIN_RESERVE 5120 | ||
14 | |||
15 | #define EFI_DUMMY_GUID \ | ||
16 | EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9) | ||
17 | |||
18 | static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 }; | ||
19 | |||
20 | static bool efi_no_storage_paranoia; | ||
21 | |||
22 | /* | ||
23 | * Some firmware implementations refuse to boot if there's insufficient | ||
24 | * space in the variable store. The implementation of garbage collection | ||
25 | * in some FW versions causes stale (deleted) variables to take up space | ||
26 | * longer than intended and space is only freed once the store becomes | ||
27 | * almost completely full. | ||
28 | * | ||
29 | * Enabling this option disables the space checks in | ||
30 | * efi_query_variable_store() and forces garbage collection. | ||
31 | * | ||
32 | * Only enable this option if deleting EFI variables does not free up | ||
33 | * space in your variable store, e.g. if despite deleting variables | ||
34 | * you're unable to create new ones. | ||
35 | */ | ||
36 | static int __init setup_storage_paranoia(char *arg) | ||
37 | { | ||
38 | efi_no_storage_paranoia = true; | ||
39 | return 0; | ||
40 | } | ||
41 | early_param("efi_no_storage_paranoia", setup_storage_paranoia); | ||
42 | |||
43 | /* | ||
44 | * Deleting the dummy variable which kicks off garbage collection | ||
45 | */ | ||
46 | void efi_delete_dummy_variable(void) | ||
47 | { | ||
48 | efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID, | ||
49 | EFI_VARIABLE_NON_VOLATILE | | ||
50 | EFI_VARIABLE_BOOTSERVICE_ACCESS | | ||
51 | EFI_VARIABLE_RUNTIME_ACCESS, | ||
52 | 0, NULL); | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * Some firmware implementations refuse to boot if there's insufficient space | ||
57 | * in the variable store. Ensure that we never use more than a safe limit. | ||
58 | * | ||
59 | * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable | ||
60 | * store. | ||
61 | */ | ||
62 | efi_status_t efi_query_variable_store(u32 attributes, unsigned long size) | ||
63 | { | ||
64 | efi_status_t status; | ||
65 | u64 storage_size, remaining_size, max_size; | ||
66 | |||
67 | if (!(attributes & EFI_VARIABLE_NON_VOLATILE)) | ||
68 | return 0; | ||
69 | |||
70 | status = efi.query_variable_info(attributes, &storage_size, | ||
71 | &remaining_size, &max_size); | ||
72 | if (status != EFI_SUCCESS) | ||
73 | return status; | ||
74 | |||
75 | /* | ||
76 | * We account for that by refusing the write if permitting it would | ||
77 | * reduce the available space to under 5KB. This figure was provided by | ||
78 | * Samsung, so should be safe. | ||
79 | */ | ||
80 | if ((remaining_size - size < EFI_MIN_RESERVE) && | ||
81 | !efi_no_storage_paranoia) { | ||
82 | |||
83 | /* | ||
84 | * Triggering garbage collection may require that the firmware | ||
85 | * generate a real EFI_OUT_OF_RESOURCES error. We can force | ||
86 | * that by attempting to use more space than is available. | ||
87 | */ | ||
88 | unsigned long dummy_size = remaining_size + 1024; | ||
89 | void *dummy = kzalloc(dummy_size, GFP_ATOMIC); | ||
90 | |||
91 | if (!dummy) | ||
92 | return EFI_OUT_OF_RESOURCES; | ||
93 | |||
94 | status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID, | ||
95 | EFI_VARIABLE_NON_VOLATILE | | ||
96 | EFI_VARIABLE_BOOTSERVICE_ACCESS | | ||
97 | EFI_VARIABLE_RUNTIME_ACCESS, | ||
98 | dummy_size, dummy); | ||
99 | |||
100 | if (status == EFI_SUCCESS) { | ||
101 | /* | ||
102 | * This should have failed, so if it didn't make sure | ||
103 | * that we delete it... | ||
104 | */ | ||
105 | efi_delete_dummy_variable(); | ||
106 | } | ||
107 | |||
108 | kfree(dummy); | ||
109 | |||
110 | /* | ||
111 | * The runtime code may now have triggered a garbage collection | ||
112 | * run, so check the variable info again | ||
113 | */ | ||
114 | status = efi.query_variable_info(attributes, &storage_size, | ||
115 | &remaining_size, &max_size); | ||
116 | |||
117 | if (status != EFI_SUCCESS) | ||
118 | return status; | ||
119 | |||
120 | /* | ||
121 | * There still isn't enough room, so return an error | ||
122 | */ | ||
123 | if (remaining_size - size < EFI_MIN_RESERVE) | ||
124 | return EFI_OUT_OF_RESOURCES; | ||
125 | } | ||
126 | |||
127 | return EFI_SUCCESS; | ||
128 | } | ||
129 | EXPORT_SYMBOL_GPL(efi_query_variable_store); | ||
130 | |||
131 | /* | ||
132 | * The UEFI specification makes it clear that the operating system is free to do | ||
133 | * whatever it wants with boot services code after ExitBootServices() has been | ||
134 | * called. Ignoring this recommendation a significant bunch of EFI implementations | ||
135 | * continue calling into boot services code (SetVirtualAddressMap). In order to | ||
136 | * work around such buggy implementations we reserve boot services region during | ||
137 | * EFI init and make sure it stays executable. Then, after SetVirtualAddressMap(), it | ||
138 | * is discarded. | ||
139 | */ | ||
140 | void __init efi_reserve_boot_services(void) | ||
141 | { | ||
142 | void *p; | ||
143 | |||
144 | for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | ||
145 | efi_memory_desc_t *md = p; | ||
146 | u64 start = md->phys_addr; | ||
147 | u64 size = md->num_pages << EFI_PAGE_SHIFT; | ||
148 | |||
149 | if (md->type != EFI_BOOT_SERVICES_CODE && | ||
150 | md->type != EFI_BOOT_SERVICES_DATA) | ||
151 | continue; | ||
152 | /* Only reserve where possible: | ||
153 | * - Not within any already allocated areas | ||
154 | * - Not over any memory area (really needed, if above?) | ||
155 | * - Not within any part of the kernel | ||
156 | * - Not the bios reserved area | ||
157 | */ | ||
158 | if ((start + size > __pa_symbol(_text) | ||
159 | && start <= __pa_symbol(_end)) || | ||
160 | !e820_all_mapped(start, start+size, E820_RAM) || | ||
161 | memblock_is_region_reserved(start, size)) { | ||
162 | /* Could not reserve, skip it */ | ||
163 | md->num_pages = 0; | ||
164 | memblock_dbg("Could not reserve boot range [0x%010llx-0x%010llx]\n", | ||
165 | start, start+size-1); | ||
166 | } else | ||
167 | memblock_reserve(start, size); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | void __init efi_free_boot_services(void) | ||
172 | { | ||
173 | void *p; | ||
174 | |||
175 | for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | ||
176 | efi_memory_desc_t *md = p; | ||
177 | unsigned long long start = md->phys_addr; | ||
178 | unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; | ||
179 | |||
180 | if (md->type != EFI_BOOT_SERVICES_CODE && | ||
181 | md->type != EFI_BOOT_SERVICES_DATA) | ||
182 | continue; | ||
183 | |||
184 | /* Could not reserve boot area */ | ||
185 | if (!size) | ||
186 | continue; | ||
187 | |||
188 | free_bootmem_late(start, size); | ||
189 | } | ||
190 | |||
191 | efi_unmap_memmap(); | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * A number of config table entries get remapped to virtual addresses | ||
196 | * after entering EFI virtual mode. However, the kexec kernel requires | ||
197 | * their physical addresses therefore we pass them via setup_data and | ||
198 | * correct those entries to their respective physical addresses here. | ||
199 | * | ||
200 | * Currently only handles smbios which is necessary for some firmware | ||
201 | * implementation. | ||
202 | */ | ||
203 | int __init efi_reuse_config(u64 tables, int nr_tables) | ||
204 | { | ||
205 | int i, sz, ret = 0; | ||
206 | void *p, *tablep; | ||
207 | struct efi_setup_data *data; | ||
208 | |||
209 | if (!efi_setup) | ||
210 | return 0; | ||
211 | |||
212 | if (!efi_enabled(EFI_64BIT)) | ||
213 | return 0; | ||
214 | |||
215 | data = early_memremap(efi_setup, sizeof(*data)); | ||
216 | if (!data) { | ||
217 | ret = -ENOMEM; | ||
218 | goto out; | ||
219 | } | ||
220 | |||
221 | if (!data->smbios) | ||
222 | goto out_memremap; | ||
223 | |||
224 | sz = sizeof(efi_config_table_64_t); | ||
225 | |||
226 | p = tablep = early_memremap(tables, nr_tables * sz); | ||
227 | if (!p) { | ||
228 | pr_err("Could not map Configuration table!\n"); | ||
229 | ret = -ENOMEM; | ||
230 | goto out_memremap; | ||
231 | } | ||
232 | |||
233 | for (i = 0; i < efi.systab->nr_tables; i++) { | ||
234 | efi_guid_t guid; | ||
235 | |||
236 | guid = ((efi_config_table_64_t *)p)->guid; | ||
237 | |||
238 | if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID)) | ||
239 | ((efi_config_table_64_t *)p)->table = data->smbios; | ||
240 | p += sz; | ||
241 | } | ||
242 | early_iounmap(tablep, nr_tables * sz); | ||
243 | |||
244 | out_memremap: | ||
245 | early_iounmap(data, sizeof(*data)); | ||
246 | out: | ||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | void __init efi_apply_memmap_quirks(void) | ||
251 | { | ||
252 | /* | ||
253 | * Once setup is done earlier, unmap the EFI memory map on mismatched | ||
254 | * firmware/kernel architectures since there is no support for runtime | ||
255 | * services. | ||
256 | */ | ||
257 | if (!efi_runtime_supported()) { | ||
258 | pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n"); | ||
259 | efi_unmap_memmap(); | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * UV doesn't support the new EFI pagetable mapping yet. | ||
264 | */ | ||
265 | if (is_uv_system()) | ||
266 | set_bit(EFI_OLD_MEMMAP, &efi.flags); | ||
267 | } | ||