Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
422 | giacomo | 1 | #ifndef _I386_PGTABLE_3LEVEL_H |
2 | #define _I386_PGTABLE_3LEVEL_H |
||
3 | |||
4 | /* |
||
5 | * Intel Physical Address Extension (PAE) Mode - three-level page |
||
6 | * tables on PPro+ CPUs. |
||
7 | * |
||
8 | * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> |
||
9 | */ |
||
10 | |||
11 | /* |
||
12 | * PGDIR_SHIFT determines what a top-level page table entry can map |
||
13 | */ |
||
14 | #define PGDIR_SHIFT 30 |
||
15 | #define PTRS_PER_PGD 4 |
||
16 | |||
17 | /* |
||
18 | * PMD_SHIFT determines the size of the area a middle-level |
||
19 | * page table can map |
||
20 | */ |
||
21 | #define PMD_SHIFT 21 |
||
22 | #define PTRS_PER_PMD 512 |
||
23 | |||
24 | /* |
||
25 | * entries per page directory level |
||
26 | */ |
||
27 | #define PTRS_PER_PTE 512 |
||
28 | |||
29 | #define pte_ERROR(e) \ |
||
30 | printk("%s:%d: bad pte %p(%08lx%08lx).\n", __FILE__, __LINE__, &(e), (e).pte_high, (e).pte_low) |
||
31 | #define pmd_ERROR(e) \ |
||
32 | printk("%s:%d: bad pmd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pmd_val(e)) |
||
33 | #define pgd_ERROR(e) \ |
||
34 | printk("%s:%d: bad pgd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pgd_val(e)) |
||
35 | |||
36 | static inline int pgd_none(pgd_t pgd) { return 0; } |
||
37 | static inline int pgd_bad(pgd_t pgd) { return 0; } |
||
38 | static inline int pgd_present(pgd_t pgd) { return 1; } |
||
39 | |||
40 | /* Rules for using set_pte: the pte being assigned *must* be |
||
41 | * either not present or in a state where the hardware will |
||
42 | * not attempt to update the pte. In places where this is |
||
43 | * not possible, use pte_get_and_clear to obtain the old pte |
||
44 | * value and then use set_pte to update it. -ben |
||
45 | */ |
||
46 | static inline void set_pte(pte_t *ptep, pte_t pte) |
||
47 | { |
||
48 | ptep->pte_high = pte.pte_high; |
||
49 | smp_wmb(); |
||
50 | ptep->pte_low = pte.pte_low; |
||
51 | } |
||
52 | #define set_pte_atomic(pteptr,pteval) \ |
||
53 | set_64bit((unsigned long long *)(pteptr),pte_val(pteval)) |
||
54 | #define set_pmd(pmdptr,pmdval) \ |
||
55 | set_64bit((unsigned long long *)(pmdptr),pmd_val(pmdval)) |
||
56 | #define set_pgd(pgdptr,pgdval) \ |
||
57 | set_64bit((unsigned long long *)(pgdptr),pgd_val(pgdval)) |
||
58 | |||
59 | /* |
||
60 | * Pentium-II erratum A13: in PAE mode we explicitly have to flush |
||
61 | * the TLB via cr3 if the top-level pgd is changed... |
||
62 | * We do not let the generic code free and clear pgd entries due to |
||
63 | * this erratum. |
||
64 | */ |
||
65 | static inline void pgd_clear (pgd_t * pgd) { } |
||
66 | |||
67 | #define pgd_page(pgd) \ |
||
68 | ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK)) |
||
69 | |||
70 | /* Find an entry in the second-level page table.. */ |
||
71 | #define pmd_offset(dir, address) ((pmd_t *) pgd_page(*(dir)) + \ |
||
72 | pmd_index(address)) |
||
73 | |||
74 | static inline pte_t ptep_get_and_clear(pte_t *ptep) |
||
75 | { |
||
76 | pte_t res; |
||
77 | |||
78 | /* xchg acts as a barrier before the setting of the high bits */ |
||
79 | res.pte_low = xchg(&ptep->pte_low, 0); |
||
80 | res.pte_high = ptep->pte_high; |
||
81 | ptep->pte_high = 0; |
||
82 | |||
83 | return res; |
||
84 | } |
||
85 | |||
86 | static inline int pte_same(pte_t a, pte_t b) |
||
87 | { |
||
88 | return a.pte_low == b.pte_low && a.pte_high == b.pte_high; |
||
89 | } |
||
90 | |||
91 | #define pte_page(x) pfn_to_page(pte_pfn(x)) |
||
92 | |||
93 | static inline int pte_none(pte_t pte) |
||
94 | { |
||
95 | return !pte.pte_low && !pte.pte_high; |
||
96 | } |
||
97 | |||
98 | static inline unsigned long pte_pfn(pte_t pte) |
||
99 | { |
||
100 | return (pte.pte_low >> PAGE_SHIFT) | |
||
101 | (pte.pte_high << (32 - PAGE_SHIFT)); |
||
102 | } |
||
103 | |||
104 | static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) |
||
105 | { |
||
106 | pte_t pte; |
||
107 | |||
108 | pte.pte_high = page_nr >> (32 - PAGE_SHIFT); |
||
109 | pte.pte_low = (page_nr << PAGE_SHIFT) | pgprot_val(pgprot); |
||
110 | return pte; |
||
111 | } |
||
112 | |||
113 | static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) |
||
114 | { |
||
115 | return __pmd(((unsigned long long)page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); |
||
116 | } |
||
117 | |||
118 | /* |
||
119 | * Bits 0, 6 and 7 are taken in the low part of the pte, |
||
120 | * put the 32 bits of offset into the high part. |
||
121 | */ |
||
122 | #define pte_to_pgoff(pte) ((pte).pte_high) |
||
123 | #define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) }) |
||
124 | #define PTE_FILE_MAX_BITS 32 |
||
125 | |||
126 | #endif /* _I386_PGTABLE_3LEVEL_H */ |