102f45fdbe
Now walk_page_range() can walk kernel page tables, we can switch the arm64 ptdump code over to using it, simplifying the code. Link: http://lkml.kernel.org/r/20191218162402.45610-22-steven.price@arm.com Signed-off-by: Steven Price <steven.price@arm.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Albert Ou <aou@eecs.berkeley.edu> Cc: Alexandre Ghiti <alex@ghiti.fr> Cc: Andy Lutomirski <luto@kernel.org> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Christian Borntraeger <borntraeger@de.ibm.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: David S. Miller <davem@davemloft.net> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Hogan <jhogan@kernel.org> Cc: James Morse <james.morse@arm.com> Cc: Jerome Glisse <jglisse@redhat.com> Cc: "Liang, Kan" <kan.liang@linux.intel.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Paul Burton <paul.burton@mips.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Paul Walmsley <paul.walmsley@sifive.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vasily Gorbik <gor@linux.ibm.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Will Deacon <will@kernel.org> Cc: Zong Li <zong.li@sifive.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
197 lines
4.3 KiB
C
197 lines
4.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Extensible Firmware Interface
|
|
*
|
|
* Based on Extensible Firmware Interface Specification version 2.4
|
|
*
|
|
* Copyright (C) 2013, 2014 Linaro Ltd.
|
|
*/
|
|
|
|
#include <linux/dmi.h>
|
|
#include <linux/efi.h>
|
|
#include <linux/io.h>
|
|
#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>
|
|
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/efi.h>
|
|
#include <asm/mmu.h>
|
|
#include <asm/pgalloc.h>
|
|
#include <asm/pgtable.h>
|
|
|
|
extern u64 efi_system_table;
|
|
|
|
#if defined(CONFIG_PTDUMP_DEBUGFS) && defined(CONFIG_ARM64)
|
|
#include <asm/ptdump.h>
|
|
|
|
static struct ptdump_info efi_ptdump_info = {
|
|
.mm = &efi_mm,
|
|
.markers = (struct addr_marker[]){
|
|
{ 0, "UEFI runtime start" },
|
|
{ DEFAULT_MAP_WINDOW_64, "UEFI runtime end" },
|
|
{ -1, NULL }
|
|
},
|
|
.base_addr = 0,
|
|
};
|
|
|
|
static int __init ptdump_init(void)
|
|
{
|
|
if (efi_enabled(EFI_RUNTIME_SERVICES))
|
|
ptdump_debugfs_register(&efi_ptdump_info, "efi_page_tables");
|
|
|
|
return 0;
|
|
}
|
|
device_initcall(ptdump_init);
|
|
|
|
#endif
|
|
|
|
static bool __init efi_virtmap_init(void)
|
|
{
|
|
efi_memory_desc_t *md;
|
|
bool systab_found;
|
|
|
|
efi_mm.pgd = pgd_alloc(&efi_mm);
|
|
mm_init_cpumask(&efi_mm);
|
|
init_new_context(NULL, &efi_mm);
|
|
|
|
systab_found = false;
|
|
for_each_efi_memory_desc(md) {
|
|
phys_addr_t phys = md->phys_addr;
|
|
int ret;
|
|
|
|
if (!(md->attribute & EFI_MEMORY_RUNTIME))
|
|
continue;
|
|
if (md->virt_addr == 0)
|
|
return false;
|
|
|
|
ret = efi_create_mapping(&efi_mm, md);
|
|
if (ret) {
|
|
pr_warn(" EFI remap %pa: failed to create mapping (%d)\n",
|
|
&phys, ret);
|
|
return false;
|
|
}
|
|
/*
|
|
* If this entry covers the address of the UEFI system table,
|
|
* calculate and record its virtual address.
|
|
*/
|
|
if (efi_system_table >= phys &&
|
|
efi_system_table < phys + (md->num_pages * EFI_PAGE_SIZE)) {
|
|
efi.systab = (void *)(unsigned long)(efi_system_table -
|
|
phys + md->virt_addr);
|
|
systab_found = true;
|
|
}
|
|
}
|
|
if (!systab_found) {
|
|
pr_err("No virtual mapping found for the UEFI System Table\n");
|
|
return false;
|
|
}
|
|
|
|
if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
static int __init arm_enable_runtime_services(void)
|
|
{
|
|
u64 mapsize;
|
|
|
|
if (!efi_enabled(EFI_BOOT)) {
|
|
pr_info("EFI services will not be available.\n");
|
|
return 0;
|
|
}
|
|
|
|
efi_memmap_unmap();
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
if (efi_runtime_disabled()) {
|
|
pr_info("EFI runtime services will be disabled.\n");
|
|
return 0;
|
|
}
|
|
|
|
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
|
|
pr_info("EFI runtime services access via paravirt.\n");
|
|
return 0;
|
|
}
|
|
|
|
pr_info("Remapping and enabling EFI services.\n");
|
|
|
|
if (!efi_virtmap_init()) {
|
|
pr_err("UEFI virtual mapping missing or invalid -- runtime services will not be available\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Set up runtime services function pointers */
|
|
efi_native_runtime_setup();
|
|
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
|
|
|
return 0;
|
|
}
|
|
early_initcall(arm_enable_runtime_services);
|
|
|
|
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();
|
|
}
|
|
|
|
|
|
static int __init arm_dmi_init(void)
|
|
{
|
|
/*
|
|
* On arm64/ARM, DMI depends on UEFI, and dmi_setup() needs to
|
|
* be called early because dmi_id_init(), which is an arch_initcall
|
|
* itself, depends on dmi_scan_machine() having been called already.
|
|
*/
|
|
dmi_setup();
|
|
return 0;
|
|
}
|
|
core_initcall(arm_dmi_init);
|