xref: /openbmc/linux/arch/arm/kernel/efi.c (revision 732ea9db9d8a6a0444d18ed810cccb2428d8766b)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2da58fb65SArd Biesheuvel /*
3da58fb65SArd Biesheuvel  * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
4da58fb65SArd Biesheuvel  */
5da58fb65SArd Biesheuvel 
6da58fb65SArd Biesheuvel #include <linux/efi.h>
769e377b2SArd Biesheuvel #include <linux/memblock.h>
8da58fb65SArd Biesheuvel #include <asm/efi.h>
9da58fb65SArd Biesheuvel #include <asm/mach/map.h>
10da58fb65SArd Biesheuvel #include <asm/mmu_context.h>
11da58fb65SArd Biesheuvel 
128b1e0f81SAnshuman Khandual static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
139fc68b71SArd Biesheuvel {
149fc68b71SArd Biesheuvel 	efi_memory_desc_t *md = data;
159fc68b71SArd Biesheuvel 	pte_t pte = *ptep;
169fc68b71SArd Biesheuvel 
179fc68b71SArd Biesheuvel 	if (md->attribute & EFI_MEMORY_RO)
189fc68b71SArd Biesheuvel 		pte = set_pte_bit(pte, __pgprot(L_PTE_RDONLY));
199fc68b71SArd Biesheuvel 	if (md->attribute & EFI_MEMORY_XP)
209fc68b71SArd Biesheuvel 		pte = set_pte_bit(pte, __pgprot(L_PTE_XN));
219fc68b71SArd Biesheuvel 	set_pte_ext(ptep, pte, PTE_EXT_NG);
229fc68b71SArd Biesheuvel 	return 0;
239fc68b71SArd Biesheuvel }
249fc68b71SArd Biesheuvel 
259fc68b71SArd Biesheuvel int __init efi_set_mapping_permissions(struct mm_struct *mm,
269fc68b71SArd Biesheuvel 				       efi_memory_desc_t *md)
279fc68b71SArd Biesheuvel {
289fc68b71SArd Biesheuvel 	unsigned long base, size;
299fc68b71SArd Biesheuvel 
309fc68b71SArd Biesheuvel 	base = md->virt_addr;
319fc68b71SArd Biesheuvel 	size = md->num_pages << EFI_PAGE_SHIFT;
329fc68b71SArd Biesheuvel 
339fc68b71SArd Biesheuvel 	/*
349fc68b71SArd Biesheuvel 	 * We can only use apply_to_page_range() if we can guarantee that the
359fc68b71SArd Biesheuvel 	 * entire region was mapped using pages. This should be the case if the
369fc68b71SArd Biesheuvel 	 * region does not cover any naturally aligned SECTION_SIZE sized
379fc68b71SArd Biesheuvel 	 * blocks.
389fc68b71SArd Biesheuvel 	 */
399fc68b71SArd Biesheuvel 	if (round_down(base + size, SECTION_SIZE) <
409fc68b71SArd Biesheuvel 	    round_up(base, SECTION_SIZE) + SECTION_SIZE)
419fc68b71SArd Biesheuvel 		return apply_to_page_range(mm, base, size, set_permissions, md);
429fc68b71SArd Biesheuvel 
439fc68b71SArd Biesheuvel 	return 0;
449fc68b71SArd Biesheuvel }
459fc68b71SArd Biesheuvel 
46da58fb65SArd Biesheuvel int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
47da58fb65SArd Biesheuvel {
48da58fb65SArd Biesheuvel 	struct map_desc desc = {
49da58fb65SArd Biesheuvel 		.virtual	= md->virt_addr,
50da58fb65SArd Biesheuvel 		.pfn		= __phys_to_pfn(md->phys_addr),
51da58fb65SArd Biesheuvel 		.length		= md->num_pages * EFI_PAGE_SIZE,
52da58fb65SArd Biesheuvel 	};
53da58fb65SArd Biesheuvel 
54da58fb65SArd Biesheuvel 	/*
55da58fb65SArd Biesheuvel 	 * Order is important here: memory regions may have all of the
56da58fb65SArd Biesheuvel 	 * bits below set (and usually do), so we check them in order of
57da58fb65SArd Biesheuvel 	 * preference.
58da58fb65SArd Biesheuvel 	 */
59da58fb65SArd Biesheuvel 	if (md->attribute & EFI_MEMORY_WB)
60da58fb65SArd Biesheuvel 		desc.type = MT_MEMORY_RWX;
61da58fb65SArd Biesheuvel 	else if (md->attribute & EFI_MEMORY_WT)
62da58fb65SArd Biesheuvel 		desc.type = MT_MEMORY_RWX_NONCACHED;
63da58fb65SArd Biesheuvel 	else if (md->attribute & EFI_MEMORY_WC)
64da58fb65SArd Biesheuvel 		desc.type = MT_DEVICE_WC;
65da58fb65SArd Biesheuvel 	else
66da58fb65SArd Biesheuvel 		desc.type = MT_DEVICE;
67da58fb65SArd Biesheuvel 
68da58fb65SArd Biesheuvel 	create_mapping_late(mm, &desc, true);
699fc68b71SArd Biesheuvel 
709fc68b71SArd Biesheuvel 	/*
719fc68b71SArd Biesheuvel 	 * If stricter permissions were specified, apply them now.
729fc68b71SArd Biesheuvel 	 */
739fc68b71SArd Biesheuvel 	if (md->attribute & (EFI_MEMORY_RO | EFI_MEMORY_XP))
749fc68b71SArd Biesheuvel 		return efi_set_mapping_permissions(mm, md);
75da58fb65SArd Biesheuvel 	return 0;
76da58fb65SArd Biesheuvel }
7769e377b2SArd Biesheuvel 
7869e377b2SArd Biesheuvel static unsigned long __initdata cpu_state_table = EFI_INVALID_TABLE_ADDR;
7969e377b2SArd Biesheuvel 
8069e377b2SArd Biesheuvel const efi_config_table_type_t efi_arch_tables[] __initconst = {
8169e377b2SArd Biesheuvel 	{LINUX_EFI_ARM_CPU_STATE_TABLE_GUID, &cpu_state_table},
8269e377b2SArd Biesheuvel 	{}
8369e377b2SArd Biesheuvel };
8469e377b2SArd Biesheuvel 
8569e377b2SArd Biesheuvel static void __init load_cpu_state_table(void)
8669e377b2SArd Biesheuvel {
8769e377b2SArd Biesheuvel 	if (cpu_state_table != EFI_INVALID_TABLE_ADDR) {
8869e377b2SArd Biesheuvel 		struct efi_arm_entry_state *state;
8969e377b2SArd Biesheuvel 		bool dump_state = true;
9069e377b2SArd Biesheuvel 
9169e377b2SArd Biesheuvel 		state = early_memremap_ro(cpu_state_table,
9269e377b2SArd Biesheuvel 					  sizeof(struct efi_arm_entry_state));
9369e377b2SArd Biesheuvel 		if (state == NULL) {
9469e377b2SArd Biesheuvel 			pr_warn("Unable to map CPU entry state table.\n");
9569e377b2SArd Biesheuvel 			return;
9669e377b2SArd Biesheuvel 		}
9769e377b2SArd Biesheuvel 
9869e377b2SArd Biesheuvel 		if ((state->sctlr_before_ebs & 1) == 0)
9969e377b2SArd Biesheuvel 			pr_warn(FW_BUG "EFI stub was entered with MMU and Dcache disabled, please fix your firmware!\n");
10069e377b2SArd Biesheuvel 		else if ((state->sctlr_after_ebs & 1) == 0)
10169e377b2SArd Biesheuvel 			pr_warn(FW_BUG "ExitBootServices() returned with MMU and Dcache disabled, please fix your firmware!\n");
10269e377b2SArd Biesheuvel 		else
10369e377b2SArd Biesheuvel 			dump_state = false;
10469e377b2SArd Biesheuvel 
10569e377b2SArd Biesheuvel 		if (dump_state || efi_enabled(EFI_DBG)) {
10669e377b2SArd Biesheuvel 			pr_info("CPSR at EFI stub entry        : 0x%08x\n",
10769e377b2SArd Biesheuvel 				state->cpsr_before_ebs);
10869e377b2SArd Biesheuvel 			pr_info("SCTLR at EFI stub entry       : 0x%08x\n",
10969e377b2SArd Biesheuvel 				state->sctlr_before_ebs);
11069e377b2SArd Biesheuvel 			pr_info("CPSR after ExitBootServices() : 0x%08x\n",
11169e377b2SArd Biesheuvel 				state->cpsr_after_ebs);
11269e377b2SArd Biesheuvel 			pr_info("SCTLR after ExitBootServices(): 0x%08x\n",
11369e377b2SArd Biesheuvel 				state->sctlr_after_ebs);
11469e377b2SArd Biesheuvel 		}
11569e377b2SArd Biesheuvel 		early_memunmap(state, sizeof(struct efi_arm_entry_state));
11669e377b2SArd Biesheuvel 	}
11769e377b2SArd Biesheuvel }
11869e377b2SArd Biesheuvel 
11969e377b2SArd Biesheuvel void __init arm_efi_init(void)
12069e377b2SArd Biesheuvel {
12169e377b2SArd Biesheuvel 	efi_init();
12269e377b2SArd Biesheuvel 
123*732ea9dbSArd Biesheuvel 	if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
124*732ea9dbSArd Biesheuvel 		/* dummycon on ARM needs non-zero values for columns/lines */
125*732ea9dbSArd Biesheuvel 		screen_info.orig_video_cols = 80;
126*732ea9dbSArd Biesheuvel 		screen_info.orig_video_lines = 25;
127*732ea9dbSArd Biesheuvel 	}
12869e377b2SArd Biesheuvel 
12969e377b2SArd Biesheuvel 	/* ARM does not permit early mappings to persist across paging_init() */
13069e377b2SArd Biesheuvel 	efi_memmap_unmap();
13169e377b2SArd Biesheuvel 
13269e377b2SArd Biesheuvel 	load_cpu_state_table();
13369e377b2SArd Biesheuvel }
134