aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/mm')
-rw-r--r--arch/arm64/mm/Makefile1
-rw-r--r--arch/arm64/mm/fault.c19
-rw-r--r--arch/arm64/mm/flush.c37
-rw-r--r--arch/arm64/mm/hugetlbpage.c70
-rw-r--r--arch/arm64/mm/init.c65
-rw-r--r--arch/arm64/mm/mm.h1
-rw-r--r--arch/arm64/mm/mmu.c20
7 files changed, 102 insertions, 111 deletions
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index 3140a2abcdc2..b51d36401d83 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -2,3 +2,4 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
2 cache.o copypage.o flush.o \ 2 cache.o copypage.o flush.o \
3 ioremap.o mmap.o pgd.o mmu.o \ 3 ioremap.o mmap.o pgd.o mmu.o \
4 context.o tlb.o proc.o 4 context.o tlb.o proc.o
5obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 1426468b77f3..0ecac8980aae 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -365,17 +365,6 @@ static int __kprobes do_translation_fault(unsigned long addr,
365} 365}
366 366
367/* 367/*
368 * Some section permission faults need to be handled gracefully. They can
369 * happen due to a __{get,put}_user during an oops.
370 */
371static int do_sect_fault(unsigned long addr, unsigned int esr,
372 struct pt_regs *regs)
373{
374 do_bad_area(addr, esr, regs);
375 return 0;
376}
377
378/*
379 * This abort handler always returns "fault". 368 * This abort handler always returns "fault".
380 */ 369 */
381static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs) 370static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
@@ -398,12 +387,12 @@ static struct fault_info {
398 { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" }, 387 { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
399 { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, 388 { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
400 { do_bad, SIGBUS, 0, "reserved access flag fault" }, 389 { do_bad, SIGBUS, 0, "reserved access flag fault" },
401 { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" }, 390 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
402 { do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, 391 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
403 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" }, 392 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
404 { do_bad, SIGBUS, 0, "reserved permission fault" }, 393 { do_bad, SIGBUS, 0, "reserved permission fault" },
405 { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" }, 394 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
406 { do_sect_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" }, 395 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
407 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" }, 396 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
408 { do_bad, SIGBUS, 0, "synchronous external abort" }, 397 { do_bad, SIGBUS, 0, "synchronous external abort" },
409 { do_bad, SIGBUS, 0, "asynchronous external abort" }, 398 { do_bad, SIGBUS, 0, "asynchronous external abort" },
diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c
index 88611c3a421a..e4193e3adc7f 100644
--- a/arch/arm64/mm/flush.c
+++ b/arch/arm64/mm/flush.c
@@ -70,23 +70,16 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
70#endif 70#endif
71} 71}
72 72
73void __flush_dcache_page(struct page *page)
74{
75 __flush_dcache_area(page_address(page), PAGE_SIZE);
76}
77
78void __sync_icache_dcache(pte_t pte, unsigned long addr) 73void __sync_icache_dcache(pte_t pte, unsigned long addr)
79{ 74{
80 unsigned long pfn; 75 struct page *page = pte_page(pte);
81 struct page *page;
82 76
83 pfn = pte_pfn(pte); 77 /* no flushing needed for anonymous pages */
84 if (!pfn_valid(pfn)) 78 if (!page_mapping(page))
85 return; 79 return;
86 80
87 page = pfn_to_page(pfn);
88 if (!test_and_set_bit(PG_dcache_clean, &page->flags)) { 81 if (!test_and_set_bit(PG_dcache_clean, &page->flags)) {
89 __flush_dcache_page(page); 82 __flush_dcache_area(page_address(page), PAGE_SIZE);
90 __flush_icache_all(); 83 __flush_icache_all();
91 } else if (icache_is_aivivt()) { 84 } else if (icache_is_aivivt()) {
92 __flush_icache_all(); 85 __flush_icache_all();
@@ -94,28 +87,14 @@ void __sync_icache_dcache(pte_t pte, unsigned long addr)
94} 87}
95 88
96/* 89/*
97 * Ensure cache coherency between kernel mapping and userspace mapping of this 90 * This function is called when a page has been modified by the kernel. Mark
98 * page. 91 * it as dirty for later flushing when mapped in user space (if executable,
92 * see __sync_icache_dcache).
99 */ 93 */
100void flush_dcache_page(struct page *page) 94void flush_dcache_page(struct page *page)
101{ 95{
102 struct address_space *mapping; 96 if (test_bit(PG_dcache_clean, &page->flags))
103
104 /*
105 * The zero page is never written to, so never has any dirty cache
106 * lines, and therefore never needs to be flushed.
107 */
108 if (page == ZERO_PAGE(0))
109 return;
110
111 mapping = page_mapping(page);
112 if (mapping && mapping_mapped(mapping)) {
113 __flush_dcache_page(page);
114 __flush_icache_all();
115 set_bit(PG_dcache_clean, &page->flags);
116 } else {
117 clear_bit(PG_dcache_clean, &page->flags); 97 clear_bit(PG_dcache_clean, &page->flags);
118 }
119} 98}
120EXPORT_SYMBOL(flush_dcache_page); 99EXPORT_SYMBOL(flush_dcache_page);
121 100
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
new file mode 100644
index 000000000000..2fc8258bab2d
--- /dev/null
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -0,0 +1,70 @@
1/*
2 * arch/arm64/mm/hugetlbpage.c
3 *
4 * Copyright (C) 2013 Linaro Ltd.
5 *
6 * Based on arch/x86/mm/hugetlbpage.c.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <linux/init.h>
23#include <linux/fs.h>
24#include <linux/mm.h>
25#include <linux/hugetlb.h>
26#include <linux/pagemap.h>
27#include <linux/err.h>
28#include <linux/sysctl.h>
29#include <asm/mman.h>
30#include <asm/tlb.h>
31#include <asm/tlbflush.h>
32#include <asm/pgalloc.h>
33
34#ifndef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
35int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
36{
37 return 0;
38}
39#endif
40
41struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
42 int write)
43{
44 return ERR_PTR(-EINVAL);
45}
46
47int pmd_huge(pmd_t pmd)
48{
49 return !(pmd_val(pmd) & PMD_TABLE_BIT);
50}
51
52int pud_huge(pud_t pud)
53{
54 return !(pud_val(pud) & PUD_TABLE_BIT);
55}
56
57static __init int setup_hugepagesz(char *opt)
58{
59 unsigned long ps = memparse(opt, &opt);
60 if (ps == PMD_SIZE) {
61 hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT);
62 } else if (ps == PUD_SIZE) {
63 hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
64 } else {
65 pr_err("hugepagesz: Unsupported page size %lu M\n", ps >> 20);
66 return 0;
67 }
68 return 1;
69}
70__setup("hugepagesz=", setup_hugepagesz);
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index f497ca77925a..67e8d7ce3fe7 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -197,14 +197,6 @@ void __init bootmem_init(void)
197 max_pfn = max_low_pfn = max; 197 max_pfn = max_low_pfn = max;
198} 198}
199 199
200/*
201 * Poison init memory with an undefined instruction (0x0).
202 */
203static inline void poison_init_mem(void *s, size_t count)
204{
205 memset(s, 0, count);
206}
207
208#ifndef CONFIG_SPARSEMEM_VMEMMAP 200#ifndef CONFIG_SPARSEMEM_VMEMMAP
209static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn) 201static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn)
210{ 202{
@@ -280,59 +272,17 @@ static void __init free_unused_memmap(void)
280 */ 272 */
281void __init mem_init(void) 273void __init mem_init(void)
282{ 274{
283 unsigned long reserved_pages, free_pages;
284 struct memblock_region *reg;
285
286 arm64_swiotlb_init(); 275 arm64_swiotlb_init();
287 276
288 max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; 277 max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
289 278
290#ifndef CONFIG_SPARSEMEM_VMEMMAP 279#ifndef CONFIG_SPARSEMEM_VMEMMAP
291 /* this will put all unused low memory onto the freelists */
292 free_unused_memmap(); 280 free_unused_memmap();
293#endif 281#endif
282 /* this will put all unused low memory onto the freelists */
283 free_all_bootmem();
294 284
295 totalram_pages += free_all_bootmem(); 285 mem_init_print_info(NULL);
296
297 reserved_pages = free_pages = 0;
298
299 for_each_memblock(memory, reg) {
300 unsigned int pfn1, pfn2;
301 struct page *page, *end;
302
303 pfn1 = __phys_to_pfn(reg->base);
304 pfn2 = pfn1 + __phys_to_pfn(reg->size);
305
306 page = pfn_to_page(pfn1);
307 end = pfn_to_page(pfn2 - 1) + 1;
308
309 do {
310 if (PageReserved(page))
311 reserved_pages++;
312 else if (!page_count(page))
313 free_pages++;
314 page++;
315 } while (page < end);
316 }
317
318 /*
319 * Since our memory may not be contiguous, calculate the real number
320 * of pages we have in this system.
321 */
322 pr_info("Memory:");
323 num_physpages = 0;
324 for_each_memblock(memory, reg) {
325 unsigned long pages = memblock_region_memory_end_pfn(reg) -
326 memblock_region_memory_base_pfn(reg);
327 num_physpages += pages;
328 printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
329 }
330 printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
331
332 pr_notice("Memory: %luk/%luk available, %luk reserved\n",
333 nr_free_pages() << (PAGE_SHIFT-10),
334 free_pages << (PAGE_SHIFT-10),
335 reserved_pages << (PAGE_SHIFT-10));
336 286
337#define MLK(b, t) b, t, ((t) - (b)) >> 10 287#define MLK(b, t) b, t, ((t) - (b)) >> 10
338#define MLM(b, t) b, t, ((t) - (b)) >> 20 288#define MLM(b, t) b, t, ((t) - (b)) >> 20
@@ -374,7 +324,7 @@ void __init mem_init(void)
374 BUILD_BUG_ON(TASK_SIZE_64 > MODULES_VADDR); 324 BUILD_BUG_ON(TASK_SIZE_64 > MODULES_VADDR);
375 BUG_ON(TASK_SIZE_64 > MODULES_VADDR); 325 BUG_ON(TASK_SIZE_64 > MODULES_VADDR);
376 326
377 if (PAGE_SIZE >= 16384 && num_physpages <= 128) { 327 if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
378 extern int sysctl_overcommit_memory; 328 extern int sysctl_overcommit_memory;
379 /* 329 /*
380 * On a machine this small we won't get anywhere without 330 * On a machine this small we won't get anywhere without
@@ -386,7 +336,6 @@ void __init mem_init(void)
386 336
387void free_initmem(void) 337void free_initmem(void)
388{ 338{
389 poison_init_mem(__init_begin, __init_end - __init_begin);
390 free_initmem_default(0); 339 free_initmem_default(0);
391} 340}
392 341
@@ -396,10 +345,8 @@ static int keep_initrd;
396 345
397void free_initrd_mem(unsigned long start, unsigned long end) 346void free_initrd_mem(unsigned long start, unsigned long end)
398{ 347{
399 if (!keep_initrd) { 348 if (!keep_initrd)
400 poison_init_mem((void *)start, PAGE_ALIGN(end) - start); 349 free_reserved_area((void *)start, (void *)end, 0, "initrd");
401 free_reserved_area(start, end, 0, "initrd");
402 }
403} 350}
404 351
405static int __init keepinitrd_setup(char *__unused) 352static int __init keepinitrd_setup(char *__unused)
diff --git a/arch/arm64/mm/mm.h b/arch/arm64/mm/mm.h
index 916701e6d040..d519f4f50c8c 100644
--- a/arch/arm64/mm/mm.h
+++ b/arch/arm64/mm/mm.h
@@ -1,3 +1,2 @@
1extern void __flush_dcache_page(struct page *page);
2extern void __init bootmem_init(void); 1extern void __init bootmem_init(void);
3extern void __init arm64_swiotlb_init(void); 2extern void __init arm64_swiotlb_init(void);
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index eeecc9c8ed68..a8d1059b91b2 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -297,6 +297,16 @@ static void __init map_mem(void)
297{ 297{
298 struct memblock_region *reg; 298 struct memblock_region *reg;
299 299
300 /*
301 * Temporarily limit the memblock range. We need to do this as
302 * create_mapping requires puds, pmds and ptes to be allocated from
303 * memory addressable from the initial direct kernel mapping.
304 *
305 * The initial direct kernel mapping, located at swapper_pg_dir,
306 * gives us PGDIR_SIZE memory starting from PHYS_OFFSET (aligned).
307 */
308 memblock_set_current_limit((PHYS_OFFSET & PGDIR_MASK) + PGDIR_SIZE);
309
300 /* map all the memory banks */ 310 /* map all the memory banks */
301 for_each_memblock(memory, reg) { 311 for_each_memblock(memory, reg) {
302 phys_addr_t start = reg->base; 312 phys_addr_t start = reg->base;
@@ -307,6 +317,9 @@ static void __init map_mem(void)
307 317
308 create_mapping(start, __phys_to_virt(start), end - start); 318 create_mapping(start, __phys_to_virt(start), end - start);
309 } 319 }
320
321 /* Limit no longer required. */
322 memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
310} 323}
311 324
312/* 325/*
@@ -317,12 +330,6 @@ void __init paging_init(void)
317{ 330{
318 void *zero_page; 331 void *zero_page;
319 332
320 /*
321 * Maximum PGDIR_SIZE addressable via the initial direct kernel
322 * mapping in swapper_pg_dir.
323 */
324 memblock_set_current_limit((PHYS_OFFSET & PGDIR_MASK) + PGDIR_SIZE);
325
326 init_mem_pgprot(); 333 init_mem_pgprot();
327 map_mem(); 334 map_mem();
328 335
@@ -339,7 +346,6 @@ void __init paging_init(void)
339 bootmem_init(); 346 bootmem_init();
340 347
341 empty_zero_page = virt_to_page(zero_page); 348 empty_zero_page = virt_to_page(zero_page);
342 __flush_dcache_page(empty_zero_page);
343 349
344 /* 350 /*
345 * TTBR0 is only used for the identity mapping at this stage. Make it 351 * TTBR0 is only used for the identity mapping at this stage. Make it