1
2
3
4
5
6#include <linux/bootmem.h>
7#include <linux/pfn.h>
8#include <linux/mm.h>
9#include <linux/init.h>
10#include <linux/list.h>
11#include <linux/hugetlb.h>
12#include <linux/slab.h>
13#include <linux/memblock.h>
14#include <asm/cacheflush.h>
15#include <asm/pgalloc.h>
16#include <asm/pgtable.h>
17#include <asm/setup.h>
18#include <asm/tlbflush.h>
19#include <asm/sections.h>
20#include <asm/set_memory.h>
21
22static DEFINE_MUTEX(vmem_mutex);
23
24struct memory_segment {
25 struct list_head list;
26 unsigned long start;
27 unsigned long size;
28};
29
30static LIST_HEAD(mem_segs);
31
32static void __ref *vmem_alloc_pages(unsigned int order)
33{
34 unsigned long size = PAGE_SIZE << order;
35
36 if (slab_is_available())
37 return (void *)__get_free_pages(GFP_KERNEL, order);
38 return (void *) memblock_alloc(size, size);
39}
40
41static inline p4d_t *vmem_p4d_alloc(void)
42{
43 p4d_t *p4d = NULL;
44
45 p4d = vmem_alloc_pages(2);
46 if (!p4d)
47 return NULL;
48 clear_table((unsigned long *) p4d, _REGION2_ENTRY_EMPTY, PAGE_SIZE * 4);
49 return p4d;
50}
51
52static inline pud_t *vmem_pud_alloc(void)
53{
54 pud_t *pud = NULL;
55
56 pud = vmem_alloc_pages(2);
57 if (!pud)
58 return NULL;
59 clear_table((unsigned long *) pud, _REGION3_ENTRY_EMPTY, PAGE_SIZE * 4);
60 return pud;
61}
62
63pmd_t *vmem_pmd_alloc(void)
64{
65 pmd_t *pmd = NULL;
66
67 pmd = vmem_alloc_pages(2);
68 if (!pmd)
69 return NULL;
70 clear_table((unsigned long *) pmd, _SEGMENT_ENTRY_EMPTY, PAGE_SIZE * 4);
71 return pmd;
72}
73
74pte_t __ref *vmem_pte_alloc(void)
75{
76 unsigned long size = PTRS_PER_PTE * sizeof(pte_t);
77 pte_t *pte;
78
79 if (slab_is_available())
80 pte = (pte_t *) page_table_alloc(&init_mm);
81 else
82 pte = (pte_t *) memblock_alloc(size, size);
83 if (!pte)
84 return NULL;
85 clear_table((unsigned long *) pte, _PAGE_INVALID, size);
86 return pte;
87}
88
89
90
91
92static int vmem_add_mem(unsigned long start, unsigned long size)
93{
94 unsigned long pgt_prot, sgt_prot, r3_prot;
95 unsigned long pages4k, pages1m, pages2g;
96 unsigned long end = start + size;
97 unsigned long address = start;
98 pgd_t *pg_dir;
99 p4d_t *p4_dir;
100 pud_t *pu_dir;
101 pmd_t *pm_dir;
102 pte_t *pt_dir;
103 int ret = -ENOMEM;
104
105 pgt_prot = pgprot_val(PAGE_KERNEL);
106 sgt_prot = pgprot_val(SEGMENT_KERNEL);
107 r3_prot = pgprot_val(REGION3_KERNEL);
108 if (!MACHINE_HAS_NX) {
109 pgt_prot &= ~_PAGE_NOEXEC;
110 sgt_prot &= ~_SEGMENT_ENTRY_NOEXEC;
111 r3_prot &= ~_REGION_ENTRY_NOEXEC;
112 }
113 pages4k = pages1m = pages2g = 0;
114 while (address < end) {
115 pg_dir = pgd_offset_k(address);
116 if (pgd_none(*pg_dir)) {
117 p4_dir = vmem_p4d_alloc();
118 if (!p4_dir)
119 goto out;
120 pgd_populate(&init_mm, pg_dir, p4_dir);
121 }
122 p4_dir = p4d_offset(pg_dir, address);
123 if (p4d_none(*p4_dir)) {
124 pu_dir = vmem_pud_alloc();
125 if (!pu_dir)
126 goto out;
127 p4d_populate(&init_mm, p4_dir, pu_dir);
128 }
129 pu_dir = pud_offset(p4_dir, address);
130 if (MACHINE_HAS_EDAT2 && pud_none(*pu_dir) && address &&
131 !(address & ~PUD_MASK) && (address + PUD_SIZE <= end) &&
132 !debug_pagealloc_enabled()) {
133 pud_val(*pu_dir) = address | r3_prot;
134 address += PUD_SIZE;
135 pages2g++;
136 continue;
137 }
138 if (pud_none(*pu_dir)) {
139 pm_dir = vmem_pmd_alloc();
140 if (!pm_dir)
141 goto out;
142 pud_populate(&init_mm, pu_dir, pm_dir);
143 }
144 pm_dir = pmd_offset(pu_dir, address);
145 if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address &&
146 !(address & ~PMD_MASK) && (address + PMD_SIZE <= end) &&
147 !debug_pagealloc_enabled()) {
148 pmd_val(*pm_dir) = address | sgt_prot;
149 address += PMD_SIZE;
150 pages1m++;
151 continue;
152 }
153 if (pmd_none(*pm_dir)) {
154 pt_dir = vmem_pte_alloc();
155 if (!pt_dir)
156 goto out;
157 pmd_populate(&init_mm, pm_dir, pt_dir);
158 }
159
160 pt_dir = pte_offset_kernel(pm_dir, address);
161 pte_val(*pt_dir) = address | pgt_prot;
162 address += PAGE_SIZE;
163 pages4k++;
164 }
165 ret = 0;
166out:
167 update_page_count(PG_DIRECT_MAP_4K, pages4k);
168 update_page_count(PG_DIRECT_MAP_1M, pages1m);
169 update_page_count(PG_DIRECT_MAP_2G, pages2g);
170 return ret;
171}
172
173
174
175
176
177static void vmem_remove_range(unsigned long start, unsigned long size)
178{
179 unsigned long pages4k, pages1m, pages2g;
180 unsigned long end = start + size;
181 unsigned long address = start;
182 pgd_t *pg_dir;
183 p4d_t *p4_dir;
184 pud_t *pu_dir;
185 pmd_t *pm_dir;
186 pte_t *pt_dir;
187
188 pages4k = pages1m = pages2g = 0;
189 while (address < end) {
190 pg_dir = pgd_offset_k(address);
191 if (pgd_none(*pg_dir)) {
192 address += PGDIR_SIZE;
193 continue;
194 }
195 p4_dir = p4d_offset(pg_dir, address);
196 if (p4d_none(*p4_dir)) {
197 address += P4D_SIZE;
198 continue;
199 }
200 pu_dir = pud_offset(p4_dir, address);
201 if (pud_none(*pu_dir)) {
202 address += PUD_SIZE;
203 continue;
204 }
205 if (pud_large(*pu_dir)) {
206 pud_clear(pu_dir);
207 address += PUD_SIZE;
208 pages2g++;
209 continue;
210 }
211 pm_dir = pmd_offset(pu_dir, address);
212 if (pmd_none(*pm_dir)) {
213 address += PMD_SIZE;
214 continue;
215 }
216 if (pmd_large(*pm_dir)) {
217 pmd_clear(pm_dir);
218 address += PMD_SIZE;
219 pages1m++;
220 continue;
221 }
222 pt_dir = pte_offset_kernel(pm_dir, address);
223 pte_clear(&init_mm, address, pt_dir);
224 address += PAGE_SIZE;
225 pages4k++;
226 }
227 flush_tlb_kernel_range(start, end);
228 update_page_count(PG_DIRECT_MAP_4K, -pages4k);
229 update_page_count(PG_DIRECT_MAP_1M, -pages1m);
230 update_page_count(PG_DIRECT_MAP_2G, -pages2g);
231}
232
233
234
235
236int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
237{
238 unsigned long pgt_prot, sgt_prot;
239 unsigned long address = start;
240 pgd_t *pg_dir;
241 p4d_t *p4_dir;
242 pud_t *pu_dir;
243 pmd_t *pm_dir;
244 pte_t *pt_dir;
245 int ret = -ENOMEM;
246
247 pgt_prot = pgprot_val(PAGE_KERNEL);
248 sgt_prot = pgprot_val(SEGMENT_KERNEL);
249 if (!MACHINE_HAS_NX) {
250 pgt_prot &= ~_PAGE_NOEXEC;
251 sgt_prot &= ~_SEGMENT_ENTRY_NOEXEC;
252 }
253 for (address = start; address < end;) {
254 pg_dir = pgd_offset_k(address);
255 if (pgd_none(*pg_dir)) {
256 p4_dir = vmem_p4d_alloc();
257 if (!p4_dir)
258 goto out;
259 pgd_populate(&init_mm, pg_dir, p4_dir);
260 }
261
262 p4_dir = p4d_offset(pg_dir, address);
263 if (p4d_none(*p4_dir)) {
264 pu_dir = vmem_pud_alloc();
265 if (!pu_dir)
266 goto out;
267 p4d_populate(&init_mm, p4_dir, pu_dir);
268 }
269
270 pu_dir = pud_offset(p4_dir, address);
271 if (pud_none(*pu_dir)) {
272 pm_dir = vmem_pmd_alloc();
273 if (!pm_dir)
274 goto out;
275 pud_populate(&init_mm, pu_dir, pm_dir);
276 }
277
278 pm_dir = pmd_offset(pu_dir, address);
279 if (pmd_none(*pm_dir)) {
280
281
282
283
284
285
286 if (MACHINE_HAS_EDAT1) {
287 void *new_page;
288
289 new_page = vmemmap_alloc_block(PMD_SIZE, node);
290 if (!new_page)
291 goto out;
292 pmd_val(*pm_dir) = __pa(new_page) | sgt_prot;
293 address = (address + PMD_SIZE) & PMD_MASK;
294 continue;
295 }
296 pt_dir = vmem_pte_alloc();
297 if (!pt_dir)
298 goto out;
299 pmd_populate(&init_mm, pm_dir, pt_dir);
300 } else if (pmd_large(*pm_dir)) {
301 address = (address + PMD_SIZE) & PMD_MASK;
302 continue;
303 }
304
305 pt_dir = pte_offset_kernel(pm_dir, address);
306 if (pte_none(*pt_dir)) {
307 void *new_page;
308
309 new_page = vmemmap_alloc_block(PAGE_SIZE, node);
310 if (!new_page)
311 goto out;
312 pte_val(*pt_dir) = __pa(new_page) | pgt_prot;
313 }
314 address += PAGE_SIZE;
315 }
316 ret = 0;
317out:
318 return ret;
319}
320
321void vmemmap_free(unsigned long start, unsigned long end)
322{
323}
324
325
326
327
328
329static int insert_memory_segment(struct memory_segment *seg)
330{
331 struct memory_segment *tmp;
332
333 if (seg->start + seg->size > VMEM_MAX_PHYS ||
334 seg->start + seg->size < seg->start)
335 return -ERANGE;
336
337 list_for_each_entry(tmp, &mem_segs, list) {
338 if (seg->start >= tmp->start + tmp->size)
339 continue;
340 if (seg->start + seg->size <= tmp->start)
341 continue;
342 return -ENOSPC;
343 }
344 list_add(&seg->list, &mem_segs);
345 return 0;
346}
347
348
349
350
351static void remove_memory_segment(struct memory_segment *seg)
352{
353 list_del(&seg->list);
354}
355
356static void __remove_shared_memory(struct memory_segment *seg)
357{
358 remove_memory_segment(seg);
359 vmem_remove_range(seg->start, seg->size);
360}
361
362int vmem_remove_mapping(unsigned long start, unsigned long size)
363{
364 struct memory_segment *seg;
365 int ret;
366
367 mutex_lock(&vmem_mutex);
368
369 ret = -ENOENT;
370 list_for_each_entry(seg, &mem_segs, list) {
371 if (seg->start == start && seg->size == size)
372 break;
373 }
374
375 if (seg->start != start || seg->size != size)
376 goto out;
377
378 ret = 0;
379 __remove_shared_memory(seg);
380 kfree(seg);
381out:
382 mutex_unlock(&vmem_mutex);
383 return ret;
384}
385
386int vmem_add_mapping(unsigned long start, unsigned long size)
387{
388 struct memory_segment *seg;
389 int ret;
390
391 mutex_lock(&vmem_mutex);
392 ret = -ENOMEM;
393 seg = kzalloc(sizeof(*seg), GFP_KERNEL);
394 if (!seg)
395 goto out;
396 seg->start = start;
397 seg->size = size;
398
399 ret = insert_memory_segment(seg);
400 if (ret)
401 goto out_free;
402
403 ret = vmem_add_mem(start, size);
404 if (ret)
405 goto out_remove;
406 goto out;
407
408out_remove:
409 __remove_shared_memory(seg);
410out_free:
411 kfree(seg);
412out:
413 mutex_unlock(&vmem_mutex);
414 return ret;
415}
416
417
418
419
420
421
422void __init vmem_map_init(void)
423{
424 struct memblock_region *reg;
425
426 for_each_memblock(memory, reg)
427 vmem_add_mem(reg->base, reg->size);
428 __set_memory((unsigned long) _stext,
429 (_etext - _stext) >> PAGE_SHIFT,
430 SET_MEMORY_RO | SET_MEMORY_X);
431 __set_memory((unsigned long) _etext,
432 (_eshared - _etext) >> PAGE_SHIFT,
433 SET_MEMORY_RO);
434 __set_memory((unsigned long) _sinittext,
435 (_einittext - _sinittext) >> PAGE_SHIFT,
436 SET_MEMORY_RO | SET_MEMORY_X);
437 pr_info("Write protected kernel read-only data: %luk\n",
438 (_eshared - _stext) >> 10);
439}
440
441
442
443
444
445static int __init vmem_convert_memory_chunk(void)
446{
447 struct memblock_region *reg;
448 struct memory_segment *seg;
449
450 mutex_lock(&vmem_mutex);
451 for_each_memblock(memory, reg) {
452 seg = kzalloc(sizeof(*seg), GFP_KERNEL);
453 if (!seg)
454 panic("Out of memory...\n");
455 seg->start = reg->base;
456 seg->size = reg->size;
457 insert_memory_segment(seg);
458 }
459 mutex_unlock(&vmem_mutex);
460 return 0;
461}
462
463core_initcall(vmem_convert_memory_chunk);
464