linux/drivers/firmware/efi/arm-runtime.c
<<
>>
Prefs
   1/*
   2 * Extensible Firmware Interface
   3 *
   4 * Based on Extensible Firmware Interface Specification version 2.4
   5 *
   6 * Copyright (C) 2013, 2014 Linaro Ltd.
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 */
  13
  14#include <linux/dmi.h>
  15#include <linux/efi.h>
  16#include <linux/io.h>
  17#include <linux/memblock.h>
  18#include <linux/mm_types.h>
  19#include <linux/preempt.h>
  20#include <linux/rbtree.h>
  21#include <linux/rwsem.h>
  22#include <linux/sched.h>
  23#include <linux/slab.h>
  24#include <linux/spinlock.h>
  25
  26#include <asm/cacheflush.h>
  27#include <asm/efi.h>
  28#include <asm/mmu.h>
  29#include <asm/pgalloc.h>
  30#include <asm/pgtable.h>
  31
  32extern u64 efi_system_table;
  33
  34static struct mm_struct efi_mm = {
  35        .mm_rb                  = RB_ROOT,
  36        .mm_users               = ATOMIC_INIT(2),
  37        .mm_count               = ATOMIC_INIT(1),
  38        .mmap_sem               = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
  39        .page_table_lock        = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
  40        .mmlist                 = LIST_HEAD_INIT(efi_mm.mmlist),
  41};
  42
  43#ifdef CONFIG_ARM64_PTDUMP_DEBUGFS
  44#include <asm/ptdump.h>
  45
  46static struct ptdump_info efi_ptdump_info = {
  47        .mm             = &efi_mm,
  48        .markers        = (struct addr_marker[]){
  49                { 0,            "UEFI runtime start" },
  50                { TASK_SIZE_64, "UEFI runtime end" }
  51        },
  52        .base_addr      = 0,
  53};
  54
  55static int __init ptdump_init(void)
  56{
  57        return ptdump_debugfs_register(&efi_ptdump_info, "efi_page_tables");
  58}
  59device_initcall(ptdump_init);
  60
  61#endif
  62
  63static bool __init efi_virtmap_init(void)
  64{
  65        efi_memory_desc_t *md;
  66        bool systab_found;
  67
  68        efi_mm.pgd = pgd_alloc(&efi_mm);
  69        mm_init_cpumask(&efi_mm);
  70        init_new_context(NULL, &efi_mm);
  71
  72        systab_found = false;
  73        for_each_efi_memory_desc(md) {
  74                phys_addr_t phys = md->phys_addr;
  75                int ret;
  76
  77                if (!(md->attribute & EFI_MEMORY_RUNTIME))
  78                        continue;
  79                if (md->virt_addr == 0)
  80                        return false;
  81
  82                ret = efi_create_mapping(&efi_mm, md);
  83                if  (!ret) {
  84                        pr_info("  EFI remap %pa => %p\n",
  85                                &phys, (void *)(unsigned long)md->virt_addr);
  86                } else {
  87                        pr_warn("  EFI remap %pa: failed to create mapping (%d)\n",
  88                                &phys, ret);
  89                        return false;
  90                }
  91                /*
  92                 * If this entry covers the address of the UEFI system table,
  93                 * calculate and record its virtual address.
  94                 */
  95                if (efi_system_table >= phys &&
  96                    efi_system_table < phys + (md->num_pages * EFI_PAGE_SIZE)) {
  97                        efi.systab = (void *)(unsigned long)(efi_system_table -
  98                                                             phys + md->virt_addr);
  99                        systab_found = true;
 100                }
 101        }
 102        if (!systab_found) {
 103                pr_err("No virtual mapping found for the UEFI System Table\n");
 104                return false;
 105        }
 106
 107        if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
 108                return false;
 109
 110        return true;
 111}
 112
 113/*
 114 * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
 115 * non-early mapping of the UEFI system table and virtual mappings for all
 116 * EFI_MEMORY_RUNTIME regions.
 117 */
 118static int __init arm_enable_runtime_services(void)
 119{
 120        u64 mapsize;
 121
 122        if (!efi_enabled(EFI_BOOT)) {
 123                pr_info("EFI services will not be available.\n");
 124                return 0;
 125        }
 126
 127        if (efi_runtime_disabled()) {
 128                pr_info("EFI runtime services will be disabled.\n");
 129                return 0;
 130        }
 131
 132        if (efi_enabled(EFI_RUNTIME_SERVICES)) {
 133                pr_info("EFI runtime services access via paravirt.\n");
 134                return 0;
 135        }
 136
 137        pr_info("Remapping and enabling EFI services.\n");
 138
 139        mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
 140
 141        if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
 142                pr_err("Failed to remap EFI memory map\n");
 143                return -ENOMEM;
 144        }
 145
 146        if (!efi_virtmap_init()) {
 147                pr_err("UEFI virtual mapping missing or invalid -- runtime services will not be available\n");
 148                return -ENOMEM;
 149        }
 150
 151        /* Set up runtime services function pointers */
 152        efi_native_runtime_setup();
 153        set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
 154
 155        return 0;
 156}
 157early_initcall(arm_enable_runtime_services);
 158
 159void efi_virtmap_load(void)
 160{
 161        preempt_disable();
 162        efi_set_pgd(&efi_mm);
 163}
 164
 165void efi_virtmap_unload(void)
 166{
 167        efi_set_pgd(current->active_mm);
 168        preempt_enable();
 169}
 170
 171
 172static int __init arm_dmi_init(void)
 173{
 174        /*
 175         * On arm64/ARM, DMI depends on UEFI, and dmi_scan_machine() needs to
 176         * be called early because dmi_id_init(), which is an arch_initcall
 177         * itself, depends on dmi_scan_machine() having been called already.
 178         */
 179        dmi_scan_machine();
 180        if (dmi_available)
 181                dmi_set_dump_stack_arch_desc();
 182        return 0;
 183}
 184core_initcall(arm_dmi_init);
 185