aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-10-14 10:05:18 -0400
committerIngo Molnar <mingo@kernel.org>2015-10-14 10:05:18 -0400
commitc7d77a7980e434c3af17de19e3348157f9b9ccce (patch)
treeb32c5988ce8239b80c83e94c22d68f5eb0fb84da /drivers/firmware/efi
parent0ce423b6492a02be11662bfaa837dd16945aad3e (diff)
parent8a53554e12e98d1759205afd7b8e9e2ea0936f48 (diff)
Merge branch 'x86/urgent' into core/efi, to pick up a pending EFI fix
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/firmware/efi')
-rw-r--r--drivers/firmware/efi/Kconfig2
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c88
-rw-r--r--drivers/firmware/efi/libstub/efistub.h4
3 files changed, 74 insertions, 20 deletions
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 54071c148340..84533e02fbf8 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -43,7 +43,7 @@ config EFI_VARS_PSTORE_DEFAULT_DISABLE
43 43
44config EFI_RUNTIME_MAP 44config EFI_RUNTIME_MAP
45 bool "Export efi runtime maps to sysfs" 45 bool "Export efi runtime maps to sysfs"
46 depends on X86 && EFI && KEXEC 46 depends on X86 && EFI && KEXEC_CORE
47 default y 47 default y
48 help 48 help
49 Export efi runtime memory maps to /sys/firmware/efi/runtime-map. 49 Export efi runtime memory maps to /sys/firmware/efi/runtime-map.
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index e29560e6b40b..950c87f5d279 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -13,6 +13,7 @@
13 */ 13 */
14 14
15#include <linux/efi.h> 15#include <linux/efi.h>
16#include <linux/sort.h>
16#include <asm/efi.h> 17#include <asm/efi.h>
17 18
18#include "efistub.h" 19#include "efistub.h"
@@ -305,6 +306,44 @@ fail:
305 */ 306 */
306#define EFI_RT_VIRTUAL_BASE 0x40000000 307#define EFI_RT_VIRTUAL_BASE 0x40000000
307 308
309static int cmp_mem_desc(const void *l, const void *r)
310{
311 const efi_memory_desc_t *left = l, *right = r;
312
313 return (left->phys_addr > right->phys_addr) ? 1 : -1;
314}
315
316/*
317 * Returns whether region @left ends exactly where region @right starts,
318 * or false if either argument is NULL.
319 */
320static bool regions_are_adjacent(efi_memory_desc_t *left,
321 efi_memory_desc_t *right)
322{
323 u64 left_end;
324
325 if (left == NULL || right == NULL)
326 return false;
327
328 left_end = left->phys_addr + left->num_pages * EFI_PAGE_SIZE;
329
330 return left_end == right->phys_addr;
331}
332
333/*
334 * Returns whether region @left and region @right have compatible memory type
335 * mapping attributes, and are both EFI_MEMORY_RUNTIME regions.
336 */
337static bool regions_have_compatible_memory_type_attrs(efi_memory_desc_t *left,
338 efi_memory_desc_t *right)
339{
340 static const u64 mem_type_mask = EFI_MEMORY_WB | EFI_MEMORY_WT |
341 EFI_MEMORY_WC | EFI_MEMORY_UC |
342 EFI_MEMORY_RUNTIME;
343
344 return ((left->attribute ^ right->attribute) & mem_type_mask) == 0;
345}
346
308/* 347/*
309 * efi_get_virtmap() - create a virtual mapping for the EFI memory map 348 * efi_get_virtmap() - create a virtual mapping for the EFI memory map
310 * 349 *
@@ -317,33 +356,52 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
317 int *count) 356 int *count)
318{ 357{
319 u64 efi_virt_base = EFI_RT_VIRTUAL_BASE; 358 u64 efi_virt_base = EFI_RT_VIRTUAL_BASE;
320 efi_memory_desc_t *out = runtime_map; 359 efi_memory_desc_t *in, *prev = NULL, *out = runtime_map;
321 int l; 360 int l;
322 361
323 for (l = 0; l < map_size; l += desc_size) { 362 /*
324 efi_memory_desc_t *in = (void *)memory_map + l; 363 * To work around potential issues with the Properties Table feature
364 * introduced in UEFI 2.5, which may split PE/COFF executable images
365 * in memory into several RuntimeServicesCode and RuntimeServicesData
366 * regions, we need to preserve the relative offsets between adjacent
367 * EFI_MEMORY_RUNTIME regions with the same memory type attributes.
368 * The easiest way to find adjacent regions is to sort the memory map
369 * before traversing it.
370 */
371 sort(memory_map, map_size / desc_size, desc_size, cmp_mem_desc, NULL);
372
373 for (l = 0; l < map_size; l += desc_size, prev = in) {
325 u64 paddr, size; 374 u64 paddr, size;
326 375
376 in = (void *)memory_map + l;
327 if (!(in->attribute & EFI_MEMORY_RUNTIME)) 377 if (!(in->attribute & EFI_MEMORY_RUNTIME))
328 continue; 378 continue;
329 379
380 paddr = in->phys_addr;
381 size = in->num_pages * EFI_PAGE_SIZE;
382
330 /* 383 /*
331 * Make the mapping compatible with 64k pages: this allows 384 * Make the mapping compatible with 64k pages: this allows
332 * a 4k page size kernel to kexec a 64k page size kernel and 385 * a 4k page size kernel to kexec a 64k page size kernel and
333 * vice versa. 386 * vice versa.
334 */ 387 */
335 paddr = round_down(in->phys_addr, SZ_64K); 388 if (!regions_are_adjacent(prev, in) ||
336 size = round_up(in->num_pages * EFI_PAGE_SIZE + 389 !regions_have_compatible_memory_type_attrs(prev, in)) {
337 in->phys_addr - paddr, SZ_64K); 390
338 391 paddr = round_down(in->phys_addr, SZ_64K);
339 /* 392 size += in->phys_addr - paddr;
340 * Avoid wasting memory on PTEs by choosing a virtual base that 393
341 * is compatible with section mappings if this region has the 394 /*
342 * appropriate size and physical alignment. (Sections are 2 MB 395 * Avoid wasting memory on PTEs by choosing a virtual
343 * on 4k granule kernels) 396 * base that is compatible with section mappings if this
344 */ 397 * region has the appropriate size and physical
345 if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M) 398 * alignment. (Sections are 2 MB on 4k granule kernels)
346 efi_virt_base = round_up(efi_virt_base, SZ_2M); 399 */
400 if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M)
401 efi_virt_base = round_up(efi_virt_base, SZ_2M);
402 else
403 efi_virt_base = round_up(efi_virt_base, SZ_64K);
404 }
347 405
348 in->virt_addr = efi_virt_base + in->phys_addr - paddr; 406 in->virt_addr = efi_virt_base + in->phys_addr - paddr;
349 efi_virt_base += size; 407 efi_virt_base += size;
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index e334a01cf92f..6b6548fda089 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -5,10 +5,6 @@
5/* error code which can't be mistaken for valid address */ 5/* error code which can't be mistaken for valid address */
6#define EFI_ERROR (~0UL) 6#define EFI_ERROR (~0UL)
7 7
8#undef memcpy
9#undef memset
10#undef memmove
11
12void efi_char16_printk(efi_system_table_t *, efi_char16_t *); 8void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
13 9
14efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, 10efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,