diff options
Diffstat (limited to 'include/asm-s390/pgtable.h')
-rw-r--r-- | include/asm-s390/pgtable.h | 163 |
1 files changed, 143 insertions, 20 deletions
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 2d968a69ed1f..13c16546eff5 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h | |||
@@ -40,6 +40,7 @@ struct mm_struct; | |||
40 | 40 | ||
41 | extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); | 41 | extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); |
42 | extern void paging_init(void); | 42 | extern void paging_init(void); |
43 | extern void vmem_map_init(void); | ||
43 | 44 | ||
44 | /* | 45 | /* |
45 | * The S390 doesn't have any external MMU info: the kernel page | 46 | * The S390 doesn't have any external MMU info: the kernel page |
@@ -107,23 +108,25 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
107 | * The vmalloc() routines leaves a hole of 4kB between each vmalloced | 108 | * The vmalloc() routines leaves a hole of 4kB between each vmalloced |
108 | * area for the same reason. ;) | 109 | * area for the same reason. ;) |
109 | */ | 110 | */ |
111 | extern unsigned long vmalloc_end; | ||
110 | #define VMALLOC_OFFSET (8*1024*1024) | 112 | #define VMALLOC_OFFSET (8*1024*1024) |
111 | #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \ | 113 | #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \ |
112 | & ~(VMALLOC_OFFSET-1)) | 114 | & ~(VMALLOC_OFFSET-1)) |
115 | #define VMALLOC_END vmalloc_end | ||
113 | 116 | ||
114 | /* | 117 | /* |
115 | * We need some free virtual space to be able to do vmalloc. | 118 | * We need some free virtual space to be able to do vmalloc. |
116 | * VMALLOC_MIN_SIZE defines the minimum size of the vmalloc | 119 | * VMALLOC_MIN_SIZE defines the minimum size of the vmalloc |
117 | * area. On a machine with 2GB memory we make sure that we | 120 | * area. On a machine with 2GB memory we make sure that we |
118 | * have at least 128MB free space for vmalloc. On a machine | 121 | * have at least 128MB free space for vmalloc. On a machine |
119 | * with 4TB we make sure we have at least 1GB. | 122 | * with 4TB we make sure we have at least 128GB. |
120 | */ | 123 | */ |
121 | #ifndef __s390x__ | 124 | #ifndef __s390x__ |
122 | #define VMALLOC_MIN_SIZE 0x8000000UL | 125 | #define VMALLOC_MIN_SIZE 0x8000000UL |
123 | #define VMALLOC_END 0x80000000UL | 126 | #define VMALLOC_END_INIT 0x80000000UL |
124 | #else /* __s390x__ */ | 127 | #else /* __s390x__ */ |
125 | #define VMALLOC_MIN_SIZE 0x40000000UL | 128 | #define VMALLOC_MIN_SIZE 0x2000000000UL |
126 | #define VMALLOC_END 0x40000000000UL | 129 | #define VMALLOC_END_INIT 0x40000000000UL |
127 | #endif /* __s390x__ */ | 130 | #endif /* __s390x__ */ |
128 | 131 | ||
129 | /* | 132 | /* |
@@ -221,6 +224,8 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
221 | #define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */ | 224 | #define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */ |
222 | #define _PAGE_TYPE_RO 0x200 | 225 | #define _PAGE_TYPE_RO 0x200 |
223 | #define _PAGE_TYPE_RW 0x000 | 226 | #define _PAGE_TYPE_RW 0x000 |
227 | #define _PAGE_TYPE_EX_RO 0x202 | ||
228 | #define _PAGE_TYPE_EX_RW 0x002 | ||
224 | 229 | ||
225 | /* | 230 | /* |
226 | * PTE type bits are rather complicated. handle_pte_fault uses pte_present, | 231 | * PTE type bits are rather complicated. handle_pte_fault uses pte_present, |
@@ -241,11 +246,13 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
241 | * _PAGE_TYPE_FILE 11?1 -> 11?1 | 246 | * _PAGE_TYPE_FILE 11?1 -> 11?1 |
242 | * _PAGE_TYPE_RO 0100 -> 1100 | 247 | * _PAGE_TYPE_RO 0100 -> 1100 |
243 | * _PAGE_TYPE_RW 0000 -> 1000 | 248 | * _PAGE_TYPE_RW 0000 -> 1000 |
249 | * _PAGE_TYPE_EX_RO 0110 -> 1110 | ||
250 | * _PAGE_TYPE_EX_RW 0010 -> 1010 | ||
244 | * | 251 | * |
245 | * pte_none is true for bits combinations 1000, 1100 | 252 | * pte_none is true for bits combinations 1000, 1010, 1100, 1110 |
246 | * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001 | 253 | * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001 |
247 | * pte_file is true for bits combinations 1101, 1111 | 254 | * pte_file is true for bits combinations 1101, 1111 |
248 | * swap pte is 1011 and 0001, 0011, 0101, 0111, 1010 and 1110 are invalid. | 255 | * swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid. |
249 | */ | 256 | */ |
250 | 257 | ||
251 | #ifndef __s390x__ | 258 | #ifndef __s390x__ |
@@ -310,33 +317,100 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
310 | #define PAGE_NONE __pgprot(_PAGE_TYPE_NONE) | 317 | #define PAGE_NONE __pgprot(_PAGE_TYPE_NONE) |
311 | #define PAGE_RO __pgprot(_PAGE_TYPE_RO) | 318 | #define PAGE_RO __pgprot(_PAGE_TYPE_RO) |
312 | #define PAGE_RW __pgprot(_PAGE_TYPE_RW) | 319 | #define PAGE_RW __pgprot(_PAGE_TYPE_RW) |
320 | #define PAGE_EX_RO __pgprot(_PAGE_TYPE_EX_RO) | ||
321 | #define PAGE_EX_RW __pgprot(_PAGE_TYPE_EX_RW) | ||
313 | 322 | ||
314 | #define PAGE_KERNEL PAGE_RW | 323 | #define PAGE_KERNEL PAGE_RW |
315 | #define PAGE_COPY PAGE_RO | 324 | #define PAGE_COPY PAGE_RO |
316 | 325 | ||
317 | /* | 326 | /* |
318 | * The S390 can't do page protection for execute, and considers that the | 327 | * Dependent on the EXEC_PROTECT option s390 can do execute protection. |
319 | * same are read. Also, write permissions imply read permissions. This is | 328 | * Write permission always implies read permission. In theory with a |
320 | * the closest we can get.. | 329 | * primary/secondary page table execute only can be implemented but |
330 | * it would cost an additional bit in the pte to distinguish all the | ||
331 | * different pte types. To avoid that execute permission currently | ||
332 | * implies read permission as well. | ||
321 | */ | 333 | */ |
322 | /*xwr*/ | 334 | /*xwr*/ |
323 | #define __P000 PAGE_NONE | 335 | #define __P000 PAGE_NONE |
324 | #define __P001 PAGE_RO | 336 | #define __P001 PAGE_RO |
325 | #define __P010 PAGE_RO | 337 | #define __P010 PAGE_RO |
326 | #define __P011 PAGE_RO | 338 | #define __P011 PAGE_RO |
327 | #define __P100 PAGE_RO | 339 | #define __P100 PAGE_EX_RO |
328 | #define __P101 PAGE_RO | 340 | #define __P101 PAGE_EX_RO |
329 | #define __P110 PAGE_RO | 341 | #define __P110 PAGE_EX_RO |
330 | #define __P111 PAGE_RO | 342 | #define __P111 PAGE_EX_RO |
331 | 343 | ||
332 | #define __S000 PAGE_NONE | 344 | #define __S000 PAGE_NONE |
333 | #define __S001 PAGE_RO | 345 | #define __S001 PAGE_RO |
334 | #define __S010 PAGE_RW | 346 | #define __S010 PAGE_RW |
335 | #define __S011 PAGE_RW | 347 | #define __S011 PAGE_RW |
336 | #define __S100 PAGE_RO | 348 | #define __S100 PAGE_EX_RO |
337 | #define __S101 PAGE_RO | 349 | #define __S101 PAGE_EX_RO |
338 | #define __S110 PAGE_RW | 350 | #define __S110 PAGE_EX_RW |
339 | #define __S111 PAGE_RW | 351 | #define __S111 PAGE_EX_RW |
352 | |||
353 | #ifndef __s390x__ | ||
354 | # define PMD_SHADOW_SHIFT 1 | ||
355 | # define PGD_SHADOW_SHIFT 1 | ||
356 | #else /* __s390x__ */ | ||
357 | # define PMD_SHADOW_SHIFT 2 | ||
358 | # define PGD_SHADOW_SHIFT 2 | ||
359 | #endif /* __s390x__ */ | ||
360 | |||
361 | static inline struct page *get_shadow_page(struct page *page) | ||
362 | { | ||
363 | if (s390_noexec && !list_empty(&page->lru)) | ||
364 | return virt_to_page(page->lru.next); | ||
365 | return NULL; | ||
366 | } | ||
367 | |||
368 | static inline pte_t *get_shadow_pte(pte_t *ptep) | ||
369 | { | ||
370 | unsigned long pteptr = (unsigned long) (ptep); | ||
371 | |||
372 | if (s390_noexec) { | ||
373 | unsigned long offset = pteptr & (PAGE_SIZE - 1); | ||
374 | void *addr = (void *) (pteptr ^ offset); | ||
375 | struct page *page = virt_to_page(addr); | ||
376 | if (!list_empty(&page->lru)) | ||
377 | return (pte_t *) ((unsigned long) page->lru.next | | ||
378 | offset); | ||
379 | } | ||
380 | return NULL; | ||
381 | } | ||
382 | |||
383 | static inline pmd_t *get_shadow_pmd(pmd_t *pmdp) | ||
384 | { | ||
385 | unsigned long pmdptr = (unsigned long) (pmdp); | ||
386 | |||
387 | if (s390_noexec) { | ||
388 | unsigned long offset = pmdptr & | ||
389 | ((PAGE_SIZE << PMD_SHADOW_SHIFT) - 1); | ||
390 | void *addr = (void *) (pmdptr ^ offset); | ||
391 | struct page *page = virt_to_page(addr); | ||
392 | if (!list_empty(&page->lru)) | ||
393 | return (pmd_t *) ((unsigned long) page->lru.next | | ||
394 | offset); | ||
395 | } | ||
396 | return NULL; | ||
397 | } | ||
398 | |||
399 | static inline pgd_t *get_shadow_pgd(pgd_t *pgdp) | ||
400 | { | ||
401 | unsigned long pgdptr = (unsigned long) (pgdp); | ||
402 | |||
403 | if (s390_noexec) { | ||
404 | unsigned long offset = pgdptr & | ||
405 | ((PAGE_SIZE << PGD_SHADOW_SHIFT) - 1); | ||
406 | void *addr = (void *) (pgdptr ^ offset); | ||
407 | struct page *page = virt_to_page(addr); | ||
408 | if (!list_empty(&page->lru)) | ||
409 | return (pgd_t *) ((unsigned long) page->lru.next | | ||
410 | offset); | ||
411 | } | ||
412 | return NULL; | ||
413 | } | ||
340 | 414 | ||
341 | /* | 415 | /* |
342 | * Certain architectures need to do special things when PTEs | 416 | * Certain architectures need to do special things when PTEs |
@@ -345,7 +419,16 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
345 | */ | 419 | */ |
346 | static inline void set_pte(pte_t *pteptr, pte_t pteval) | 420 | static inline void set_pte(pte_t *pteptr, pte_t pteval) |
347 | { | 421 | { |
422 | pte_t *shadow_pte = get_shadow_pte(pteptr); | ||
423 | |||
348 | *pteptr = pteval; | 424 | *pteptr = pteval; |
425 | if (shadow_pte) { | ||
426 | if (!(pte_val(pteval) & _PAGE_INVALID) && | ||
427 | (pte_val(pteval) & _PAGE_SWX)) | ||
428 | pte_val(*shadow_pte) = pte_val(pteval) | _PAGE_RO; | ||
429 | else | ||
430 | pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY; | ||
431 | } | ||
349 | } | 432 | } |
350 | #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) | 433 | #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) |
351 | 434 | ||
@@ -463,7 +546,7 @@ static inline int pte_read(pte_t pte) | |||
463 | 546 | ||
464 | static inline void pgd_clear(pgd_t * pgdp) { } | 547 | static inline void pgd_clear(pgd_t * pgdp) { } |
465 | 548 | ||
466 | static inline void pmd_clear(pmd_t * pmdp) | 549 | static inline void pmd_clear_kernel(pmd_t * pmdp) |
467 | { | 550 | { |
468 | pmd_val(pmdp[0]) = _PAGE_TABLE_INV; | 551 | pmd_val(pmdp[0]) = _PAGE_TABLE_INV; |
469 | pmd_val(pmdp[1]) = _PAGE_TABLE_INV; | 552 | pmd_val(pmdp[1]) = _PAGE_TABLE_INV; |
@@ -471,24 +554,55 @@ static inline void pmd_clear(pmd_t * pmdp) | |||
471 | pmd_val(pmdp[3]) = _PAGE_TABLE_INV; | 554 | pmd_val(pmdp[3]) = _PAGE_TABLE_INV; |
472 | } | 555 | } |
473 | 556 | ||
557 | static inline void pmd_clear(pmd_t * pmdp) | ||
558 | { | ||
559 | pmd_t *shadow_pmd = get_shadow_pmd(pmdp); | ||
560 | |||
561 | pmd_clear_kernel(pmdp); | ||
562 | if (shadow_pmd) | ||
563 | pmd_clear_kernel(shadow_pmd); | ||
564 | } | ||
565 | |||
474 | #else /* __s390x__ */ | 566 | #else /* __s390x__ */ |
475 | 567 | ||
476 | static inline void pgd_clear(pgd_t * pgdp) | 568 | static inline void pgd_clear_kernel(pgd_t * pgdp) |
477 | { | 569 | { |
478 | pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY; | 570 | pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY; |
479 | } | 571 | } |
480 | 572 | ||
481 | static inline void pmd_clear(pmd_t * pmdp) | 573 | static inline void pgd_clear(pgd_t * pgdp) |
574 | { | ||
575 | pgd_t *shadow_pgd = get_shadow_pgd(pgdp); | ||
576 | |||
577 | pgd_clear_kernel(pgdp); | ||
578 | if (shadow_pgd) | ||
579 | pgd_clear_kernel(shadow_pgd); | ||
580 | } | ||
581 | |||
582 | static inline void pmd_clear_kernel(pmd_t * pmdp) | ||
482 | { | 583 | { |
483 | pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY; | 584 | pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY; |
484 | pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY; | 585 | pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY; |
485 | } | 586 | } |
486 | 587 | ||
588 | static inline void pmd_clear(pmd_t * pmdp) | ||
589 | { | ||
590 | pmd_t *shadow_pmd = get_shadow_pmd(pmdp); | ||
591 | |||
592 | pmd_clear_kernel(pmdp); | ||
593 | if (shadow_pmd) | ||
594 | pmd_clear_kernel(shadow_pmd); | ||
595 | } | ||
596 | |||
487 | #endif /* __s390x__ */ | 597 | #endif /* __s390x__ */ |
488 | 598 | ||
489 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 599 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
490 | { | 600 | { |
601 | pte_t *shadow_pte = get_shadow_pte(ptep); | ||
602 | |||
491 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | 603 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; |
604 | if (shadow_pte) | ||
605 | pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY; | ||
492 | } | 606 | } |
493 | 607 | ||
494 | /* | 608 | /* |
@@ -606,8 +720,11 @@ ptep_clear_flush(struct vm_area_struct *vma, | |||
606 | unsigned long address, pte_t *ptep) | 720 | unsigned long address, pte_t *ptep) |
607 | { | 721 | { |
608 | pte_t pte = *ptep; | 722 | pte_t pte = *ptep; |
723 | pte_t *shadow_pte = get_shadow_pte(ptep); | ||
609 | 724 | ||
610 | __ptep_ipte(address, ptep); | 725 | __ptep_ipte(address, ptep); |
726 | if (shadow_pte) | ||
727 | __ptep_ipte(address, shadow_pte); | ||
611 | return pte; | 728 | return pte; |
612 | } | 729 | } |
613 | 730 | ||
@@ -815,11 +932,17 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) | |||
815 | 932 | ||
816 | #define kern_addr_valid(addr) (1) | 933 | #define kern_addr_valid(addr) (1) |
817 | 934 | ||
935 | extern int add_shared_memory(unsigned long start, unsigned long size); | ||
936 | extern int remove_shared_memory(unsigned long start, unsigned long size); | ||
937 | |||
818 | /* | 938 | /* |
819 | * No page table caches to initialise | 939 | * No page table caches to initialise |
820 | */ | 940 | */ |
821 | #define pgtable_cache_init() do { } while (0) | 941 | #define pgtable_cache_init() do { } while (0) |
822 | 942 | ||
943 | #define __HAVE_ARCH_MEMMAP_INIT | ||
944 | extern void memmap_init(unsigned long, int, unsigned long, unsigned long); | ||
945 | |||
823 | #define __HAVE_ARCH_PTEP_ESTABLISH | 946 | #define __HAVE_ARCH_PTEP_ESTABLISH |
824 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | 947 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS |
825 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | 948 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG |