aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2008-02-09 12:24:36 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-02-09 12:24:40 -0500
commit5a216a20837c5f5fa1ca4b8ae8991ffd96b08e6f (patch)
treedde54e28497e920fa460cc95dadb6b38f1b2dbe0
parent146e4b3c8b92071b18f0b2e6f47165bad4f9e825 (diff)
[S390] Add four level page tables for CONFIG_64BIT=y.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/mm/init.c4
-rw-r--r--arch/s390/mm/vmem.c14
-rw-r--r--include/asm-s390/elf.h9
-rw-r--r--include/asm-s390/mmu_context.h2
-rw-r--r--include/asm-s390/pgalloc.h29
-rw-r--r--include/asm-s390/pgtable.h57
-rw-r--r--include/asm-s390/processor.h24
-rw-r--r--include/asm-s390/tlb.h33
8 files changed, 124 insertions, 48 deletions
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 01dfe20f846d..248a71010700 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -112,8 +112,8 @@ void __init paging_init(void)
112 init_mm.pgd = swapper_pg_dir; 112 init_mm.pgd = swapper_pg_dir;
113 S390_lowcore.kernel_asce = __pa(init_mm.pgd) & PAGE_MASK; 113 S390_lowcore.kernel_asce = __pa(init_mm.pgd) & PAGE_MASK;
114#ifdef CONFIG_64BIT 114#ifdef CONFIG_64BIT
115 S390_lowcore.kernel_asce |= _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH; 115 S390_lowcore.kernel_asce |= _ASCE_TYPE_REGION2 | _ASCE_TABLE_LENGTH;
116 pgd_type = _REGION3_ENTRY_EMPTY; 116 pgd_type = _REGION2_ENTRY_EMPTY;
117#else 117#else
118 S390_lowcore.kernel_asce |= _ASCE_TABLE_LENGTH; 118 S390_lowcore.kernel_asce |= _ASCE_TABLE_LENGTH;
119 pgd_type = _SEGMENT_ENTRY_EMPTY; 119 pgd_type = _SEGMENT_ENTRY_EMPTY;
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 434491f8f47c..35d90a4720fd 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -69,7 +69,19 @@ static void __ref *vmem_alloc_pages(unsigned int order)
69 return alloc_bootmem_pages((1 << order) * PAGE_SIZE); 69 return alloc_bootmem_pages((1 << order) * PAGE_SIZE);
70} 70}
71 71
72#define vmem_pud_alloc() ({ BUG(); ((pud_t *) NULL); }) 72static inline pud_t *vmem_pud_alloc(void)
73{
74 pud_t *pud = NULL;
75
76#ifdef CONFIG_64BIT
77 pud = vmem_alloc_pages(2);
78 if (!pud)
79 return NULL;
80 pud_val(*pud) = _REGION3_ENTRY_EMPTY;
81 memcpy(pud + 1, pud, (PTRS_PER_PUD - 1)*sizeof(pud_t));
82#endif
83 return pud;
84}
73 85
74static inline pmd_t *vmem_pmd_alloc(void) 86static inline pmd_t *vmem_pmd_alloc(void)
75{ 87{
diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h
index 8181ca5b98f4..b760cd4de385 100644
--- a/include/asm-s390/elf.h
+++ b/include/asm-s390/elf.h
@@ -138,14 +138,7 @@ typedef s390_regs elf_gregset_t;
138 use of this is to invoke "./ld.so someprog" to test out a new version of 138 use of this is to invoke "./ld.so someprog" to test out a new version of
139 the loader. We need to make sure that it is out of the way of the program 139 the loader. We need to make sure that it is out of the way of the program
140 that it will "exec", and that there is sufficient room for the brk. */ 140 that it will "exec", and that there is sufficient room for the brk. */
141 141#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
142#ifndef __s390x__
143#define ELF_ET_DYN_BASE ((TASK_SIZE & 0x80000000) \
144 ? TASK_SIZE / 3 * 2 \
145 : 2 * TASK_SIZE / 3)
146#else /* __s390x__ */
147#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
148#endif /* __s390x__ */
149 142
150/* Wow, the "main" arch needs arch dependent functions too.. :) */ 143/* Wow, the "main" arch needs arch dependent functions too.. :) */
151 144
diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
index 3eaac5efc632..b3ea3e199921 100644
--- a/include/asm-s390/mmu_context.h
+++ b/include/asm-s390/mmu_context.h
@@ -18,7 +18,7 @@ static inline int init_new_context(struct task_struct *tsk,
18{ 18{
19 mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; 19 mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
20#ifdef CONFIG_64BIT 20#ifdef CONFIG_64BIT
21 mm->context.asce_bits |= _ASCE_TYPE_REGION3; 21 mm->context.asce_bits |= _ASCE_TYPE_REGION2;
22#endif 22#endif
23 mm->context.noexec = s390_noexec; 23 mm->context.noexec = s390_noexec;
24 return 0; 24 return 0;
diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h
index af4aee856df3..cc47dd65a499 100644
--- a/include/asm-s390/pgalloc.h
+++ b/include/asm-s390/pgalloc.h
@@ -73,11 +73,17 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm)
73 73
74static inline unsigned long pgd_entry_type(struct mm_struct *mm) 74static inline unsigned long pgd_entry_type(struct mm_struct *mm)
75{ 75{
76 return _REGION3_ENTRY_EMPTY; 76 return _REGION2_ENTRY_EMPTY;
77} 77}
78 78
79#define pud_alloc_one(mm,address) ({ BUG(); ((pud_t *)2); }) 79static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
80#define pud_free(mm, x) do { } while (0) 80{
81 unsigned long *table = crst_table_alloc(mm, mm->context.noexec);
82 if (table)
83 crst_table_init(table, _REGION3_ENTRY_EMPTY);
84 return (pud_t *) table;
85}
86#define pud_free(mm, pud) crst_table_free(mm, (unsigned long *) pud)
81 87
82static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) 88static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
83{ 89{
@@ -88,8 +94,21 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
88} 94}
89#define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd) 95#define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd)
90 96
91#define pgd_populate(mm, pgd, pud) BUG() 97static inline void pgd_populate_kernel(struct mm_struct *mm,
92#define pgd_populate_kernel(mm, pgd, pud) BUG() 98 pgd_t *pgd, pud_t *pud)
99{
100 pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud);
101}
102
103static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
104{
105 pgd_t *shadow_pgd = get_shadow_table(pgd);
106 pud_t *shadow_pud = get_shadow_table(pud);
107
108 if (shadow_pgd && shadow_pud)
109 pgd_populate_kernel(mm, shadow_pgd, shadow_pud);
110 pgd_populate_kernel(mm, pgd, pud);
111}
93 112
94static inline void pud_populate_kernel(struct mm_struct *mm, 113static inline void pud_populate_kernel(struct mm_struct *mm,
95 pud_t *pud, pmd_t *pmd) 114 pud_t *pud, pmd_t *pmd)
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index 4fc937711482..8f473a718111 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -63,15 +63,15 @@ extern char empty_zero_page[PAGE_SIZE];
63#else /* __s390x__ */ 63#else /* __s390x__ */
64# define PMD_SHIFT 20 64# define PMD_SHIFT 20
65# define PUD_SHIFT 31 65# define PUD_SHIFT 31
66# define PGDIR_SHIFT 31 66# define PGDIR_SHIFT 42
67#endif /* __s390x__ */ 67#endif /* __s390x__ */
68 68
69#define PMD_SIZE (1UL << PMD_SHIFT) 69#define PMD_SIZE (1UL << PMD_SHIFT)
70#define PMD_MASK (~(PMD_SIZE-1)) 70#define PMD_MASK (~(PMD_SIZE-1))
71#define PUD_SIZE (1UL << PUD_SHIFT) 71#define PUD_SIZE (1UL << PUD_SHIFT)
72#define PUD_MASK (~(PUD_SIZE-1)) 72#define PUD_MASK (~(PUD_SIZE-1))
73#define PGDIR_SIZE (1UL << PGDIR_SHIFT) 73#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
74#define PGDIR_MASK (~(PGDIR_SIZE-1)) 74#define PGDIR_MASK (~(PGDIR_SIZE-1))
75 75
76/* 76/*
77 * entries per page directory level: the S390 is two-level, so 77 * entries per page directory level: the S390 is two-level, so
@@ -82,10 +82,11 @@ extern char empty_zero_page[PAGE_SIZE];
82#define PTRS_PER_PTE 256 82#define PTRS_PER_PTE 256
83#ifndef __s390x__ 83#ifndef __s390x__
84#define PTRS_PER_PMD 1 84#define PTRS_PER_PMD 1
85#define PTRS_PER_PUD 1
85#else /* __s390x__ */ 86#else /* __s390x__ */
86#define PTRS_PER_PMD 2048 87#define PTRS_PER_PMD 2048
88#define PTRS_PER_PUD 2048
87#endif /* __s390x__ */ 89#endif /* __s390x__ */
88#define PTRS_PER_PUD 1
89#define PTRS_PER_PGD 2048 90#define PTRS_PER_PGD 2048
90 91
91#define FIRST_USER_ADDRESS 0 92#define FIRST_USER_ADDRESS 0
@@ -418,9 +419,23 @@ static inline int pud_bad(pud_t pud) { return 0; }
418 419
419#else /* __s390x__ */ 420#else /* __s390x__ */
420 421
421static inline int pgd_present(pgd_t pgd) { return 1; } 422static inline int pgd_present(pgd_t pgd)
422static inline int pgd_none(pgd_t pgd) { return 0; } 423{
423static inline int pgd_bad(pgd_t pgd) { return 0; } 424 return (pgd_val(pgd) & _REGION_ENTRY_ORIGIN) != 0UL;
425}
426
427static inline int pgd_none(pgd_t pgd)
428{
429 return (pgd_val(pgd) & _REGION_ENTRY_INV) != 0UL;
430}
431
432static inline int pgd_bad(pgd_t pgd)
433{
434 unsigned long mask =
435 ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV &
436 ~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH;
437 return (pgd_val(pgd) & mask) != 0;
438}
424 439
425static inline int pud_present(pud_t pud) 440static inline int pud_present(pud_t pud)
426{ 441{
@@ -434,8 +449,10 @@ static inline int pud_none(pud_t pud)
434 449
435static inline int pud_bad(pud_t pud) 450static inline int pud_bad(pud_t pud)
436{ 451{
437 unsigned long mask = ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV; 452 unsigned long mask =
438 return (pud_val(pud) & mask) != _REGION3_ENTRY; 453 ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV &
454 ~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH;
455 return (pud_val(pud) & mask) != 0;
439} 456}
440 457
441#endif /* __s390x__ */ 458#endif /* __s390x__ */
@@ -516,7 +533,19 @@ static inline int pte_young(pte_t pte)
516 533
517#else /* __s390x__ */ 534#else /* __s390x__ */
518 535
519#define pgd_clear(pgd) do { } while (0) 536static inline void pgd_clear_kernel(pgd_t * pgd)
537{
538 pgd_val(*pgd) = _REGION2_ENTRY_EMPTY;
539}
540
541static inline void pgd_clear(pgd_t * pgd)
542{
543 pgd_t *shadow = get_shadow_table(pgd);
544
545 pgd_clear_kernel(pgd);
546 if (shadow)
547 pgd_clear_kernel(shadow);
548}
520 549
521static inline void pud_clear_kernel(pud_t *pud) 550static inline void pud_clear_kernel(pud_t *pud)
522{ 551{
@@ -808,9 +837,13 @@ static inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
808 837
809#define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN) 838#define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN)
810#define pud_deref(pud) (pud_val(pud) & _REGION_ENTRY_ORIGIN) 839#define pud_deref(pud) (pud_val(pud) & _REGION_ENTRY_ORIGIN)
811#define pgd_deref(pgd) ({ BUG(); 0UL; }) 840#define pgd_deref(pgd) (pgd_val(pgd) & _REGION_ENTRY_ORIGIN)
812 841
813#define pud_offset(pgd, address) ((pud_t *) pgd) 842static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address)
843{
844 pud_t *pud = (pud_t *) pgd_deref(*pgd);
845 return pud + pud_index(address);
846}
814 847
815static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) 848static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
816{ 849{
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
index e8785634cbdb..5a21f457d583 100644
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -64,24 +64,28 @@ extern int get_cpu_capability(unsigned int *);
64 */ 64 */
65#ifndef __s390x__ 65#ifndef __s390x__
66 66
67# define TASK_SIZE (0x80000000UL) 67#define TASK_SIZE (1UL << 31)
68# define TASK_UNMAPPED_BASE (TASK_SIZE / 2) 68#define TASK_UNMAPPED_BASE (1UL << 30)
69# define DEFAULT_TASK_SIZE (0x80000000UL)
70 69
71#else /* __s390x__ */ 70#else /* __s390x__ */
72 71
73# define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_31BIT) ? \ 72#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk,TIF_31BIT) ? \
74 (0x80000000UL) : (0x40000000000UL)) 73 (1UL << 31) : (1UL << 53))
75# define TASK_SIZE TASK_SIZE_OF(current) 74#define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \
76# define TASK_UNMAPPED_BASE (TASK_SIZE / 2) 75 (1UL << 30) : (1UL << 41))
77# define DEFAULT_TASK_SIZE (0x40000000000UL) 76#define TASK_SIZE TASK_SIZE_OF(current)
78 77
79#endif /* __s390x__ */ 78#endif /* __s390x__ */
80 79
81#ifdef __KERNEL__ 80#ifdef __KERNEL__
82 81
83#define STACK_TOP TASK_SIZE 82#ifndef __s390x__
84#define STACK_TOP_MAX DEFAULT_TASK_SIZE 83#define STACK_TOP (1UL << 31)
84#else /* __s390x__ */
85#define STACK_TOP (1UL << (test_thread_flag(TIF_31BIT) ? 31:53))
86#endif /* __s390x__ */
87
88#define STACK_TOP_MAX STACK_TOP
85 89
86#endif 90#endif
87 91
diff --git a/include/asm-s390/tlb.h b/include/asm-s390/tlb.h
index ecac75ec6cb0..9b2ddb7aac49 100644
--- a/include/asm-s390/tlb.h
+++ b/include/asm-s390/tlb.h
@@ -38,7 +38,7 @@ struct mmu_gather {
38 struct mm_struct *mm; 38 struct mm_struct *mm;
39 unsigned int fullmm; 39 unsigned int fullmm;
40 unsigned int nr_ptes; 40 unsigned int nr_ptes;
41 unsigned int nr_pmds; 41 unsigned int nr_pxds;
42 void *array[TLB_NR_PTRS]; 42 void *array[TLB_NR_PTRS];
43}; 43};
44 44
@@ -53,7 +53,7 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm,
53 tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) || 53 tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) ||
54 (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm); 54 (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm);
55 tlb->nr_ptes = 0; 55 tlb->nr_ptes = 0;
56 tlb->nr_pmds = TLB_NR_PTRS; 56 tlb->nr_pxds = TLB_NR_PTRS;
57 if (tlb->fullmm) 57 if (tlb->fullmm)
58 __tlb_flush_mm(mm); 58 __tlb_flush_mm(mm);
59 return tlb; 59 return tlb;
@@ -62,12 +62,13 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm,
62static inline void tlb_flush_mmu(struct mmu_gather *tlb, 62static inline void tlb_flush_mmu(struct mmu_gather *tlb,
63 unsigned long start, unsigned long end) 63 unsigned long start, unsigned long end)
64{ 64{
65 if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pmds < TLB_NR_PTRS)) 65 if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS))
66 __tlb_flush_mm(tlb->mm); 66 __tlb_flush_mm(tlb->mm);
67 while (tlb->nr_ptes > 0) 67 while (tlb->nr_ptes > 0)
68 pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]); 68 pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]);
69 while (tlb->nr_pmds < TLB_NR_PTRS) 69 while (tlb->nr_pxds < TLB_NR_PTRS)
70 pmd_free(tlb->mm, (pmd_t *) tlb->array[tlb->nr_pmds++]); 70 /* pgd_free frees the pointer as region or segment table */
71 pgd_free(tlb->mm, tlb->array[tlb->nr_pxds++]);
71} 72}
72 73
73static inline void tlb_finish_mmu(struct mmu_gather *tlb, 74static inline void tlb_finish_mmu(struct mmu_gather *tlb,
@@ -99,7 +100,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte)
99{ 100{
100 if (!tlb->fullmm) { 101 if (!tlb->fullmm) {
101 tlb->array[tlb->nr_ptes++] = pte; 102 tlb->array[tlb->nr_ptes++] = pte;
102 if (tlb->nr_ptes >= tlb->nr_pmds) 103 if (tlb->nr_ptes >= tlb->nr_pxds)
103 tlb_flush_mmu(tlb, 0, 0); 104 tlb_flush_mmu(tlb, 0, 0);
104 } else 105 } else
105 pte_free(tlb->mm, pte); 106 pte_free(tlb->mm, pte);
@@ -113,15 +114,29 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
113{ 114{
114#ifdef __s390x__ 115#ifdef __s390x__
115 if (!tlb->fullmm) { 116 if (!tlb->fullmm) {
116 tlb->array[--tlb->nr_pmds] = (struct page *) pmd; 117 tlb->array[--tlb->nr_pxds] = pmd;
117 if (tlb->nr_ptes >= tlb->nr_pmds) 118 if (tlb->nr_ptes >= tlb->nr_pxds)
118 tlb_flush_mmu(tlb, 0, 0); 119 tlb_flush_mmu(tlb, 0, 0);
119 } else 120 } else
120 pmd_free(tlb->mm, pmd); 121 pmd_free(tlb->mm, pmd);
121#endif 122#endif
122} 123}
123 124
124#define pud_free_tlb(tlb, pud) do { } while (0) 125/*
126 * pud_free_tlb frees a pud table and clears the CRSTE for the
127 * region third table entry from the tlb.
128 */
129static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud)
130{
131#ifdef __s390x__
132 if (!tlb->fullmm) {
133 tlb->array[--tlb->nr_pxds] = pud;
134 if (tlb->nr_ptes >= tlb->nr_pxds)
135 tlb_flush_mmu(tlb, 0, 0);
136 } else
137 pud_free(tlb->mm, pud);
138#endif
139}
125 140
126#define tlb_start_vma(tlb, vma) do { } while (0) 141#define tlb_start_vma(tlb, vma) do { } while (0)
127#define tlb_end_vma(tlb, vma) do { } while (0) 142#define tlb_end_vma(tlb, vma) do { } while (0)