diff options
Diffstat (limited to 'arch/s390/mm/vmem.c')
-rw-r--r-- | arch/s390/mm/vmem.c | 55 |
1 files changed, 48 insertions, 7 deletions
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 3ffc0211dc85..97bce6c97574 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c | |||
@@ -10,10 +10,12 @@ | |||
10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/list.h> | 12 | #include <linux/list.h> |
13 | #include <linux/hugetlb.h> | ||
13 | #include <asm/pgalloc.h> | 14 | #include <asm/pgalloc.h> |
14 | #include <asm/pgtable.h> | 15 | #include <asm/pgtable.h> |
15 | #include <asm/setup.h> | 16 | #include <asm/setup.h> |
16 | #include <asm/tlbflush.h> | 17 | #include <asm/tlbflush.h> |
18 | #include <asm/sections.h> | ||
17 | 19 | ||
18 | static DEFINE_MUTEX(vmem_mutex); | 20 | static DEFINE_MUTEX(vmem_mutex); |
19 | 21 | ||
@@ -113,7 +115,7 @@ static pte_t __init_refok *vmem_pte_alloc(void) | |||
113 | /* | 115 | /* |
114 | * Add a physical memory range to the 1:1 mapping. | 116 | * Add a physical memory range to the 1:1 mapping. |
115 | */ | 117 | */ |
116 | static int vmem_add_range(unsigned long start, unsigned long size) | 118 | static int vmem_add_range(unsigned long start, unsigned long size, int ro) |
117 | { | 119 | { |
118 | unsigned long address; | 120 | unsigned long address; |
119 | pgd_t *pg_dir; | 121 | pgd_t *pg_dir; |
@@ -140,7 +142,19 @@ static int vmem_add_range(unsigned long start, unsigned long size) | |||
140 | pud_populate_kernel(&init_mm, pu_dir, pm_dir); | 142 | pud_populate_kernel(&init_mm, pu_dir, pm_dir); |
141 | } | 143 | } |
142 | 144 | ||
145 | pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0)); | ||
143 | pm_dir = pmd_offset(pu_dir, address); | 146 | pm_dir = pmd_offset(pu_dir, address); |
147 | |||
148 | #ifdef __s390x__ | ||
149 | if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) && | ||
150 | (address + HPAGE_SIZE <= start + size) && | ||
151 | (address >= HPAGE_SIZE)) { | ||
152 | pte_val(pte) |= _SEGMENT_ENTRY_LARGE; | ||
153 | pmd_val(*pm_dir) = pte_val(pte); | ||
154 | address += HPAGE_SIZE - PAGE_SIZE; | ||
155 | continue; | ||
156 | } | ||
157 | #endif | ||
144 | if (pmd_none(*pm_dir)) { | 158 | if (pmd_none(*pm_dir)) { |
145 | pt_dir = vmem_pte_alloc(); | 159 | pt_dir = vmem_pte_alloc(); |
146 | if (!pt_dir) | 160 | if (!pt_dir) |
@@ -149,7 +163,6 @@ static int vmem_add_range(unsigned long start, unsigned long size) | |||
149 | } | 163 | } |
150 | 164 | ||
151 | pt_dir = pte_offset_kernel(pm_dir, address); | 165 | pt_dir = pte_offset_kernel(pm_dir, address); |
152 | pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL); | ||
153 | *pt_dir = pte; | 166 | *pt_dir = pte; |
154 | } | 167 | } |
155 | ret = 0; | 168 | ret = 0; |
@@ -180,6 +193,13 @@ static void vmem_remove_range(unsigned long start, unsigned long size) | |||
180 | pm_dir = pmd_offset(pu_dir, address); | 193 | pm_dir = pmd_offset(pu_dir, address); |
181 | if (pmd_none(*pm_dir)) | 194 | if (pmd_none(*pm_dir)) |
182 | continue; | 195 | continue; |
196 | |||
197 | if (pmd_huge(*pm_dir)) { | ||
198 | pmd_clear_kernel(pm_dir); | ||
199 | address += HPAGE_SIZE - PAGE_SIZE; | ||
200 | continue; | ||
201 | } | ||
202 | |||
183 | pt_dir = pte_offset_kernel(pm_dir, address); | 203 | pt_dir = pte_offset_kernel(pm_dir, address); |
184 | *pt_dir = pte; | 204 | *pt_dir = pte; |
185 | } | 205 | } |
@@ -248,14 +268,14 @@ out: | |||
248 | return ret; | 268 | return ret; |
249 | } | 269 | } |
250 | 270 | ||
251 | static int vmem_add_mem(unsigned long start, unsigned long size) | 271 | static int vmem_add_mem(unsigned long start, unsigned long size, int ro) |
252 | { | 272 | { |
253 | int ret; | 273 | int ret; |
254 | 274 | ||
255 | ret = vmem_add_mem_map(start, size); | 275 | ret = vmem_add_mem_map(start, size); |
256 | if (ret) | 276 | if (ret) |
257 | return ret; | 277 | return ret; |
258 | return vmem_add_range(start, size); | 278 | return vmem_add_range(start, size, ro); |
259 | } | 279 | } |
260 | 280 | ||
261 | /* | 281 | /* |
@@ -338,7 +358,7 @@ int add_shared_memory(unsigned long start, unsigned long size) | |||
338 | if (ret) | 358 | if (ret) |
339 | goto out_free; | 359 | goto out_free; |
340 | 360 | ||
341 | ret = vmem_add_mem(start, size); | 361 | ret = vmem_add_mem(start, size, 0); |
342 | if (ret) | 362 | if (ret) |
343 | goto out_remove; | 363 | goto out_remove; |
344 | 364 | ||
@@ -374,14 +394,35 @@ out: | |||
374 | */ | 394 | */ |
375 | void __init vmem_map_init(void) | 395 | void __init vmem_map_init(void) |
376 | { | 396 | { |
397 | unsigned long ro_start, ro_end; | ||
398 | unsigned long start, end; | ||
377 | int i; | 399 | int i; |
378 | 400 | ||
379 | INIT_LIST_HEAD(&init_mm.context.crst_list); | 401 | INIT_LIST_HEAD(&init_mm.context.crst_list); |
380 | INIT_LIST_HEAD(&init_mm.context.pgtable_list); | 402 | INIT_LIST_HEAD(&init_mm.context.pgtable_list); |
381 | init_mm.context.noexec = 0; | 403 | init_mm.context.noexec = 0; |
382 | NODE_DATA(0)->node_mem_map = VMEM_MAP; | 404 | NODE_DATA(0)->node_mem_map = VMEM_MAP; |
383 | for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) | 405 | ro_start = ((unsigned long)&_stext) & PAGE_MASK; |
384 | vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size); | 406 | ro_end = PFN_ALIGN((unsigned long)&_eshared); |
407 | for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { | ||
408 | start = memory_chunk[i].addr; | ||
409 | end = memory_chunk[i].addr + memory_chunk[i].size; | ||
410 | if (start >= ro_end || end <= ro_start) | ||
411 | vmem_add_mem(start, end - start, 0); | ||
412 | else if (start >= ro_start && end <= ro_end) | ||
413 | vmem_add_mem(start, end - start, 1); | ||
414 | else if (start >= ro_start) { | ||
415 | vmem_add_mem(start, ro_end - start, 1); | ||
416 | vmem_add_mem(ro_end, end - ro_end, 0); | ||
417 | } else if (end < ro_end) { | ||
418 | vmem_add_mem(start, ro_start - start, 0); | ||
419 | vmem_add_mem(ro_start, end - ro_start, 1); | ||
420 | } else { | ||
421 | vmem_add_mem(start, ro_start - start, 0); | ||
422 | vmem_add_mem(ro_start, ro_end - ro_start, 1); | ||
423 | vmem_add_mem(ro_end, end - ro_end, 0); | ||
424 | } | ||
425 | } | ||
385 | } | 426 | } |
386 | 427 | ||
387 | /* | 428 | /* |