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