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