crypto: s5p-sss - Fix kernel Oops in AES-ECB mode
[sfrench/cifs-2.6.git] / arch / arm64 / mm / pageattr.c
1 /*
2  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 and
6  * only version 2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13 #include <linux/kernel.h>
14 #include <linux/mm.h>
15 #include <linux/module.h>
16 #include <linux/sched.h>
17 #include <linux/vmalloc.h>
18
19 #include <asm/pgtable.h>
20 #include <asm/set_memory.h>
21 #include <asm/tlbflush.h>
22
23 struct page_change_data {
24         pgprot_t set_mask;
25         pgprot_t clear_mask;
26 };
27
28 static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
29                         void *data)
30 {
31         struct page_change_data *cdata = data;
32         pte_t pte = *ptep;
33
34         pte = clear_pte_bit(pte, cdata->clear_mask);
35         pte = set_pte_bit(pte, cdata->set_mask);
36
37         set_pte(ptep, pte);
38         return 0;
39 }
40
41 /*
42  * This function assumes that the range is mapped with PAGE_SIZE pages.
43  */
44 static int __change_memory_common(unsigned long start, unsigned long size,
45                                 pgprot_t set_mask, pgprot_t clear_mask)
46 {
47         struct page_change_data data;
48         int ret;
49
50         data.set_mask = set_mask;
51         data.clear_mask = clear_mask;
52
53         ret = apply_to_page_range(&init_mm, start, size, change_page_range,
54                                         &data);
55
56         flush_tlb_kernel_range(start, start + size);
57         return ret;
58 }
59
60 static int change_memory_common(unsigned long addr, int numpages,
61                                 pgprot_t set_mask, pgprot_t clear_mask)
62 {
63         unsigned long start = addr;
64         unsigned long size = PAGE_SIZE*numpages;
65         unsigned long end = start + size;
66         struct vm_struct *area;
67
68         if (!PAGE_ALIGNED(addr)) {
69                 start &= PAGE_MASK;
70                 end = start + size;
71                 WARN_ON_ONCE(1);
72         }
73
74         /*
75          * Kernel VA mappings are always live, and splitting live section
76          * mappings into page mappings may cause TLB conflicts. This means
77          * we have to ensure that changing the permission bits of the range
78          * we are operating on does not result in such splitting.
79          *
80          * Let's restrict ourselves to mappings created by vmalloc (or vmap).
81          * Those are guaranteed to consist entirely of page mappings, and
82          * splitting is never needed.
83          *
84          * So check whether the [addr, addr + size) interval is entirely
85          * covered by precisely one VM area that has the VM_ALLOC flag set.
86          */
87         area = find_vm_area((void *)addr);
88         if (!area ||
89             end > (unsigned long)area->addr + area->size ||
90             !(area->flags & VM_ALLOC))
91                 return -EINVAL;
92
93         if (!numpages)
94                 return 0;
95
96         return __change_memory_common(start, size, set_mask, clear_mask);
97 }
98
99 int set_memory_ro(unsigned long addr, int numpages)
100 {
101         return change_memory_common(addr, numpages,
102                                         __pgprot(PTE_RDONLY),
103                                         __pgprot(PTE_WRITE));
104 }
105
106 int set_memory_rw(unsigned long addr, int numpages)
107 {
108         return change_memory_common(addr, numpages,
109                                         __pgprot(PTE_WRITE),
110                                         __pgprot(PTE_RDONLY));
111 }
112
113 int set_memory_nx(unsigned long addr, int numpages)
114 {
115         return change_memory_common(addr, numpages,
116                                         __pgprot(PTE_PXN),
117                                         __pgprot(0));
118 }
119 EXPORT_SYMBOL_GPL(set_memory_nx);
120
121 int set_memory_x(unsigned long addr, int numpages)
122 {
123         return change_memory_common(addr, numpages,
124                                         __pgprot(0),
125                                         __pgprot(PTE_PXN));
126 }
127 EXPORT_SYMBOL_GPL(set_memory_x);
128
129 int set_memory_valid(unsigned long addr, int numpages, int enable)
130 {
131         if (enable)
132                 return __change_memory_common(addr, PAGE_SIZE * numpages,
133                                         __pgprot(PTE_VALID),
134                                         __pgprot(0));
135         else
136                 return __change_memory_common(addr, PAGE_SIZE * numpages,
137                                         __pgprot(0),
138                                         __pgprot(PTE_VALID));
139 }
140
141 #ifdef CONFIG_DEBUG_PAGEALLOC
142 void __kernel_map_pages(struct page *page, int numpages, int enable)
143 {
144         set_memory_valid((unsigned long)page_address(page), numpages, enable);
145 }
146 #ifdef CONFIG_HIBERNATION
147 /*
148  * When built with CONFIG_DEBUG_PAGEALLOC and CONFIG_HIBERNATION, this function
149  * is used to determine if a linear map page has been marked as not-valid by
150  * CONFIG_DEBUG_PAGEALLOC. Walk the page table and check the PTE_VALID bit.
151  * This is based on kern_addr_valid(), which almost does what we need.
152  *
153  * Because this is only called on the kernel linear map,  p?d_sect() implies
154  * p?d_present(). When debug_pagealloc is enabled, sections mappings are
155  * disabled.
156  */
157 bool kernel_page_present(struct page *page)
158 {
159         pgd_t *pgd;
160         pud_t *pud;
161         pmd_t *pmd;
162         pte_t *pte;
163         unsigned long addr = (unsigned long)page_address(page);
164
165         pgd = pgd_offset_k(addr);
166         if (pgd_none(*pgd))
167                 return false;
168
169         pud = pud_offset(pgd, addr);
170         if (pud_none(*pud))
171                 return false;
172         if (pud_sect(*pud))
173                 return true;
174
175         pmd = pmd_offset(pud, addr);
176         if (pmd_none(*pmd))
177                 return false;
178         if (pmd_sect(*pmd))
179                 return true;
180
181         pte = pte_offset_kernel(pmd, addr);
182         return pte_valid(*pte);
183 }
184 #endif /* CONFIG_HIBERNATION */
185 #endif /* CONFIG_DEBUG_PAGEALLOC */