diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2012-03-05 06:49:27 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2012-09-17 08:41:57 -0400 |
commit | 1d18c47c735e8adfe531fc41fae31e98f86b68fe (patch) | |
tree | b63f253304e2d955e1a17d12e4f0dc94312f58ea /arch/arm64/mm/mmap.c | |
parent | c1cc1552616d0f354d040823151e61634e7ad01f (diff) |
arm64: MMU fault handling and page table management
This patch adds support for the handling of the MMU faults (exception
entry code introduced by a previous patch) and page table management.
The user translation table is pointed to by TTBR0 and the kernel one
(swapper_pg_dir) by TTBR1. There is no translation information shared or
address space overlapping between user and kernel page tables.
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Acked-by: Nicolas Pitre <nico@linaro.org>
Acked-by: Olof Johansson <olof@lixom.net>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/arm64/mm/mmap.c')
-rw-r--r-- | arch/arm64/mm/mmap.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c new file mode 100644 index 000000000000..7c7be7855638 --- /dev/null +++ b/arch/arm64/mm/mmap.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * Based on arch/arm/mm/mmap.c | ||
3 | * | ||
4 | * Copyright (C) 2012 ARM Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/elf.h> | ||
20 | #include <linux/fs.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/mman.h> | ||
23 | #include <linux/export.h> | ||
24 | #include <linux/shm.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/personality.h> | ||
28 | #include <linux/random.h> | ||
29 | |||
30 | #include <asm/cputype.h> | ||
31 | |||
32 | /* | ||
33 | * Leave enough space between the mmap area and the stack to honour ulimit in | ||
34 | * the face of randomisation. | ||
35 | */ | ||
36 | #define MIN_GAP (SZ_128M + ((STACK_RND_MASK << PAGE_SHIFT) + 1)) | ||
37 | #define MAX_GAP (STACK_TOP/6*5) | ||
38 | |||
39 | static int mmap_is_legacy(void) | ||
40 | { | ||
41 | if (current->personality & ADDR_COMPAT_LAYOUT) | ||
42 | return 1; | ||
43 | |||
44 | if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) | ||
45 | return 1; | ||
46 | |||
47 | return sysctl_legacy_va_layout; | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * Since get_random_int() returns the same value within a 1 jiffy window, we | ||
52 | * will almost always get the same randomisation for the stack and mmap | ||
53 | * region. This will mean the relative distance between stack and mmap will be | ||
54 | * the same. | ||
55 | * | ||
56 | * To avoid this we can shift the randomness by 1 bit. | ||
57 | */ | ||
58 | static unsigned long mmap_rnd(void) | ||
59 | { | ||
60 | unsigned long rnd = 0; | ||
61 | |||
62 | if (current->flags & PF_RANDOMIZE) | ||
63 | rnd = (long)get_random_int() & (STACK_RND_MASK >> 1); | ||
64 | |||
65 | return rnd << (PAGE_SHIFT + 1); | ||
66 | } | ||
67 | |||
68 | static unsigned long mmap_base(void) | ||
69 | { | ||
70 | unsigned long gap = rlimit(RLIMIT_STACK); | ||
71 | |||
72 | if (gap < MIN_GAP) | ||
73 | gap = MIN_GAP; | ||
74 | else if (gap > MAX_GAP) | ||
75 | gap = MAX_GAP; | ||
76 | |||
77 | return PAGE_ALIGN(STACK_TOP - gap - mmap_rnd()); | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * This function, called very early during the creation of a new process VM | ||
82 | * image, sets up which VM layout function to use: | ||
83 | */ | ||
84 | void arch_pick_mmap_layout(struct mm_struct *mm) | ||
85 | { | ||
86 | /* | ||
87 | * Fall back to the standard layout if the personality bit is set, or | ||
88 | * if the expected stack growth is unlimited: | ||
89 | */ | ||
90 | if (mmap_is_legacy()) { | ||
91 | mm->mmap_base = TASK_UNMAPPED_BASE; | ||
92 | mm->get_unmapped_area = arch_get_unmapped_area; | ||
93 | mm->unmap_area = arch_unmap_area; | ||
94 | } else { | ||
95 | mm->mmap_base = mmap_base(); | ||
96 | mm->get_unmapped_area = arch_get_unmapped_area_topdown; | ||
97 | mm->unmap_area = arch_unmap_area_topdown; | ||
98 | } | ||
99 | } | ||
100 | EXPORT_SYMBOL_GPL(arch_pick_mmap_layout); | ||
101 | |||
102 | |||
103 | /* | ||
104 | * You really shouldn't be using read() or write() on /dev/mem. This might go | ||
105 | * away in the future. | ||
106 | */ | ||
107 | int valid_phys_addr_range(unsigned long addr, size_t size) | ||
108 | { | ||
109 | if (addr < PHYS_OFFSET) | ||
110 | return 0; | ||
111 | if (addr + size > __pa(high_memory - 1) + 1) | ||
112 | return 0; | ||
113 | |||
114 | return 1; | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * Do not allow /dev/mem mappings beyond the supported physical range. | ||
119 | */ | ||
120 | int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) | ||
121 | { | ||
122 | return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK); | ||
123 | } | ||
124 | |||
125 | #ifdef CONFIG_STRICT_DEVMEM | ||
126 | |||
127 | #include <linux/ioport.h> | ||
128 | |||
129 | /* | ||
130 | * devmem_is_allowed() checks to see if /dev/mem access to a certain address | ||
131 | * is valid. The argument is a physical page number. We mimic x86 here by | ||
132 | * disallowing access to system RAM as well as device-exclusive MMIO regions. | ||
133 | * This effectively disable read()/write() on /dev/mem. | ||
134 | */ | ||
135 | int devmem_is_allowed(unsigned long pfn) | ||
136 | { | ||
137 | if (iomem_is_exclusive(pfn << PAGE_SHIFT)) | ||
138 | return 0; | ||
139 | if (!page_is_ram(pfn)) | ||
140 | return 1; | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | #endif | ||