xref: /openbmc/linux/arch/riscv/kernel/efi.c (revision ca2478a7d974f38d29d27acb42a952c7f168916e)
1b91540d5SAtish Patra // SPDX-License-Identifier: GPL-2.0-only
2b91540d5SAtish Patra /*
3b91540d5SAtish Patra  * Copyright (C) 2020 Western Digital Corporation or its affiliates.
4b91540d5SAtish Patra  * Adapted from arch/arm64/kernel/efi.c
5b91540d5SAtish Patra  */
6b91540d5SAtish Patra 
7b91540d5SAtish Patra #include <linux/efi.h>
8b91540d5SAtish Patra #include <linux/init.h>
9b91540d5SAtish Patra 
10b91540d5SAtish Patra #include <asm/efi.h>
11b91540d5SAtish Patra #include <asm/pgtable.h>
12b91540d5SAtish Patra #include <asm/pgtable-bits.h>
13b91540d5SAtish Patra 
14b91540d5SAtish Patra /*
15b91540d5SAtish Patra  * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
16b91540d5SAtish Patra  * executable, everything else can be mapped with the XN bits
17b91540d5SAtish Patra  * set. Also take the new (optional) RO/XP bits into account.
18b91540d5SAtish Patra  */
efimem_to_pgprot_map(efi_memory_desc_t * md)19b91540d5SAtish Patra static __init pgprot_t efimem_to_pgprot_map(efi_memory_desc_t *md)
20b91540d5SAtish Patra {
21b91540d5SAtish Patra 	u64 attr = md->attribute;
22b91540d5SAtish Patra 	u32 type = md->type;
23b91540d5SAtish Patra 
24b91540d5SAtish Patra 	if (type == EFI_MEMORY_MAPPED_IO)
25b91540d5SAtish Patra 		return PAGE_KERNEL;
26b91540d5SAtish Patra 
27b91540d5SAtish Patra 	/* R-- */
28b91540d5SAtish Patra 	if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) ==
29b91540d5SAtish Patra 	    (EFI_MEMORY_XP | EFI_MEMORY_RO))
30b91540d5SAtish Patra 		return PAGE_KERNEL_READ;
31b91540d5SAtish Patra 
32b91540d5SAtish Patra 	/* R-X */
33b91540d5SAtish Patra 	if (attr & EFI_MEMORY_RO)
34b91540d5SAtish Patra 		return PAGE_KERNEL_READ_EXEC;
35b91540d5SAtish Patra 
36b91540d5SAtish Patra 	/* RW- */
37b91540d5SAtish Patra 	if (((attr & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP)) ==
38b91540d5SAtish Patra 	     EFI_MEMORY_XP) ||
39b91540d5SAtish Patra 	    type != EFI_RUNTIME_SERVICES_CODE)
40b91540d5SAtish Patra 		return PAGE_KERNEL;
41b91540d5SAtish Patra 
42b91540d5SAtish Patra 	/* RWX */
43b91540d5SAtish Patra 	return PAGE_KERNEL_EXEC;
44b91540d5SAtish Patra }
45b91540d5SAtish Patra 
efi_create_mapping(struct mm_struct * mm,efi_memory_desc_t * md)46b91540d5SAtish Patra int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
47b91540d5SAtish Patra {
48b91540d5SAtish Patra 	pgprot_t prot = __pgprot(pgprot_val(efimem_to_pgprot_map(md)) &
49b91540d5SAtish Patra 				~(_PAGE_GLOBAL));
50b91540d5SAtish Patra 	int i;
51b91540d5SAtish Patra 
52b91540d5SAtish Patra 	/* RISC-V maps one page at a time */
53b91540d5SAtish Patra 	for (i = 0; i < md->num_pages; i++)
54b91540d5SAtish Patra 		create_pgd_mapping(mm->pgd, md->virt_addr + i * PAGE_SIZE,
55b91540d5SAtish Patra 				   md->phys_addr + i * PAGE_SIZE,
56b91540d5SAtish Patra 				   PAGE_SIZE, prot);
57b91540d5SAtish Patra 	return 0;
58b91540d5SAtish Patra }
59b91540d5SAtish Patra 
set_permissions(pte_t * ptep,unsigned long addr,void * data)60b91540d5SAtish Patra static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
61b91540d5SAtish Patra {
62b91540d5SAtish Patra 	efi_memory_desc_t *md = data;
63*e0316069SAlexandre Ghiti 	pte_t pte = ptep_get(ptep);
64b91540d5SAtish Patra 	unsigned long val;
65b91540d5SAtish Patra 
66b91540d5SAtish Patra 	if (md->attribute & EFI_MEMORY_RO) {
67b91540d5SAtish Patra 		val = pte_val(pte) & ~_PAGE_WRITE;
68630f972dSHeinrich Schuchardt 		val |= _PAGE_READ;
69b91540d5SAtish Patra 		pte = __pte(val);
70b91540d5SAtish Patra 	}
71b91540d5SAtish Patra 	if (md->attribute & EFI_MEMORY_XP) {
72b91540d5SAtish Patra 		val = pte_val(pte) & ~_PAGE_EXEC;
73b91540d5SAtish Patra 		pte = __pte(val);
74b91540d5SAtish Patra 	}
75b91540d5SAtish Patra 	set_pte(ptep, pte);
76b91540d5SAtish Patra 
77b91540d5SAtish Patra 	return 0;
78b91540d5SAtish Patra }
79b91540d5SAtish Patra 
efi_set_mapping_permissions(struct mm_struct * mm,efi_memory_desc_t * md,bool ignored)80b91540d5SAtish Patra int __init efi_set_mapping_permissions(struct mm_struct *mm,
81cf1d2ffcSArd Biesheuvel 				       efi_memory_desc_t *md,
82cf1d2ffcSArd Biesheuvel 				       bool ignored)
83b91540d5SAtish Patra {
84b91540d5SAtish Patra 	BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
85b91540d5SAtish Patra 	       md->type != EFI_RUNTIME_SERVICES_DATA);
86b91540d5SAtish Patra 
87b91540d5SAtish Patra 	/*
88b91540d5SAtish Patra 	 * Calling apply_to_page_range() is only safe on regions that are
89b91540d5SAtish Patra 	 * guaranteed to be mapped down to pages. Since we are only called
90b91540d5SAtish Patra 	 * for regions that have been mapped using efi_create_mapping() above
91b91540d5SAtish Patra 	 * (and this is checked by the generic Memory Attributes table parsing
92b91540d5SAtish Patra 	 * routines), there is no need to check that again here.
93b91540d5SAtish Patra 	 */
94b91540d5SAtish Patra 	return apply_to_page_range(mm, md->virt_addr,
95b91540d5SAtish Patra 				   md->num_pages << EFI_PAGE_SHIFT,
96b91540d5SAtish Patra 				   set_permissions, md);
97b91540d5SAtish Patra }
98