diff options
Diffstat (limited to 'include/asm-s390/pgalloc.h')
-rw-r--r-- | include/asm-s390/pgalloc.h | 213 |
1 files changed, 70 insertions, 143 deletions
diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h index 6cbbfe4f6749..229b0bd59331 100644 --- a/include/asm-s390/pgalloc.h +++ b/include/asm-s390/pgalloc.h | |||
@@ -19,114 +19,75 @@ | |||
19 | 19 | ||
20 | #define check_pgt_cache() do {} while (0) | 20 | #define check_pgt_cache() do {} while (0) |
21 | 21 | ||
22 | /* | 22 | unsigned long *crst_table_alloc(struct mm_struct *, int); |
23 | * Page allocation orders. | 23 | void crst_table_free(unsigned long *); |
24 | */ | ||
25 | #ifndef __s390x__ | ||
26 | # define PTE_ALLOC_ORDER 0 | ||
27 | # define PMD_ALLOC_ORDER 0 | ||
28 | # define PGD_ALLOC_ORDER 1 | ||
29 | #else /* __s390x__ */ | ||
30 | # define PTE_ALLOC_ORDER 0 | ||
31 | # define PMD_ALLOC_ORDER 2 | ||
32 | # define PGD_ALLOC_ORDER 2 | ||
33 | #endif /* __s390x__ */ | ||
34 | 24 | ||
35 | /* | 25 | unsigned long *page_table_alloc(int); |
36 | * Allocate and free page tables. The xxx_kernel() versions are | 26 | void page_table_free(unsigned long *); |
37 | * used to allocate a kernel page table - this turns on ASN bits | ||
38 | * if any. | ||
39 | */ | ||
40 | 27 | ||
41 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | 28 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) |
42 | { | 29 | { |
43 | pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER); | 30 | *s = val; |
44 | int i; | 31 | n = (n / 256) - 1; |
45 | 32 | asm volatile( | |
46 | if (!pgd) | 33 | #ifdef CONFIG_64BIT |
47 | return NULL; | 34 | " mvc 8(248,%0),0(%0)\n" |
48 | if (s390_noexec) { | ||
49 | pgd_t *shadow_pgd = (pgd_t *) | ||
50 | __get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER); | ||
51 | struct page *page = virt_to_page(pgd); | ||
52 | |||
53 | if (!shadow_pgd) { | ||
54 | free_pages((unsigned long) pgd, PGD_ALLOC_ORDER); | ||
55 | return NULL; | ||
56 | } | ||
57 | page->lru.next = (void *) shadow_pgd; | ||
58 | } | ||
59 | for (i = 0; i < PTRS_PER_PGD; i++) | ||
60 | #ifndef __s390x__ | ||
61 | pmd_clear(pmd_offset(pgd + i, i*PGDIR_SIZE)); | ||
62 | #else | 35 | #else |
63 | pgd_clear(pgd + i); | 36 | " mvc 4(252,%0),0(%0)\n" |
64 | #endif | 37 | #endif |
65 | return pgd; | 38 | "0: mvc 256(256,%0),0(%0)\n" |
39 | " la %0,256(%0)\n" | ||
40 | " brct %1,0b\n" | ||
41 | : "+a" (s), "+d" (n)); | ||
66 | } | 42 | } |
67 | 43 | ||
68 | static inline void pgd_free(pgd_t *pgd) | 44 | static inline void crst_table_init(unsigned long *crst, unsigned long entry) |
69 | { | 45 | { |
70 | pgd_t *shadow_pgd = get_shadow_pgd(pgd); | 46 | clear_table(crst, entry, sizeof(unsigned long)*2048); |
71 | 47 | crst = get_shadow_table(crst); | |
72 | if (shadow_pgd) | 48 | if (crst) |
73 | free_pages((unsigned long) shadow_pgd, PGD_ALLOC_ORDER); | 49 | clear_table(crst, entry, sizeof(unsigned long)*2048); |
74 | free_pages((unsigned long) pgd, PGD_ALLOC_ORDER); | ||
75 | } | 50 | } |
76 | 51 | ||
77 | #ifndef __s390x__ | 52 | #ifndef __s390x__ |
78 | /* | 53 | |
79 | * page middle directory allocation/free routines. | 54 | static inline unsigned long pgd_entry_type(struct mm_struct *mm) |
80 | * We use pmd cache only on s390x, so these are dummy routines. This | 55 | { |
81 | * code never triggers because the pgd will always be present. | 56 | return _SEGMENT_ENTRY_EMPTY; |
82 | */ | 57 | } |
83 | #define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) | 58 | |
84 | #define pmd_free(x) do { } while (0) | 59 | #define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) |
85 | #define pgd_populate(mm, pmd, pte) BUG() | 60 | #define pmd_free(x) do { } while (0) |
61 | |||
62 | #define pgd_populate(mm, pmd, pte) BUG() | ||
86 | #define pgd_populate_kernel(mm, pmd, pte) BUG() | 63 | #define pgd_populate_kernel(mm, pmd, pte) BUG() |
64 | |||
87 | #else /* __s390x__ */ | 65 | #else /* __s390x__ */ |
88 | static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) | 66 | |
67 | static inline unsigned long pgd_entry_type(struct mm_struct *mm) | ||
89 | { | 68 | { |
90 | pmd_t *pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER); | 69 | return _REGION3_ENTRY_EMPTY; |
91 | int i; | ||
92 | |||
93 | if (!pmd) | ||
94 | return NULL; | ||
95 | if (s390_noexec) { | ||
96 | pmd_t *shadow_pmd = (pmd_t *) | ||
97 | __get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER); | ||
98 | struct page *page = virt_to_page(pmd); | ||
99 | |||
100 | if (!shadow_pmd) { | ||
101 | free_pages((unsigned long) pmd, PMD_ALLOC_ORDER); | ||
102 | return NULL; | ||
103 | } | ||
104 | page->lru.next = (void *) shadow_pmd; | ||
105 | } | ||
106 | for (i=0; i < PTRS_PER_PMD; i++) | ||
107 | pmd_clear(pmd + i); | ||
108 | return pmd; | ||
109 | } | 70 | } |
110 | 71 | ||
111 | static inline void pmd_free (pmd_t *pmd) | 72 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) |
112 | { | 73 | { |
113 | pmd_t *shadow_pmd = get_shadow_pmd(pmd); | 74 | unsigned long *crst = crst_table_alloc(mm, s390_noexec); |
114 | 75 | if (crst) | |
115 | if (shadow_pmd) | 76 | crst_table_init(crst, _SEGMENT_ENTRY_EMPTY); |
116 | free_pages((unsigned long) shadow_pmd, PMD_ALLOC_ORDER); | 77 | return (pmd_t *) crst; |
117 | free_pages((unsigned long) pmd, PMD_ALLOC_ORDER); | ||
118 | } | 78 | } |
79 | #define pmd_free(pmd) crst_table_free((unsigned long *) pmd) | ||
119 | 80 | ||
120 | static inline void | 81 | static inline void pgd_populate_kernel(struct mm_struct *mm, |
121 | pgd_populate_kernel(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) | 82 | pgd_t *pgd, pmd_t *pmd) |
122 | { | 83 | { |
123 | pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd); | 84 | pgd_val(*pgd) = _REGION3_ENTRY | __pa(pmd); |
124 | } | 85 | } |
125 | 86 | ||
126 | static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) | 87 | static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) |
127 | { | 88 | { |
128 | pgd_t *shadow_pgd = get_shadow_pgd(pgd); | 89 | pgd_t *shadow_pgd = get_shadow_table(pgd); |
129 | pmd_t *shadow_pmd = get_shadow_pmd(pmd); | 90 | pmd_t *shadow_pmd = get_shadow_table(pmd); |
130 | 91 | ||
131 | if (shadow_pgd && shadow_pmd) | 92 | if (shadow_pgd && shadow_pmd) |
132 | pgd_populate_kernel(mm, shadow_pgd, shadow_pmd); | 93 | pgd_populate_kernel(mm, shadow_pgd, shadow_pmd); |
@@ -135,17 +96,26 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) | |||
135 | 96 | ||
136 | #endif /* __s390x__ */ | 97 | #endif /* __s390x__ */ |
137 | 98 | ||
99 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | ||
100 | { | ||
101 | unsigned long *crst = crst_table_alloc(mm, s390_noexec); | ||
102 | if (crst) | ||
103 | crst_table_init(crst, pgd_entry_type(mm)); | ||
104 | return (pgd_t *) crst; | ||
105 | } | ||
106 | #define pgd_free(pgd) crst_table_free((unsigned long *) pgd) | ||
107 | |||
138 | static inline void | 108 | static inline void |
139 | pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) | 109 | pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) |
140 | { | 110 | { |
141 | #ifndef __s390x__ | 111 | #ifndef __s390x__ |
142 | pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte); | 112 | pmd_val(pmd[0]) = _SEGMENT_ENTRY + __pa(pte); |
143 | pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte+256); | 113 | pmd_val(pmd[1]) = _SEGMENT_ENTRY + __pa(pte+256); |
144 | pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte+512); | 114 | pmd_val(pmd[2]) = _SEGMENT_ENTRY + __pa(pte+512); |
145 | pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte+768); | 115 | pmd_val(pmd[3]) = _SEGMENT_ENTRY + __pa(pte+768); |
146 | #else /* __s390x__ */ | 116 | #else /* __s390x__ */ |
147 | pmd_val(*pmd) = _PMD_ENTRY + __pa(pte); | 117 | pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte); |
148 | pmd_val1(*pmd) = _PMD_ENTRY + __pa(pte+256); | 118 | pmd_val1(*pmd) = _SEGMENT_ENTRY + __pa(pte+256); |
149 | #endif /* __s390x__ */ | 119 | #endif /* __s390x__ */ |
150 | } | 120 | } |
151 | 121 | ||
@@ -153,7 +123,7 @@ static inline void | |||
153 | pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page) | 123 | pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page) |
154 | { | 124 | { |
155 | pte_t *pte = (pte_t *)page_to_phys(page); | 125 | pte_t *pte = (pte_t *)page_to_phys(page); |
156 | pmd_t *shadow_pmd = get_shadow_pmd(pmd); | 126 | pmd_t *shadow_pmd = get_shadow_table(pmd); |
157 | pte_t *shadow_pte = get_shadow_pte(pte); | 127 | pte_t *shadow_pte = get_shadow_pte(pte); |
158 | 128 | ||
159 | pmd_populate_kernel(mm, pmd, pte); | 129 | pmd_populate_kernel(mm, pmd, pte); |
@@ -164,57 +134,14 @@ pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page) | |||
164 | /* | 134 | /* |
165 | * page table entry allocation/free routines. | 135 | * page table entry allocation/free routines. |
166 | */ | 136 | */ |
167 | static inline pte_t * | 137 | #define pte_alloc_one_kernel(mm, vmaddr) \ |
168 | pte_alloc_one_kernel(struct mm_struct *mm, unsigned long vmaddr) | 138 | ((pte_t *) page_table_alloc(s390_noexec)) |
169 | { | 139 | #define pte_alloc_one(mm, vmaddr) \ |
170 | pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL|__GFP_REPEAT); | 140 | virt_to_page(page_table_alloc(s390_noexec)) |
171 | int i; | 141 | |
172 | 142 | #define pte_free_kernel(pte) \ | |
173 | if (!pte) | 143 | page_table_free((unsigned long *) pte) |
174 | return NULL; | 144 | #define pte_free(pte) \ |
175 | if (s390_noexec) { | 145 | page_table_free((unsigned long *) page_to_phys((struct page *) pte)) |
176 | pte_t *shadow_pte = (pte_t *) | ||
177 | __get_free_page(GFP_KERNEL|__GFP_REPEAT); | ||
178 | struct page *page = virt_to_page(pte); | ||
179 | |||
180 | if (!shadow_pte) { | ||
181 | free_page((unsigned long) pte); | ||
182 | return NULL; | ||
183 | } | ||
184 | page->lru.next = (void *) shadow_pte; | ||
185 | } | ||
186 | for (i=0; i < PTRS_PER_PTE; i++) { | ||
187 | pte_clear(mm, vmaddr, pte + i); | ||
188 | vmaddr += PAGE_SIZE; | ||
189 | } | ||
190 | return pte; | ||
191 | } | ||
192 | |||
193 | static inline struct page * | ||
194 | pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr) | ||
195 | { | ||
196 | pte_t *pte = pte_alloc_one_kernel(mm, vmaddr); | ||
197 | if (pte) | ||
198 | return virt_to_page(pte); | ||
199 | return NULL; | ||
200 | } | ||
201 | |||
202 | static inline void pte_free_kernel(pte_t *pte) | ||
203 | { | ||
204 | pte_t *shadow_pte = get_shadow_pte(pte); | ||
205 | |||
206 | if (shadow_pte) | ||
207 | free_page((unsigned long) shadow_pte); | ||
208 | free_page((unsigned long) pte); | ||
209 | } | ||
210 | |||
211 | static inline void pte_free(struct page *pte) | ||
212 | { | ||
213 | struct page *shadow_page = get_shadow_page(pte); | ||
214 | |||
215 | if (shadow_page) | ||
216 | __free_page(shadow_page); | ||
217 | __free_page(pte); | ||
218 | } | ||
219 | 146 | ||
220 | #endif /* _S390_PGALLOC_H */ | 147 | #endif /* _S390_PGALLOC_H */ |