1 /* * Last edited: Nov 7 23:44 1995 (cort) */
2 #ifndef _PPC_PGTABLE_H
3 #define _PPC_PGTABLE_H
4
5 #include <asm/page.h>
6 #include <asm/mmu.h>
7
8 /*
9 * Memory management on the PowerPC is a software emulation of the i386
10 * MMU folded onto the PowerPC hardware MMU. The emulated version looks
11 * and behaves like the two-level i386 MMU. Entries from these tables
12 * are merged into the PowerPC hashed MMU tables, on demand, treating the
13 * hashed tables like a special cache.
14 *
15 * Since the PowerPC does not have separate kernel and user address spaces,
16 * the user virtual address space must be a [proper] subset of the kernel
17 * space. Thus, all tasks will have a specific virtual mapping for the
18 * user virtual space and a common mapping for the kernel space. The
19 * simplest way to split this was literally in half. Also, life is so
20 * much simpler for the kernel if the machine hardware resources are
21 * always mapped in. Thus, some additional space is given up to the
22 * kernel space to accomodate this.
23 *
24 * CAUTION! Some of the trade-offs make sense for the PreP platform on
25 * which this code was originally developed. When it migrates to other
26 * PowerPC environments, some of the assumptions may fail and the whole
27 * setup may need to be reevaluated.
28 *
29 * On the PowerPC, page translations are kept in a hashed table. There
30 * is exactly one of these tables [although the architecture supports
31 * an arbitrary number]. Page table entries move in/out of this hashed
32 * structure on demand, with the kernel filling in entries as they are
33 * needed. Just where a page table entry hits in the hashed table is a
34 * function of the hashing which is in turn based on the upper 4 bits
35 * of the logical address. These 4 bits address a "virtual segment id"
36 * which is unique per task/page combination for user addresses and
37 * fixed for the kernel addresses. Thus, the kernel space can be simply
38 * shared [indeed at low overhead] amoung all tasks.
39 *
40 * The basic virtual address space is thus:
41 *
42 * 0x0XXXXXX --+
43 * 0x1XXXXXX |
44 * 0x2XXXXXX | User address space.
45 * 0x3XXXXXX |
46 * 0x4XXXXXX |
47 * 0x5XXXXXX |
48 * 0x6XXXXXX |
49 * 0x7XXXXXX --+
50 * 0x8XXXXXX PCI/ISA I/O space
51 * 0x9XXXXXX --+
52 * 0xAXXXXXX | Kernel virtual memory
53 * 0xBXXXXXX --+
54 * 0xCXXXXXX PCI/ISA Memory space
55 * 0xDXXXXXX
56 * 0xEXXXXXX
57 * 0xFXXXXXX Board I/O space
58 *
59 * CAUTION! One of the real problems here is keeping the software
60 * managed tables coherent with the hardware hashed tables. When
61 * the software decides to update the table, it's normally easy to
62 * update the hardware table. But when the hardware tables need
63 * changed, e.g. as the result of a page fault, it's more difficult
64 * to reflect those changes back into the software entries. Currently,
65 * this process is quite crude, with updates causing the entire set
66 * of tables to become invalidated. Some performance could certainly
67 * be regained by improving this.
68 *
69 * The Linux memory management assumes a three-level page table setup. On
70 * the i386, we use that, but "fold" the mid level into the top-level page
71 * table, so that we physically have the same two-level page table as the
72 * i386 mmu expects.
73 *
74 * This file contains the functions and defines necessary to modify and use
75 * the i386 page table tree.
76 */
77
78 /* PMD_SHIFT determines the size of the area a second-level page table can map */
79 #define PMD_SHIFT 22
80 #define PMD_SIZE (1UL << PMD_SHIFT)
81 #define PMD_MASK (~(PMD_SIZE-1))
82
83 /* PGDIR_SHIFT determines what a third-level page table entry can map */
84 #define PGDIR_SHIFT 22
85 #define PGDIR_SIZE (1UL << PGDIR_SHIFT)
86 #define PGDIR_MASK (~(PGDIR_SIZE-1))
87
88 /*
89 * entries per page directory level: the i386 is two-level, so
90 * we don't really have any PMD directory physically.
91 */
92 #define PTRS_PER_PTE 1024
93 #define PTRS_PER_PMD 1
94 #define PTRS_PER_PGD 1024
95
96 /* Just any arbitrary offset to the start of the vmalloc VM area: the
97 * current 8MB value just means that there will be a 8MB "hole" after the
98 * physical memory until the kernel virtual memory starts. That means that
99 * any out-of-bounds memory accesses will hopefully be caught.
100 * The vmalloc() routines leaves a hole of 4kB between each vmalloced
101 * area for the same reason. ;)
102 */
103 #define VMALLOC_OFFSET (8*1024*1024)
104 #define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
105 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
106
107 #define _PAGE_PRESENT 0x001
108 #define _PAGE_RW 0x002
109 #define _PAGE_USER 0x004
110 #define _PAGE_PCD 0x010
111 #define _PAGE_ACCESSED 0x020
112 #define _PAGE_DIRTY 0x040
113 #define _PAGE_COW 0x200 /* implemented in software (one of the AVL bits) */
114
115 #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
116 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
117
118 #define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
119 #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
120 #define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_COW)
121 #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
122 #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
123
124 /*
125 * The i386 can't do page protection for execute, and considers that the same are read.
126 * Also, write permissions imply read permissions. This is the closest we can get..
127 */
128 #define __P000 PAGE_NONE
129 #define __P001 PAGE_READONLY
130 #define __P010 PAGE_COPY
131 #define __P011 PAGE_COPY
132 #define __P100 PAGE_READONLY
133 #define __P101 PAGE_READONLY
134 #define __P110 PAGE_COPY
135 #define __P111 PAGE_COPY
136
137 #define __S000 PAGE_NONE
138 #define __S001 PAGE_READONLY
139 #define __S010 PAGE_SHARED
140 #define __S011 PAGE_SHARED
141 #define __S100 PAGE_READONLY
142 #define __S101 PAGE_READONLY
143 #define __S110 PAGE_SHARED
144 #define __S111 PAGE_SHARED
145
146 /*
147 * Define this if things work differently on a i386 and a i486:
148 * it will (on a i486) warn about kernel memory accesses that are
149 * done without a 'verify_area(VERIFY_WRITE,..)'
150 */
151 #undef CONFIG_TEST_VERIFY_AREA
152
153 /* page table for 0-4MB for everybody */
154 extern unsigned long pg0[1024];
155
156 /*
157 * BAD_PAGETABLE is used when we need a bogus page-table, while
158 * BAD_PAGE is used for a bogus page.
159 *
160 * ZERO_PAGE is a global shared page that is always zero: used
161 * for zero-mapped memory areas etc..
162 */
163 extern pte_t __bad_page(void);
164 extern pte_t * __bad_pagetable(void);
165
166 extern unsigned long __zero_page(void);
167
168 #define BAD_PAGETABLE __bad_pagetable()
169 #define BAD_PAGE __bad_page()
170 #define ZERO_PAGE __zero_page()
171
172 /* number of bits that fit into a memory pointer */
173 #define BITS_PER_PTR (8*sizeof(unsigned long))
174
175 /* to align the pointer to a pointer address */
176 #define PTR_MASK (~(sizeof(void*)-1))
177
178 /* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
179 /* 64-bit machines, beware! SRB. */
180 #define SIZEOF_PTR_LOG2 2
181
182 /* to find an entry in a page-table */
183 #define PAGE_PTR(address) \
184 ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
185
186 /* to set the page-dir */
187 /* tsk is a task_struct and pgdir is a pte_t */
188 #define SET_PAGE_DIR(tsk,pgdir) \
189 do { \
190 (tsk)->tss.pg_tables = (unsigned long *)(pgdir); \
191 if ((tsk) == current) \
192 { \
193 /*_printk("Change page tables = %x\n", pgdir);*/ \
194 } \
195 } while (0)
196
197 extern unsigned long high_memory;
198
199 extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
200 extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
201 extern inline int pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)].reserved; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
202 /*extern inline int pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)] != 1; }*/
203 extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
204 extern inline void pte_reuse(pte_t * ptep)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
205 {
206 if (!mem_map[MAP_NR(ptep)].reserved)
207 mem_map[MAP_NR(ptep)].count++;
208 }
209 /*
210 extern inline void pte_reuse(pte_t * ptep)
211 {
212 if (!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
213 mem_map[MAP_NR(ptep)]++;
214 }
215 */
216 extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
217 extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
218 extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_PRESENT; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
219 extern inline int pmd_inuse(pmd_t *pmdp) { return 0; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
220 extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
221 extern inline void pmd_reuse(pmd_t * pmdp) { }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
222
223 /*
224 * The "pgd_xxx()" functions here are trivial for a folded two-level
225 * setup: the pgd is never bad, and a pmd always exists (as it's folded
226 * into the pgd entry)
227 */
228 extern inline int pgd_none(pgd_t pgd) { return 0; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
229 extern inline int pgd_bad(pgd_t pgd) { return 0; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
230 extern inline int pgd_present(pgd_t pgd) { return 1; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
231 /*extern inline int pgd_inuse(pgd_t * pgdp) { return mem_map[MAP_NR(pgdp)] != 1; }*/
232 extern inline int pgd_inuse(pgd_t *pgdp) { return mem_map[MAP_NR(pgdp)].reserved; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
233 extern inline void pgd_clear(pgd_t * pgdp) { }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
234
235 /*
236 extern inline void pgd_reuse(pgd_t * pgdp)
237 {
238 if (!mem_map[MAP_NR(pgdp)].reserved)
239 mem_map[MAP_NR(pgdp)].count++;
240 }
241 */
242
243 /*
244 * The following only work if pte_present() is true.
245 * Undefined behaviour if not..
246 */
247 extern inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
248 extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
249 extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
250 extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
251 extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
252 extern inline int pte_cow(pte_t pte) { return pte_val(pte) & _PAGE_COW; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
253
254 extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_RW; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
255 extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
256 extern inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
257 extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
258 extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
259 extern inline pte_t pte_uncow(pte_t pte) { pte_val(pte) &= ~_PAGE_COW; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
260 extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_RW; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
261 extern inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_USER; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
262 extern inline pte_t pte_mkexec(pte_t pte) { pte_val(pte) |= _PAGE_USER; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
263 extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
264 extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
265 extern inline pte_t pte_mkcow(pte_t pte) { pte_val(pte) |= _PAGE_COW; return pte; }
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
266
267 /*
268 * Conversion functions: convert a page and protection to a page entry,
269 * and a page entry and page directory to the page they refer to.
270 */
271 extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
272 { pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
273
274 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
275 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
276
277 /*extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
278 { pmd_val(*pmdp) = _PAGE_TABLE | ((((unsigned long) ptep) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
279 */
280 extern inline unsigned long pte_page(pte_t pte)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
281 { return pte_val(pte) & PAGE_MASK; }
282
283 extern inline unsigned long pmd_page(pmd_t pmd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
284 { return pmd_val(pmd) & PAGE_MASK; }
285
286
287 /* to find an entry in a page-table-directory */
288 extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
289 {
290 return mm->pgd + (address >> PGDIR_SHIFT);
291 }
292
293 /* Find an entry in the second-level page table.. */
294 extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
295 {
296 return (pmd_t *) dir;
297 }
298
299 /* Find an entry in the third-level page table.. */
300 extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
301 {
302 return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
303 }
304
305
306 /*
307 * Allocate and free page tables. The xxx_kernel() versions are
308 * used to allocate a kernel page table - this turns on ASN bits
309 * if any, and marks the page tables reserved.
310 */
311 extern inline void pte_free_kernel(pte_t * pte)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
312 {
313 mem_map[MAP_NR(pte)].reserved = 1;
314 free_page((unsigned long) pte);
315 }
316 /*extern inline void pte_free_kernel(pte_t * pte)
317 {
318 mem_map[MAP_NR(pte)] = 1;
319 free_page((unsigned long) pte);
320 }
321 */
322
323 /*
324 extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
325 {
326 address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
327 if (pmd_none(*pmd)) {
328 pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
329 if (pmd_none(*pmd)) {
330 if (page) {
331 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
332 mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
333 return page + address;
334 }
335 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
336 return NULL;
337 }
338 free_page((unsigned long) page);
339 }
340 if (pmd_bad(*pmd)) {
341 printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
342 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
343 return NULL;
344 }
345 return (pte_t *) pmd_page(*pmd) + address;
346 }*/
347 /*
348 extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
349 {
350 printk("pte_alloc_kernel pmd = %08X, address = %08X\n", pmd, address);
351 address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
352 printk("address now = %08X\n", address);
353 if (pmd_none(*pmd)) {
354 pte_t *page;
355 printk("pmd_none(*pmd) true\n");
356 page = (pte_t *) get_free_page(GFP_KERNEL);
357 printk("page = %08X after get_free_page(%08X)\n",page,GFP_KERNEL);
358 if (pmd_none(*pmd)) {
359 printk("pmd_none(*pmd=%08X) still\n",*pmd);
360 if (page) {
361 printk("page true = %08X\n",page);
362 pmd_set(pmd, page);
363 printk("pmd_set(%08X,%08X)\n",pmd,page);
364 mem_map[MAP_NR(page)].reserved = 1;
365 printk("did mem_map\n",pmd,page);
366 return page + address;
367 }
368 printk("did pmd_set(%08X, %08X\n",pmd,BAD_PAGETABLE);
369 pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
370 return NULL;
371 }
372 printk("did free_page(%08X)\n",page);
373 free_page((unsigned long) page);
374 }
375 if (pmd_bad(*pmd)) {
376 printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
377 pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
378 return NULL;
379 }
380 printk("returning pmd_page(%08X) + %08X\n",pmd_page(*pmd) , address);
381
382 return (pte_t *) pmd_page(*pmd) + address;
383 }
384 */
385 extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
386 {
387 address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
388 if (pmd_none(*pmd)) {
389 pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
390 if (pmd_none(*pmd)) {
391 if (page) {
392 /* pmd_set(pmd,page);*/
393 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
394 mem_map[MAP_NR(page)].reserved = 1;
395 return page + address;
396 }
397 /* pmd_set(pmd, BAD_PAGETABLE);*/
398 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
399 return NULL;
400 }
401 free_page((unsigned long) page);
402 }
403 if (pmd_bad(*pmd)) {
404 printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
405 /* pmd_set(pmd, (pte_t *) BAD_PAGETABLE); */
406 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
407 return NULL;
408 }
409 return (pte_t *) pmd_page(*pmd) + address;
410 }
411
412 /*
413 * allocating and freeing a pmd is trivial: the 1-entry pmd is
414 * inside the pgd, so has no extra memory associated with it.
415 */
416 extern inline void pmd_free_kernel(pmd_t * pmd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
417 {
418 }
419
420 extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
421 {
422 return (pmd_t *) pgd;
423 }
424
425 extern inline void pte_free(pte_t * pte)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
426 {
427 free_page((unsigned long) pte);
428 }
429
430 extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
431 {
432 address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
433 if (pmd_none(*pmd)) {
434 pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
435 if (pmd_none(*pmd)) {
436 if (page) {
437 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
438 return page + address;
439 }
440 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
441 return NULL;
442 }
443 free_page((unsigned long) page);
444 }
445 if (pmd_bad(*pmd)) {
446 printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
447 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
448 return NULL;
449 }
450 return (pte_t *) pmd_page(*pmd) + address;
451 }
452
453 /*
454 * allocating and freeing a pmd is trivial: the 1-entry pmd is
455 * inside the pgd, so has no extra memory associated with it.
456 */
457 extern inline void pmd_free(pmd_t * pmd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
458 {
459 }
460
461 extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
462 {
463 return (pmd_t *) pgd;
464 }
465
466 extern inline void pgd_free(pgd_t * pgd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
467 {
468 free_page((unsigned long) pgd);
469 }
470
471 extern inline pgd_t * pgd_alloc(void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
472 {
473 return (pgd_t *) get_free_page(GFP_KERNEL);
474 }
475
476 extern pgd_t swapper_pg_dir[1024*8];
477 /*extern pgd_t *swapper_pg_dir;*/
478
479 /*
480 * Software maintained MMU tables may have changed -- update the
481 * hardware [aka cache]
482 */
483 extern inline void update_mmu_cache(struct vm_area_struct * vma,
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
484 unsigned long address, pte_t _pte)
485 {
486 #if 0
487 printk("Update MMU cache - VMA: %x, Addr: %x, PTE: %x\n", vma, address, *(long *)&_pte);
488 _printk("Update MMU cache - VMA: %x, Addr: %x, PTE: %x\n", vma, address, *(long *)&_pte);
489 /* MMU_hash_page(&(vma->vm_task)->tss, address & PAGE_MASK, (pte *)&_pte);*/
490 #endif
491 MMU_hash_page(&(current)->tss, address & PAGE_MASK, (pte *)&_pte);
492
493 }
494
495
496 #ifdef _SCHED_INIT_
497 #define INIT_MMAP { &init_task, 0, 0x40000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
498
499 #endif
500
501 #define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
502 #define SWP_OFFSET(entry) ((entry) >> 8)
503 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
504
505 #endif /* _PPC_PAGE_H */