blob: 974743e13a4d7376c4a9b9517d2fa0443cdd88e7 [file] [log] [blame]
Ard Biesheuvele5bc22a2015-11-30 13:28:18 +01001/*
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/efi.h>
15#include <linux/memblock.h>
16#include <linux/mm_types.h>
17#include <linux/preempt.h>
18#include <linux/rbtree.h>
19#include <linux/rwsem.h>
20#include <linux/sched.h>
21#include <linux/slab.h>
22#include <linux/spinlock.h>
23
24#include <asm/cacheflush.h>
25#include <asm/efi.h>
26#include <asm/tlbflush.h>
27#include <asm/mmu_context.h>
28#include <asm/mmu.h>
29#include <asm/pgtable.h>
30
31static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss;
32
33extern u64 efi_system_table;
34
35static struct mm_struct efi_mm = {
36 .mm_rb = RB_ROOT,
37 .pgd = efi_pgd,
38 .mm_users = ATOMIC_INIT(2),
39 .mm_count = ATOMIC_INIT(1),
40 .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
41 .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
42 .mmlist = LIST_HEAD_INIT(efi_mm.mmlist),
43};
44
45static bool __init efi_virtmap_init(void)
46{
47 efi_memory_desc_t *md;
48
49 init_new_context(NULL, &efi_mm);
50
51 for_each_efi_memory_desc(&memmap, md) {
52 pgprot_t prot;
53
54 if (!(md->attribute & EFI_MEMORY_RUNTIME))
55 continue;
56 if (md->virt_addr == 0)
57 return false;
58
59 pr_info(" EFI remap 0x%016llx => %p\n",
60 md->phys_addr, (void *)md->virt_addr);
61
62 /*
63 * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
64 * executable, everything else can be mapped with the XN bits
65 * set.
66 */
67 if ((md->attribute & EFI_MEMORY_WB) == 0)
68 prot = __pgprot(PROT_DEVICE_nGnRE);
69 else if (md->type == EFI_RUNTIME_SERVICES_CODE ||
70 !PAGE_ALIGNED(md->phys_addr))
71 prot = PAGE_KERNEL_EXEC;
72 else
73 prot = PAGE_KERNEL;
74
75 create_pgd_mapping(&efi_mm, md->phys_addr, md->virt_addr,
76 md->num_pages << EFI_PAGE_SHIFT,
77 __pgprot(pgprot_val(prot) | PTE_NG));
78 }
79 return true;
80}
81
82/*
83 * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
84 * non-early mapping of the UEFI system table and virtual mappings for all
85 * EFI_MEMORY_RUNTIME regions.
86 */
87static int __init arm64_enable_runtime_services(void)
88{
89 u64 mapsize;
90
91 if (!efi_enabled(EFI_BOOT)) {
92 pr_info("EFI services will not be available.\n");
93 return 0;
94 }
95
96 if (efi_runtime_disabled()) {
97 pr_info("EFI runtime services will be disabled.\n");
98 return 0;
99 }
100
101 pr_info("Remapping and enabling EFI services.\n");
102
103 mapsize = memmap.map_end - memmap.map;
104 memmap.map = (__force void *)ioremap_cache(memmap.phys_map,
105 mapsize);
106 if (!memmap.map) {
107 pr_err("Failed to remap EFI memory map\n");
108 return -ENOMEM;
109 }
110 memmap.map_end = memmap.map + mapsize;
111 efi.memmap = &memmap;
112
113 efi.systab = (__force void *)ioremap_cache(efi_system_table,
114 sizeof(efi_system_table_t));
115 if (!efi.systab) {
116 pr_err("Failed to remap EFI System Table\n");
117 return -ENOMEM;
118 }
119 set_bit(EFI_SYSTEM_TABLES, &efi.flags);
120
121 if (!efi_virtmap_init()) {
122 pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n");
123 return -ENOMEM;
124 }
125
126 /* Set up runtime services function pointers */
127 efi_native_runtime_setup();
128 set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
129
130 efi.runtime_version = efi.systab->hdr.revision;
131
132 return 0;
133}
134early_initcall(arm64_enable_runtime_services);
135
136static void efi_set_pgd(struct mm_struct *mm)
137{
138 switch_mm(NULL, mm, NULL);
139}
140
141void efi_virtmap_load(void)
142{
143 preempt_disable();
144 efi_set_pgd(&efi_mm);
145}
146
147void efi_virtmap_unload(void)
148{
149 efi_set_pgd(current->active_mm);
150 preempt_enable();
151}