aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaurabh Tangri <saurabh.tangri@intel.com>2014-06-02 08:18:35 -0400
committerMatt Fleming <matt.fleming@intel.com>2014-06-19 06:14:33 -0400
commiteeb9db09f738993c63ecb5aedf950a1e4fe4bd3f (patch)
tree7204b7099708ec4f0f25faac6ac01797c141ff28
parent7171511eaec5bf23fb06078f59784a3a0626b38f (diff)
x86/efi: Move all workarounds to a separate file quirks.c
Currently, it's difficult to find all the workarounds that are applied when running on EFI, because they're littered throughout various code paths. This change moves all of them into a separate file with the hope that it will be come the single location for all our well documented quirks. Signed-off-by: Saurabh Tangri <saurabh.tangri@intel.com> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--arch/x86/include/asm/efi.h2
-rw-r--r--arch/x86/platform/efi/Makefile2
-rw-r--r--arch/x86/platform/efi/efi.c237
-rw-r--r--arch/x86/platform/efi/quirks.c267
4 files changed, 272 insertions, 236 deletions
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 1eb5f6433ad8..3dbf56eb540d 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -104,6 +104,8 @@ extern void __init runtime_code_page_mkexec(void);
104extern void __init efi_runtime_mkexec(void); 104extern void __init efi_runtime_mkexec(void);
105extern void __init efi_dump_pagetable(void); 105extern void __init efi_dump_pagetable(void);
106extern void __init efi_apply_memmap_quirks(void); 106extern void __init efi_apply_memmap_quirks(void);
107extern int __init efi_reuse_config(u64 tables, int nr_tables);
108extern void efi_delete_dummy_variable(void);
107 109
108struct efi_setup_data { 110struct efi_setup_data {
109 u64 fw_vendor; 111 u64 fw_vendor;
diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
index d51045afcaaf..2846aaab5103 100644
--- a/arch/x86/platform/efi/Makefile
+++ b/arch/x86/platform/efi/Makefile
@@ -1,4 +1,4 @@
1obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o 1obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o
2obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o 2obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
3obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o 3obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
4obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o 4obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 87fc96bcc13c..f8524434bf65 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -56,13 +56,6 @@
56 56
57#define EFI_DEBUG 57#define EFI_DEBUG
58 58
59#define EFI_MIN_RESERVE 5120
60
61#define EFI_DUMMY_GUID \
62 EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9)
63
64static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
65
66struct efi_memory_map memmap; 59struct efi_memory_map memmap;
67 60
68static struct efi efi_phys __initdata; 61static struct efi efi_phys __initdata;
@@ -95,15 +88,6 @@ static int __init setup_add_efi_memmap(char *arg)
95} 88}
96early_param("add_efi_memmap", setup_add_efi_memmap); 89early_param("add_efi_memmap", setup_add_efi_memmap);
97 90
98static bool efi_no_storage_paranoia;
99
100static int __init setup_storage_paranoia(char *arg)
101{
102 efi_no_storage_paranoia = true;
103 return 0;
104}
105early_param("efi_no_storage_paranoia", setup_storage_paranoia);
106
107static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 91static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
108{ 92{
109 unsigned long flags; 93 unsigned long flags;
@@ -392,37 +376,6 @@ static void __init print_efi_memmap(void)
392#endif /* EFI_DEBUG */ 376#endif /* EFI_DEBUG */
393} 377}
394 378
395void __init efi_reserve_boot_services(void)
396{
397 void *p;
398
399 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
400 efi_memory_desc_t *md = p;
401 u64 start = md->phys_addr;
402 u64 size = md->num_pages << EFI_PAGE_SHIFT;
403
404 if (md->type != EFI_BOOT_SERVICES_CODE &&
405 md->type != EFI_BOOT_SERVICES_DATA)
406 continue;
407 /* Only reserve where possible:
408 * - Not within any already allocated areas
409 * - Not over any memory area (really needed, if above?)
410 * - Not within any part of the kernel
411 * - Not the bios reserved area
412 */
413 if ((start + size > __pa_symbol(_text)
414 && start <= __pa_symbol(_end)) ||
415 !e820_all_mapped(start, start+size, E820_RAM) ||
416 memblock_is_region_reserved(start, size)) {
417 /* Could not reserve, skip it */
418 md->num_pages = 0;
419 memblock_dbg("Could not reserve boot range [0x%010llx-0x%010llx]\n",
420 start, start+size-1);
421 } else
422 memblock_reserve(start, size);
423 }
424}
425
426void __init efi_unmap_memmap(void) 379void __init efi_unmap_memmap(void)
427{ 380{
428 clear_bit(EFI_MEMMAP, &efi.flags); 381 clear_bit(EFI_MEMMAP, &efi.flags);
@@ -432,29 +385,6 @@ void __init efi_unmap_memmap(void)
432 } 385 }
433} 386}
434 387
435void __init efi_free_boot_services(void)
436{
437 void *p;
438
439 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
440 efi_memory_desc_t *md = p;
441 unsigned long long start = md->phys_addr;
442 unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
443
444 if (md->type != EFI_BOOT_SERVICES_CODE &&
445 md->type != EFI_BOOT_SERVICES_DATA)
446 continue;
447
448 /* Could not reserve boot area */
449 if (!size)
450 continue;
451
452 free_bootmem_late(start, size);
453 }
454
455 efi_unmap_memmap();
456}
457
458static int __init efi_systab_init(void *phys) 388static int __init efi_systab_init(void *phys)
459{ 389{
460 if (efi_enabled(EFI_64BIT)) { 390 if (efi_enabled(EFI_64BIT)) {
@@ -649,62 +579,6 @@ static int __init efi_memmap_init(void)
649 return 0; 579 return 0;
650} 580}
651 581
652/*
653 * A number of config table entries get remapped to virtual addresses
654 * after entering EFI virtual mode. However, the kexec kernel requires
655 * their physical addresses therefore we pass them via setup_data and
656 * correct those entries to their respective physical addresses here.
657 *
658 * Currently only handles smbios which is necessary for some firmware
659 * implementation.
660 */
661static int __init efi_reuse_config(u64 tables, int nr_tables)
662{
663 int i, sz, ret = 0;
664 void *p, *tablep;
665 struct efi_setup_data *data;
666
667 if (!efi_setup)
668 return 0;
669
670 if (!efi_enabled(EFI_64BIT))
671 return 0;
672
673 data = early_memremap(efi_setup, sizeof(*data));
674 if (!data) {
675 ret = -ENOMEM;
676 goto out;
677 }
678
679 if (!data->smbios)
680 goto out_memremap;
681
682 sz = sizeof(efi_config_table_64_t);
683
684 p = tablep = early_memremap(tables, nr_tables * sz);
685 if (!p) {
686 pr_err("Could not map Configuration table!\n");
687 ret = -ENOMEM;
688 goto out_memremap;
689 }
690
691 for (i = 0; i < efi.systab->nr_tables; i++) {
692 efi_guid_t guid;
693
694 guid = ((efi_config_table_64_t *)p)->guid;
695
696 if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID))
697 ((efi_config_table_64_t *)p)->table = data->smbios;
698 p += sz;
699 }
700 early_iounmap(tablep, nr_tables * sz);
701
702out_memremap:
703 early_iounmap(data, sizeof(*data));
704out:
705 return ret;
706}
707
708void __init efi_init(void) 582void __init efi_init(void)
709{ 583{
710 efi_char16_t *c16; 584 efi_char16_t *c16;
@@ -1057,11 +931,7 @@ static void __init kexec_enter_virtual_mode(void)
1057 runtime_code_page_mkexec(); 931 runtime_code_page_mkexec();
1058 932
1059 /* clean DUMMY object */ 933 /* clean DUMMY object */
1060 efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID, 934 efi_delete_dummy_variable();
1061 EFI_VARIABLE_NON_VOLATILE |
1062 EFI_VARIABLE_BOOTSERVICE_ACCESS |
1063 EFI_VARIABLE_RUNTIME_ACCESS,
1064 0, NULL);
1065#endif 935#endif
1066} 936}
1067 937
@@ -1179,11 +1049,7 @@ static void __init __efi_enter_virtual_mode(void)
1179 free_pages((unsigned long)new_memmap, pg_shift); 1049 free_pages((unsigned long)new_memmap, pg_shift);
1180 1050
1181 /* clean DUMMY object */ 1051 /* clean DUMMY object */
1182 efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID, 1052 efi_delete_dummy_variable();
1183 EFI_VARIABLE_NON_VOLATILE |
1184 EFI_VARIABLE_BOOTSERVICE_ACCESS |
1185 EFI_VARIABLE_RUNTIME_ACCESS,
1186 0, NULL);
1187} 1053}
1188 1054
1189void __init efi_enter_virtual_mode(void) 1055void __init efi_enter_virtual_mode(void)
@@ -1230,86 +1096,6 @@ u64 efi_mem_attributes(unsigned long phys_addr)
1230 return 0; 1096 return 0;
1231} 1097}
1232 1098
1233/*
1234 * Some firmware implementations refuse to boot if there's insufficient space
1235 * in the variable store. Ensure that we never use more than a safe limit.
1236 *
1237 * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
1238 * store.
1239 */
1240efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
1241{
1242 efi_status_t status;
1243 u64 storage_size, remaining_size, max_size;
1244
1245 if (!(attributes & EFI_VARIABLE_NON_VOLATILE))
1246 return 0;
1247
1248 status = efi.query_variable_info(attributes, &storage_size,
1249 &remaining_size, &max_size);
1250 if (status != EFI_SUCCESS)
1251 return status;
1252
1253 /*
1254 * We account for that by refusing the write if permitting it would
1255 * reduce the available space to under 5KB. This figure was provided by
1256 * Samsung, so should be safe.
1257 */
1258 if ((remaining_size - size < EFI_MIN_RESERVE) &&
1259 !efi_no_storage_paranoia) {
1260
1261 /*
1262 * Triggering garbage collection may require that the firmware
1263 * generate a real EFI_OUT_OF_RESOURCES error. We can force
1264 * that by attempting to use more space than is available.
1265 */
1266 unsigned long dummy_size = remaining_size + 1024;
1267 void *dummy = kzalloc(dummy_size, GFP_ATOMIC);
1268
1269 if (!dummy)
1270 return EFI_OUT_OF_RESOURCES;
1271
1272 status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
1273 EFI_VARIABLE_NON_VOLATILE |
1274 EFI_VARIABLE_BOOTSERVICE_ACCESS |
1275 EFI_VARIABLE_RUNTIME_ACCESS,
1276 dummy_size, dummy);
1277
1278 if (status == EFI_SUCCESS) {
1279 /*
1280 * This should have failed, so if it didn't make sure
1281 * that we delete it...
1282 */
1283 efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
1284 EFI_VARIABLE_NON_VOLATILE |
1285 EFI_VARIABLE_BOOTSERVICE_ACCESS |
1286 EFI_VARIABLE_RUNTIME_ACCESS,
1287 0, dummy);
1288 }
1289
1290 kfree(dummy);
1291
1292 /*
1293 * The runtime code may now have triggered a garbage collection
1294 * run, so check the variable info again
1295 */
1296 status = efi.query_variable_info(attributes, &storage_size,
1297 &remaining_size, &max_size);
1298
1299 if (status != EFI_SUCCESS)
1300 return status;
1301
1302 /*
1303 * There still isn't enough room, so return an error
1304 */
1305 if (remaining_size - size < EFI_MIN_RESERVE)
1306 return EFI_OUT_OF_RESOURCES;
1307 }
1308
1309 return EFI_SUCCESS;
1310}
1311EXPORT_SYMBOL_GPL(efi_query_variable_store);
1312
1313static int __init parse_efi_cmdline(char *str) 1099static int __init parse_efi_cmdline(char *str)
1314{ 1100{
1315 if (*str == '=') 1101 if (*str == '=')
@@ -1321,22 +1107,3 @@ static int __init parse_efi_cmdline(char *str)
1321 return 0; 1107 return 0;
1322} 1108}
1323early_param("efi", parse_efi_cmdline); 1109early_param("efi", parse_efi_cmdline);
1324
1325void __init efi_apply_memmap_quirks(void)
1326{
1327 /*
1328 * Once setup is done earlier, unmap the EFI memory map on mismatched
1329 * firmware/kernel architectures since there is no support for runtime
1330 * services.
1331 */
1332 if (!efi_runtime_supported()) {
1333 pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
1334 efi_unmap_memmap();
1335 }
1336
1337 /*
1338 * UV doesn't support the new EFI pagetable mapping yet.
1339 */
1340 if (is_uv_system())
1341 set_bit(EFI_OLD_MEMMAP, &efi.flags);
1342}
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
18static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
19
20static 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 */
36static int __init setup_storage_paranoia(char *arg)
37{
38 efi_no_storage_paranoia = true;
39 return 0;
40}
41early_param("efi_no_storage_paranoia", setup_storage_paranoia);
42
43/*
44 * Deleting the dummy variable which kicks off garbage collection
45*/
46void 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 */
62efi_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}
129EXPORT_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*/
140void __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
171void __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 */
203int __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
244out_memremap:
245 early_iounmap(data, sizeof(*data));
246out:
247 return ret;
248}
249
250void __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}