File: /usr/src/linux/include/asm-s390/pgtable.h
1 /*
2 * include/asm-s390/pgtable.h
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Hartmut Penner (hp@de.ibm.com)
7 * Ulrich Weigand (weigand@de.ibm.com)
8 * Martin Schwidefsky (schwidefsky@de.ibm.com)
9 *
10 * Derived from "include/asm-i386/pgtable.h"
11 */
12
13 #ifndef _ASM_S390_PGTABLE_H
14 #define _ASM_S390_PGTABLE_H
15
16 /*
17 * The Linux memory management assumes a three-level page table setup. On
18 * the S390, we use that, but "fold" the mid level into the top-level page
19 * table, so that we physically have the same two-level page table as the
20 * S390 mmu expects.
21 *
22 * The "pgd_xxx()" functions are trivial for a folded two-level
23 * setup: the pgd is never bad, and a pmd always exists (as it's folded
24 * into the pgd entry)
25 *
26 * This file contains the functions and defines necessary to modify and use
27 * the S390 page table tree.
28 */
29 #ifndef __ASSEMBLY__
30 #include <asm/processor.h>
31 #include <linux/threads.h>
32
33 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
34 extern void paging_init(void);
35
36 /* Caches aren't brain-dead on S390. */
37 #define flush_cache_all() do { } while (0)
38 #define flush_cache_mm(mm) do { } while (0)
39 #define flush_cache_range(mm, start, end) do { } while (0)
40 #define flush_cache_page(vma, vmaddr) do { } while (0)
41 #define flush_page_to_ram(page) do { } while (0)
42 #define flush_dcache_page(page) do { } while (0)
43 #define flush_icache_range(start, end) do { } while (0)
44 #define flush_icache_page(vma,pg) do { } while (0)
45
46 /*
47 * The S390 doesn't have any external MMU info: the kernel page
48 * tables contain all the necessary information.
49 */
50 #define update_mmu_cache(vma, address, pte) do { } while (0)
51
52 /*
53 * ZERO_PAGE is a global shared page that is always zero: used
54 * for zero-mapped memory areas etc..
55 */
56 extern char empty_zero_page[PAGE_SIZE];
57 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
58 #endif /* !__ASSEMBLY__ */
59
60 /*
61 * Certain architectures need to do special things when PTEs
62 * within a page table are directly modified. Thus, the following
63 * hook is made available.
64 */
65 #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
66
67 /*
68 * PMD_SHIFT determines the size of the area a second-level page
69 * table can map
70 */
71 #define PMD_SHIFT 22
72 #define PMD_SIZE (1UL << PMD_SHIFT)
73 #define PMD_MASK (~(PMD_SIZE-1))
74
75 /* PGDIR_SHIFT determines what a third-level page table entry can map */
76 #define PGDIR_SHIFT 22
77 #define PGDIR_SIZE (1UL << PGDIR_SHIFT)
78 #define PGDIR_MASK (~(PGDIR_SIZE-1))
79
80 /*
81 * entries per page directory level: the S390 is two-level, so
82 * we don't really have any PMD directory physically.
83 * for S390 segment-table entries are combined to one PGD
84 * that leads to 1024 pte per pgd
85 */
86 #define PTRS_PER_PTE 1024
87 #define PTRS_PER_PMD 1
88 #define PTRS_PER_PGD 512
89
90 /*
91 * pgd entries used up by user/kernel:
92 */
93 #define USER_PTRS_PER_PGD 512
94 #define USER_PGD_PTRS 512
95 #define KERNEL_PGD_PTRS 512
96 #define FIRST_USER_PGD_NR 0
97
98 #define pte_ERROR(e) \
99 printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
100 #define pmd_ERROR(e) \
101 printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
102 #define pgd_ERROR(e) \
103 printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
104
105 #ifndef __ASSEMBLY__
106 /*
107 * Just any arbitrary offset to the start of the vmalloc VM area: the
108 * current 8MB value just means that there will be a 8MB "hole" after the
109 * physical memory until the kernel virtual memory starts. That means that
110 * any out-of-bounds memory accesses will hopefully be caught.
111 * The vmalloc() routines leaves a hole of 4kB between each vmalloced
112 * area for the same reason. ;)
113 */
114 #define VMALLOC_OFFSET (8*1024*1024)
115 #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \
116 & ~(VMALLOC_OFFSET-1))
117 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
118 #define VMALLOC_END (0x7fffffffL)
119
120
121 /*
122 * A pagetable entry of S390 has following format:
123 * | PFRA | | OS |
124 * 0 0IP0
125 * 00000000001111111111222222222233
126 * 01234567890123456789012345678901
127 *
128 * I Page-Invalid Bit: Page is not available for address-translation
129 * P Page-Protection Bit: Store access not possible for page
130 *
131 * A segmenttable entry of S390 has following format:
132 * | P-table origin | |PTL
133 * 0 IC
134 * 00000000001111111111222222222233
135 * 01234567890123456789012345678901
136 *
137 * I Segment-Invalid Bit: Segment is not available for address-translation
138 * C Common-Segment Bit: Segment is not private (PoP 3-30)
139 * PTL Page-Table-Length: Page-table length (PTL+1*16 entries -> up to 256)
140 *
141 * The segmenttable origin of S390 has following format:
142 *
143 * |S-table origin | | STL |
144 * X **GPS
145 * 00000000001111111111222222222233
146 * 01234567890123456789012345678901
147 *
148 * X Space-Switch event:
149 * G Segment-Invalid Bit: *
150 * P Private-Space Bit: Segment is not private (PoP 3-30)
151 * S Storage-Alteration:
152 * STL Segment-Table-Length: Segment-table length (STL+1*16 entries -> up to 2048)
153 *
154 * A storage key has the following format:
155 * | ACC |F|R|C|0|
156 * 0 3 4 5 6 7
157 * ACC: access key
158 * F : fetch protection bit
159 * R : referenced bit
160 * C : changed bit
161 */
162
163 /* Bits in the page table entry */
164 #define _PAGE_PRESENT 0x001 /* Software */
165 #define _PAGE_RO 0x200 /* HW read-only */
166 #define _PAGE_INVALID 0x400 /* HW invalid */
167
168 /* Bits in the segment table entry */
169 #define _PAGE_TABLE_LEN 0xf /* only full page-tables */
170 #define _PAGE_TABLE_COM 0x10 /* common page-table */
171 #define _PAGE_TABLE_INV 0x20 /* invalid page-table */
172 #define _SEG_PRESENT 0x001 /* Software (overlap with PTL) */
173
174 /* Bits int the storage key */
175 #define _PAGE_CHANGED 0x02 /* HW changed bit */
176 #define _PAGE_REFERENCED 0x04 /* HW referenced bit */
177
178 #define _USER_SEG_TABLE_LEN 0x7f /* user-segment-table up to 2 GB */
179 #define _KERNEL_SEG_TABLE_LEN 0x7f /* kernel-segment-table up to 2 GB */
180
181 /*
182 * User and Kernel pagetables are identical
183 */
184 #define _PAGE_TABLE (_PAGE_TABLE_LEN )
185 #define _KERNPG_TABLE (_PAGE_TABLE_LEN )
186
187 /*
188 * The Kernel segment-tables includes the User segment-table
189 */
190
191 #define _SEGMENT_TABLE (_USER_SEG_TABLE_LEN|0x80000000|0x100)
192 #define _KERNSEG_TABLE (_KERNEL_SEG_TABLE_LEN)
193
194 /*
195 * No mapping available
196 */
197 #define PAGE_INVALID __pgprot(_PAGE_INVALID)
198 #define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_INVALID)
199 #define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_RO)
200 #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_RO)
201 #define PAGE_SHARED __pgprot(_PAGE_PRESENT)
202 #define PAGE_KERNEL __pgprot(_PAGE_PRESENT)
203
204 /*
205 * The S390 can't do page protection for execute, and considers that the
206 * same are read. Also, write permissions imply read permissions. This is
207 * the closest we can get..
208 */
209 /*xwr*/
210 #define __P000 PAGE_NONE
211 #define __P001 PAGE_READONLY
212 #define __P010 PAGE_COPY
213 #define __P011 PAGE_COPY
214 #define __P100 PAGE_READONLY
215 #define __P101 PAGE_READONLY
216 #define __P110 PAGE_COPY
217 #define __P111 PAGE_COPY
218
219 #define __S000 PAGE_NONE
220 #define __S001 PAGE_READONLY
221 #define __S010 PAGE_SHARED
222 #define __S011 PAGE_SHARED
223 #define __S100 PAGE_READONLY
224 #define __S101 PAGE_READONLY
225 #define __S110 PAGE_SHARED
226 #define __S111 PAGE_SHARED
227
228 /*
229 * Permanent address of a page.
230 */
231 #define page_address(page) ((page)->virtual)
232 #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
233
234 /*
235 * pgd/pmd/pte query functions
236 */
237 extern inline int pgd_present(pgd_t pgd) { return 1; }
238 extern inline int pgd_none(pgd_t pgd) { return 0; }
239 extern inline int pgd_bad(pgd_t pgd) { return 0; }
240
241 extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SEG_PRESENT; }
242 extern inline int pmd_none(pmd_t pmd) { return pmd_val(pmd) & _PAGE_TABLE_INV; }
243 extern inline int pmd_bad(pmd_t pmd)
244 {
245 return (pmd_val(pmd) & (~PAGE_MASK & ~_PAGE_TABLE_INV)) != _PAGE_TABLE;
246 }
247
248 extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
249 extern inline int pte_none(pte_t pte)
250 {
251 return ((pte_val(pte) &
252 (_PAGE_INVALID | _PAGE_RO | _PAGE_PRESENT)) == _PAGE_INVALID);
253 }
254
255 #define pte_same(a,b) (pte_val(a) == pte_val(b))
256
257 /*
258 * query functions pte_write/pte_dirty/pte_young only work if
259 * pte_present() is true. Undefined behaviour if not..
260 */
261 extern inline int pte_write(pte_t pte)
262 {
263 return (pte_val(pte) & _PAGE_RO) == 0;
264 }
265
266 extern inline int pte_dirty(pte_t pte)
267 {
268 int skey;
269
270 asm volatile ("iske %0,%1" : "=d" (skey) : "a" (pte_val(pte)));
271 return skey & _PAGE_CHANGED;
272 }
273
274 extern inline int pte_young(pte_t pte)
275 {
276 int skey;
277
278 asm volatile ("iske %0,%1" : "=d" (skey) : "a" (pte_val(pte)));
279 return skey & _PAGE_REFERENCED;
280 }
281
282 /*
283 * pgd/pmd/pte modification functions
284 */
285 extern inline void pgd_clear(pgd_t * pgdp) { }
286
287 extern inline void pmd_clear(pmd_t * pmdp)
288 {
289 pmd_val(pmdp[0]) = _PAGE_TABLE_INV;
290 pmd_val(pmdp[1]) = _PAGE_TABLE_INV;
291 pmd_val(pmdp[2]) = _PAGE_TABLE_INV;
292 pmd_val(pmdp[3]) = _PAGE_TABLE_INV;
293 }
294
295 extern inline void pte_clear(pte_t *ptep)
296 {
297 pte_val(*ptep) = _PAGE_INVALID;
298 }
299
300 #define PTE_INIT(x) pte_clear(x)
301
302 /*
303 * The following pte modification functions only work if
304 * pte_present() is true. Undefined behaviour if not..
305 */
306 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
307 {
308 pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot);
309 return pte;
310 }
311
312 extern inline pte_t pte_wrprotect(pte_t pte)
313 {
314 pte_val(pte) |= _PAGE_RO;
315 return pte;
316 }
317
318 extern inline pte_t pte_mkwrite(pte_t pte)
319 {
320 pte_val(pte) &= ~_PAGE_RO;
321 return pte;
322 }
323
324 extern inline pte_t pte_mkclean(pte_t pte)
325 {
326 /* We can't clear the changed bit atomically. The iske/and/sske
327 * sequence has a race condition with the page referenced bit.
328 * At the moment pte_mkclean is always followed by a pte_mkold.
329 * So its safe to ignore the problem for now. Hope this will
330 * never change ... */
331 asm volatile ("sske %0,%1"
332 : : "d" (0), "a" (pte_val(pte)));
333 return pte;
334 }
335
336 extern inline pte_t pte_mkdirty(pte_t pte)
337 {
338 /* We can't set the changed bit atomically either. For now we
339 * set (!) the page referenced bit. */
340 asm volatile ("sske %0,%1"
341 : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED),
342 "a" (pte_val(pte)));
343 return pte;
344 }
345
346 extern inline pte_t pte_mkold(pte_t pte)
347 {
348 asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)) : "cc" );
349 return pte;
350 }
351
352 extern inline pte_t pte_mkyoung(pte_t pte)
353 {
354 /* To set the referenced bit we read the first word from the real
355 * page with a special instruction: load using real address (lura).
356 * Isn't S/390 a nice architecture ?! */
357 asm volatile ("lura 0,%0" : : "a" (pte_val(pte) & PAGE_MASK) : "0" );
358 return pte;
359 }
360
361 static inline int ptep_test_and_clear_young(pte_t *ptep)
362 {
363 int ccode;
364
365 asm volatile ("rrbe 0,%1\n\t"
366 "ipm %0\n\t"
367 "srl %0,28\n\t"
368 : "=d" (ccode) : "a" (pte_val(*ptep)) : "cc" );
369 return ccode & 2;
370 }
371
372 static inline int ptep_test_and_clear_dirty(pte_t *ptep)
373 {
374 int skey;
375
376 asm volatile ("iske %0,%1" : "=d" (skey) : "a" (*ptep));
377 if ((skey & _PAGE_CHANGED) == 0)
378 return 0;
379 /* We can't clear the changed bit atomically. For now we
380 * clear (!) the page referenced bit. */
381 asm volatile ("sske %0,%1"
382 : : "d" (0), "a" (*ptep));
383 return 1;
384 }
385
386 static inline pte_t ptep_get_and_clear(pte_t *ptep)
387 {
388 pte_t pte = *ptep;
389 pte_clear(ptep);
390 return pte;
391 }
392
393 static inline void ptep_set_wrprotect(pte_t *ptep)
394 {
395 pte_t old_pte = *ptep;
396 set_pte(ptep, pte_wrprotect(old_pte));
397 }
398
399 static inline void ptep_mkdirty(pte_t *ptep)
400 {
401 pte_mkdirty(*ptep);
402 }
403
404 /*
405 * Conversion functions: convert a page and protection to a page entry,
406 * and a page entry and page directory to the page they refer to.
407 */
408 extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
409 {
410 pte_t __pte;
411 pte_val(__pte) = physpage + pgprot_val(pgprot);
412 return __pte;
413 }
414 #define mk_pte(page,pgprot) mk_pte_phys(__pa(((page)-mem_map)<<PAGE_SHIFT),pgprot)
415
416 #define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT)))
417
418 #define pmd_page(pmd) \
419 ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
420
421 /* to find an entry in a page-table-directory */
422 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
423 #define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
424
425 /* to find an entry in a kernel page-table-directory */
426 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
427
428 /* Find an entry in the second-level page table.. */
429 extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
430 {
431 return (pmd_t *) dir;
432 }
433
434 /* Find an entry in the third-level page table.. */
435 #define pte_offset(pmd, address) \
436 ((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2))))
437
438 /*
439 * A page-table entry has some bits we have to treat in a special way.
440 * Bits 0, 20 and bit 23 have to be zero, otherwise an specification
441 * exception will occur instead of a page translation exception. The
442 * specifiation exception has the bad habit not to store necessary
443 * information in the lowcore.
444 * Bit 21 and bit 22 are the page invalid bit and the page protection
445 * bit. We set both to indicate a swapped page.
446 * Bit 31 is used as the software page present bit. If a page is
447 * swapped this obviously has to be zero.
448 * This leaves the bits 1-19 and bits 24-30 to store type and offset.
449 * We use the 7 bits from 24-30 for the type and the 19 bits from 1-19
450 * for the offset.
451 * 0| offset |0110|type |0
452 * 00000000001111111111222222222233
453 * 01234567890123456789012345678901
454 */
455 extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
456 {
457 pte_t pte;
458 pte_val(pte) = (type << 1) | (offset << 12) | _PAGE_INVALID | _PAGE_RO;
459 pte_val(pte) &= 0x7ffff6fe; /* better to be paranoid */
460 return pte;
461 }
462
463 #define SWP_TYPE(entry) (((entry).val >> 1) & 0x3f)
464 #define SWP_OFFSET(entry) (((entry).val >> 12) & 0x7FFFF )
465 #define SWP_ENTRY(type,offset) ((swp_entry_t) { pte_val(mk_swap_pte((type),(offset))) })
466
467 #define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
468 #define swp_entry_to_pte(x) ((pte_t) { (x).val })
469
470 #endif /* !__ASSEMBLY__ */
471
472 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
473 #define PageSkip(page) (0)
474 #define kern_addr_valid(addr) (1)
475
476 #endif /* _S390_PAGE_H */
477
478