1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
4 */
5
6 #include <linux/efi.h>
7 #include <linux/memblock.h>
8 #include <asm/efi.h>
9 #include <asm/mach/map.h>
10 #include <asm/mmu_context.h>
11
set_permissions(pte_t * ptep,unsigned long addr,void * data)12 static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
13 {
14 efi_memory_desc_t *md = data;
15 pte_t pte = *ptep;
16
17 if (md->attribute & EFI_MEMORY_RO)
18 pte = set_pte_bit(pte, __pgprot(L_PTE_RDONLY));
19 if (md->attribute & EFI_MEMORY_XP)
20 pte = set_pte_bit(pte, __pgprot(L_PTE_XN));
21 set_pte_ext(ptep, pte, PTE_EXT_NG);
22 return 0;
23 }
24
efi_set_mapping_permissions(struct mm_struct * mm,efi_memory_desc_t * md,bool ignored)25 int __init efi_set_mapping_permissions(struct mm_struct *mm,
26 efi_memory_desc_t *md,
27 bool ignored)
28 {
29 unsigned long base, size;
30
31 base = md->virt_addr;
32 size = md->num_pages << EFI_PAGE_SHIFT;
33
34 /*
35 * We can only use apply_to_page_range() if we can guarantee that the
36 * entire region was mapped using pages. This should be the case if the
37 * region does not cover any naturally aligned SECTION_SIZE sized
38 * blocks.
39 */
40 if (round_down(base + size, SECTION_SIZE) <
41 round_up(base, SECTION_SIZE) + SECTION_SIZE)
42 return apply_to_page_range(mm, base, size, set_permissions, md);
43
44 return 0;
45 }
46
efi_create_mapping(struct mm_struct * mm,efi_memory_desc_t * md)47 int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
48 {
49 struct map_desc desc = {
50 .virtual = md->virt_addr,
51 .pfn = __phys_to_pfn(md->phys_addr),
52 .length = md->num_pages * EFI_PAGE_SIZE,
53 };
54
55 /*
56 * Order is important here: memory regions may have all of the
57 * bits below set (and usually do), so we check them in order of
58 * preference.
59 */
60 if (md->attribute & EFI_MEMORY_WB)
61 desc.type = MT_MEMORY_RWX;
62 else if (md->attribute & EFI_MEMORY_WT)
63 desc.type = MT_MEMORY_RWX_NONCACHED;
64 else if (md->attribute & EFI_MEMORY_WC)
65 desc.type = MT_DEVICE_WC;
66 else
67 desc.type = MT_DEVICE;
68
69 create_mapping_late(mm, &desc, true);
70
71 /*
72 * If stricter permissions were specified, apply them now.
73 */
74 if (md->attribute & (EFI_MEMORY_RO | EFI_MEMORY_XP))
75 return efi_set_mapping_permissions(mm, md, false);
76 return 0;
77 }
78
79 static unsigned long __initdata cpu_state_table = EFI_INVALID_TABLE_ADDR;
80
81 const efi_config_table_type_t efi_arch_tables[] __initconst = {
82 {LINUX_EFI_ARM_CPU_STATE_TABLE_GUID, &cpu_state_table},
83 {}
84 };
85
load_cpu_state_table(void)86 static void __init load_cpu_state_table(void)
87 {
88 if (cpu_state_table != EFI_INVALID_TABLE_ADDR) {
89 struct efi_arm_entry_state *state;
90 bool dump_state = true;
91
92 state = early_memremap_ro(cpu_state_table,
93 sizeof(struct efi_arm_entry_state));
94 if (state == NULL) {
95 pr_warn("Unable to map CPU entry state table.\n");
96 return;
97 }
98
99 if ((state->sctlr_before_ebs & 1) == 0)
100 pr_warn(FW_BUG "EFI stub was entered with MMU and Dcache disabled, please fix your firmware!\n");
101 else if ((state->sctlr_after_ebs & 1) == 0)
102 pr_warn(FW_BUG "ExitBootServices() returned with MMU and Dcache disabled, please fix your firmware!\n");
103 else
104 dump_state = false;
105
106 if (dump_state || efi_enabled(EFI_DBG)) {
107 pr_info("CPSR at EFI stub entry : 0x%08x\n",
108 state->cpsr_before_ebs);
109 pr_info("SCTLR at EFI stub entry : 0x%08x\n",
110 state->sctlr_before_ebs);
111 pr_info("CPSR after ExitBootServices() : 0x%08x\n",
112 state->cpsr_after_ebs);
113 pr_info("SCTLR after ExitBootServices(): 0x%08x\n",
114 state->sctlr_after_ebs);
115 }
116 early_memunmap(state, sizeof(struct efi_arm_entry_state));
117 }
118 }
119
arm_efi_init(void)120 void __init arm_efi_init(void)
121 {
122 efi_init();
123
124 if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
125 /* dummycon on ARM needs non-zero values for columns/lines */
126 screen_info.orig_video_cols = 80;
127 screen_info.orig_video_lines = 25;
128 }
129
130 /* ARM does not permit early mappings to persist across paging_init() */
131 efi_memmap_unmap();
132
133 load_cpu_state_table();
134 }
135