2019-02-02 17:41:15 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2015-11-30 20:28:18 +08:00
|
|
|
/*
|
|
|
|
* Extensible Firmware Interface
|
|
|
|
*
|
|
|
|
* Based on Extensible Firmware Interface Specification version 2.4
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013, 2014 Linaro Ltd.
|
|
|
|
*/
|
|
|
|
|
2017-06-02 21:52:07 +08:00
|
|
|
#include <linux/dmi.h>
|
2015-11-30 20:28:18 +08:00
|
|
|
#include <linux/efi.h>
|
2015-11-30 20:28:19 +08:00
|
|
|
#include <linux/io.h>
|
2015-11-30 20:28:18 +08:00
|
|
|
#include <linux/memblock.h>
|
|
|
|
#include <linux/mm_types.h>
|
|
|
|
#include <linux/preempt.h>
|
|
|
|
#include <linux/rbtree.h>
|
|
|
|
#include <linux/rwsem.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/spinlock.h>
|
2020-06-09 12:32:42 +08:00
|
|
|
#include <linux/pgtable.h>
|
2015-11-30 20:28:18 +08:00
|
|
|
|
|
|
|
#include <asm/cacheflush.h>
|
|
|
|
#include <asm/efi.h>
|
|
|
|
#include <asm/mmu.h>
|
2015-11-30 20:28:19 +08:00
|
|
|
#include <asm/pgalloc.h>
|
2015-11-30 20:28:18 +08:00
|
|
|
|
2020-02-04 09:36:29 +08:00
|
|
|
#if defined(CONFIG_PTDUMP_DEBUGFS) && defined(CONFIG_ARM64)
|
2016-08-16 20:13:21 +08:00
|
|
|
#include <asm/ptdump.h>
|
|
|
|
|
|
|
|
static struct ptdump_info efi_ptdump_info = {
|
|
|
|
.mm = &efi_mm,
|
|
|
|
.markers = (struct addr_marker[]){
|
2019-02-02 17:50:17 +08:00
|
|
|
{ 0, "UEFI runtime start" },
|
|
|
|
{ DEFAULT_MAP_WINDOW_64, "UEFI runtime end" },
|
|
|
|
{ -1, NULL }
|
2016-08-16 20:13:21 +08:00
|
|
|
},
|
|
|
|
.base_addr = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init ptdump_init(void)
|
|
|
|
{
|
2019-02-02 03:20:01 +08:00
|
|
|
if (efi_enabled(EFI_RUNTIME_SERVICES))
|
|
|
|
ptdump_debugfs_register(&efi_ptdump_info, "efi_page_tables");
|
efi/arm*: Only register page tables when they exist
Currently the arm/arm64 runtime code registers the runtime servies
pagetables with ptdump regardless of whether runtime services page
tables have been created.
As efi_mm.pgd is NULL in these cases, attempting to dump the efi page
tables results in a NULL pointer dereference in the ptdump code:
/sys/kernel/debug# cat efi_page_tables
[ 479.522600] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[ 479.522715] Mem abort info:
[ 479.522764] ESR = 0x96000006
[ 479.522850] Exception class = DABT (current EL), IL = 32 bits
[ 479.522899] SET = 0, FnV = 0
[ 479.522937] EA = 0, S1PTW = 0
[ 479.528200] Data abort info:
[ 479.528230] ISV = 0, ISS = 0x00000006
[ 479.528317] CM = 0, WnR = 0
[ 479.528317] user pgtable: 4k pages, 48-bit VAs, pgd = 0000000064ab0cb0
[ 479.528449] [0000000000000000] *pgd=00000000fbbe4003, *pud=00000000fb66e003, *pmd=0000000000000000
[ 479.528600] Internal error: Oops: 96000006 [#1] PREEMPT SMP
[ 479.528664] Modules linked in:
[ 479.528699] CPU: 0 PID: 2457 Comm: cat Not tainted 4.15.0-rc3-00065-g2ad2ee7ecb5c-dirty #7
[ 479.528799] Hardware name: FVP Base (DT)
[ 479.528899] pstate: 00400009 (nzcv daif +PAN -UAO)
[ 479.528941] pc : walk_pgd.isra.1+0x20/0x1d0
[ 479.529011] lr : ptdump_walk_pgd+0x30/0x50
[ 479.529105] sp : ffff00000bf4bc20
[ 479.529185] x29: ffff00000bf4bc20 x28: 0000ffff9d22e000
[ 479.529271] x27: 0000000000020000 x26: ffff80007b4c63c0
[ 479.529358] x25: 00000000014000c0 x24: ffff80007c098900
[ 479.529445] x23: ffff00000bf4beb8 x22: 0000000000000000
[ 479.529532] x21: ffff00000bf4bd70 x20: 0000000000000001
[ 479.529618] x19: ffff00000bf4bcb0 x18: 0000000000000000
[ 479.529760] x17: 000000000041a1c8 x16: ffff0000082139d8
[ 479.529800] x15: 0000ffff9d3c6030 x14: 0000ffff9d2527f4
[ 479.529924] x13: 00000000000003f3 x12: 0000000000000038
[ 479.530000] x11: 0000000000000003 x10: 0101010101010101
[ 479.530099] x9 : 0000000017e94050 x8 : 000000000000003f
[ 479.530226] x7 : 0000000000000000 x6 : 0000000000000000
[ 479.530313] x5 : 0000000000000001 x4 : 0000000000000000
[ 479.530416] x3 : ffff000009069fd8 x2 : 0000000000000000
[ 479.530500] x1 : 0000000000000000 x0 : 0000000000000000
[ 479.530599] Process cat (pid: 2457, stack limit = 0x000000005d1b0e6f)
[ 479.530660] Call trace:
[ 479.530746] walk_pgd.isra.1+0x20/0x1d0
[ 479.530833] ptdump_walk_pgd+0x30/0x50
[ 479.530907] ptdump_show+0x10/0x20
[ 479.530920] seq_read+0xc8/0x470
[ 479.531023] full_proxy_read+0x60/0x90
[ 479.531100] __vfs_read+0x18/0x100
[ 479.531180] vfs_read+0x88/0x160
[ 479.531267] SyS_read+0x48/0xb0
[ 479.531299] el0_svc_naked+0x20/0x24
[ 479.531400] Code: 91400420 f90033a0 a90707a2 f9403fa0 (f9400000)
[ 479.531499] ---[ end trace bfe8e28d8acb2b67 ]---
Segmentation fault
Let's avoid this problem by only registering the tables after their
successful creation, which is also less confusing when EFI runtime
services are not in use.
Reported-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/20180308080020.22828-2-ard.biesheuvel@linaro.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2018-03-08 16:00:09 +08:00
|
|
|
|
2019-02-02 03:20:01 +08:00
|
|
|
return 0;
|
2016-08-16 20:13:21 +08:00
|
|
|
}
|
|
|
|
device_initcall(ptdump_init);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2015-11-30 20:28:18 +08:00
|
|
|
static bool __init efi_virtmap_init(void)
|
|
|
|
{
|
|
|
|
efi_memory_desc_t *md;
|
|
|
|
|
2015-11-30 20:28:19 +08:00
|
|
|
efi_mm.pgd = pgd_alloc(&efi_mm);
|
2017-03-02 03:05:54 +08:00
|
|
|
mm_init_cpumask(&efi_mm);
|
2015-11-30 20:28:18 +08:00
|
|
|
init_new_context(NULL, &efi_mm);
|
|
|
|
|
2016-04-26 04:06:38 +08:00
|
|
|
for_each_efi_memory_desc(md) {
|
2015-11-30 20:28:19 +08:00
|
|
|
phys_addr_t phys = md->phys_addr;
|
|
|
|
int ret;
|
2015-11-30 20:28:18 +08:00
|
|
|
|
|
|
|
if (!(md->attribute & EFI_MEMORY_RUNTIME))
|
|
|
|
continue;
|
|
|
|
if (md->virt_addr == 0)
|
|
|
|
return false;
|
|
|
|
|
2015-11-30 20:28:19 +08:00
|
|
|
ret = efi_create_mapping(&efi_mm, md);
|
2018-03-08 16:00:11 +08:00
|
|
|
if (ret) {
|
2015-11-30 20:28:19 +08:00
|
|
|
pr_warn(" EFI remap %pa: failed to create mapping (%d)\n",
|
|
|
|
&phys, ret);
|
|
|
|
return false;
|
|
|
|
}
|
2016-04-26 04:06:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
2015-11-30 20:28:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
|
|
|
|
* non-early mapping of the UEFI system table and virtual mappings for all
|
|
|
|
* EFI_MEMORY_RUNTIME regions.
|
|
|
|
*/
|
2015-11-30 20:28:19 +08:00
|
|
|
static int __init arm_enable_runtime_services(void)
|
2015-11-30 20:28:18 +08:00
|
|
|
{
|
|
|
|
u64 mapsize;
|
|
|
|
|
2018-11-15 01:55:41 +08:00
|
|
|
if (!efi_enabled(EFI_BOOT)) {
|
2015-11-30 20:28:18 +08:00
|
|
|
pr_info("EFI services will not be available.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-23 09:57:30 +08:00
|
|
|
efi_memmap_unmap();
|
|
|
|
|
2018-07-23 09:57:31 +08:00
|
|
|
mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
|
|
|
|
|
|
|
|
if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
|
|
|
|
pr_err("Failed to remap EFI memory map\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-07 09:43:21 +08:00
|
|
|
if (efi_soft_reserve_enabled()) {
|
|
|
|
efi_memory_desc_t *md;
|
|
|
|
|
|
|
|
for_each_efi_memory_desc(md) {
|
|
|
|
int md_size = md->num_pages << EFI_PAGE_SHIFT;
|
|
|
|
struct resource *res;
|
|
|
|
|
|
|
|
if (!(md->attribute & EFI_MEMORY_SP))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
res = kzalloc(sizeof(*res), GFP_KERNEL);
|
|
|
|
if (WARN_ON(!res))
|
|
|
|
break;
|
|
|
|
|
|
|
|
res->start = md->phys_addr;
|
|
|
|
res->end = md->phys_addr + md_size - 1;
|
|
|
|
res->name = "Soft Reserved";
|
|
|
|
res->flags = IORESOURCE_MEM;
|
|
|
|
res->desc = IORES_DESC_SOFT_RESERVED;
|
|
|
|
|
|
|
|
insert_resource(&iomem_resource, res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-30 20:28:18 +08:00
|
|
|
if (efi_runtime_disabled()) {
|
|
|
|
pr_info("EFI runtime services will be disabled.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-05-12 20:19:54 +08:00
|
|
|
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
|
|
|
|
pr_info("EFI runtime services access via paravirt.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-30 20:28:18 +08:00
|
|
|
pr_info("Remapping and enabling EFI services.\n");
|
|
|
|
|
|
|
|
if (!efi_virtmap_init()) {
|
efi/arm*: Drop writable mapping of the UEFI System table
Commit:
2eec5dedf770 ("efi/arm-init: Use read-only early mappings")
updated the early ARM UEFI init code to create the temporary, early
mapping of the UEFI System table using read-only attributes, as a
hardening measure against inadvertent modification.
However, this still leaves the permanent, writable mapping of the UEFI
System table, which is only ever referenced during invocations of UEFI
Runtime Services, at which time the UEFI virtual mapping is available,
which also covers the system table. (This is guaranteed by the fact that
SetVirtualAddressMap(), which is a runtime service itself, converts
various entries in the table to their virtual equivalents, which implies
that the table must be covered by a RuntimeServicesData region that has
the EFI_MEMORY_RUNTIME attribute.)
So instead of creating this permanent mapping, record the virtual address
of the system table inside the UEFI virtual mapping, and dereference that
when accessing the table. This protects the contents of the system table
from inadvertent (or deliberate) modification when no UEFI Runtime
Services calls are in progress.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1461614832-17633-3-git-send-email-matt@codeblueprint.co.uk
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-04-26 04:06:34 +08:00
|
|
|
pr_err("UEFI virtual mapping missing or invalid -- runtime services will not be available\n");
|
2015-11-30 20:28:18 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up runtime services function pointers */
|
|
|
|
efi_native_runtime_setup();
|
|
|
|
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-11-30 20:28:19 +08:00
|
|
|
early_initcall(arm_enable_runtime_services);
|
2015-11-30 20:28:18 +08:00
|
|
|
|
|
|
|
void efi_virtmap_load(void)
|
|
|
|
{
|
|
|
|
preempt_disable();
|
|
|
|
efi_set_pgd(&efi_mm);
|
|
|
|
}
|
|
|
|
|
|
|
|
void efi_virtmap_unload(void)
|
|
|
|
{
|
|
|
|
efi_set_pgd(current->active_mm);
|
|
|
|
preempt_enable();
|
|
|
|
}
|
2017-06-02 21:52:07 +08:00
|
|
|
|
|
|
|
|
|
|
|
static int __init arm_dmi_init(void)
|
|
|
|
{
|
|
|
|
/*
|
2019-03-29 03:34:28 +08:00
|
|
|
* On arm64/ARM, DMI depends on UEFI, and dmi_setup() needs to
|
2017-06-02 21:52:07 +08:00
|
|
|
* be called early because dmi_id_init(), which is an arch_initcall
|
|
|
|
* itself, depends on dmi_scan_machine() having been called already.
|
|
|
|
*/
|
2019-03-29 03:34:28 +08:00
|
|
|
dmi_setup();
|
2017-06-02 21:52:07 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
core_initcall(arm_dmi_init);
|