|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
4: * All Rights Reserved.
1.1.1.2 root 5: *
1.1 root 6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
1.1.1.2 root 11: *
1.1 root 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1.1.1.2 root 15: *
1.1 root 16: * Carnegie Mellon requests users of this software to return to
1.1.1.2 root 17: *
1.1 root 18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
1.1.1.2 root 22: *
1.1 root 23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * File: pmap.h
28: *
29: * Authors: Avadis Tevanian, Jr., Michael Wayne Young
30: * Date: 1985
31: *
32: * Machine-dependent structures for the physical map module.
33: */
34:
35: #ifndef _PMAP_MACHINE_
36: #define _PMAP_MACHINE_ 1
37:
1.1.1.3 ! root 38: #ifndef __ASSEMBLER__
1.1 root 39:
40: #include <kern/lock.h>
41: #include <mach/machine/vm_param.h>
42: #include <mach/vm_statistics.h>
43: #include <mach/kern_return.h>
1.1.1.3 ! root 44: #include <mach/vm_prot.h>
! 45: #include <i386/proc_reg.h>
1.1 root 46:
47: /*
48: * Define the generic in terms of the specific
49: */
50:
1.1.1.3 ! root 51: #if defined(__i386__)
1.1 root 52: #define INTEL_PGBYTES I386_PGBYTES
53: #define INTEL_PGSHIFT I386_PGSHIFT
54: #define intel_btop(x) i386_btop(x)
55: #define intel_ptob(x) i386_ptob(x)
56: #define intel_round_page(x) i386_round_page(x)
57: #define intel_trunc_page(x) i386_trunc_page(x)
58: #define trunc_intel_to_vm(x) trunc_i386_to_vm(x)
59: #define round_intel_to_vm(x) round_i386_to_vm(x)
60: #define vm_to_intel(x) vm_to_i386(x)
1.1.1.3 ! root 61: #endif /* __i386__ */
1.1 root 62:
63: /*
1.1.1.3 ! root 64: * i386/i486 Page Table Entry
1.1 root 65: */
66:
1.1.1.3 ! root 67: #if PAE
! 68: typedef unsigned long long pt_entry_t;
! 69: #else /* PAE */
1.1 root 70: typedef unsigned int pt_entry_t;
1.1.1.3 ! root 71: #endif /* PAE */
1.1 root 72: #define PT_ENTRY_NULL ((pt_entry_t *) 0)
73:
1.1.1.3 ! root 74: #endif /* __ASSEMBLER__ */
1.1 root 75:
76: #define INTEL_OFFMASK 0xfff /* offset within page */
1.1.1.3 ! root 77: #if PAE
! 78: #define PDPSHIFT 30 /* page directory pointer */
! 79: #define PDPNUM 4 /* number of page directory pointers */
! 80: #define PDPMASK 3 /* mask for page directory pointer index */
! 81: #define PDESHIFT 21 /* page descriptor shift */
! 82: #define PDEMASK 0x1ff /* mask for page descriptor index */
! 83: #define PTESHIFT 12 /* page table shift */
! 84: #define PTEMASK 0x1ff /* mask for page table index */
! 85: #else /* PAE */
! 86: #define PDPNUM 1 /* number of page directory pointers */
1.1 root 87: #define PDESHIFT 22 /* page descriptor shift */
88: #define PDEMASK 0x3ff /* mask for page descriptor index */
89: #define PTESHIFT 12 /* page table shift */
90: #define PTEMASK 0x3ff /* mask for page table index */
1.1.1.3 ! root 91: #endif /* PAE */
1.1 root 92:
93: /*
94: * Convert linear offset to page descriptor index
95: */
1.1.1.3 ! root 96: #if PAE
! 97: /* Making it include the page directory pointer table index too */
! 98: #define lin2pdenum(a) (((a) >> PDESHIFT) & 0x7ff)
! 99: #else
1.1 root 100: #define lin2pdenum(a) (((a) >> PDESHIFT) & PDEMASK)
1.1.1.3 ! root 101: #endif
! 102:
! 103: /*
! 104: * Convert linear offset to page directory pointer index
! 105: */
! 106: #if PAE
! 107: #define lin2pdpnum(a) (((a) >> PDPSHIFT) & PDPMASK)
! 108: #endif
1.1 root 109:
110: /*
111: * Convert page descriptor index to linear address
112: */
113: #define pdenum2lin(a) ((vm_offset_t)(a) << PDESHIFT)
114:
115: /*
116: * Convert linear offset to page table index
117: */
118: #define ptenum(a) (((a) >> PTESHIFT) & PTEMASK)
119:
120: #define NPTES (intel_ptob(1)/sizeof(pt_entry_t))
1.1.1.3 ! root 121: #define NPDES (PDPNUM * (intel_ptob(1)/sizeof(pt_entry_t)))
1.1 root 122:
123: /*
124: * Hardware pte bit definitions (to be used directly on the ptes
125: * without using the bit fields).
126: */
127:
128: #define INTEL_PTE_VALID 0x00000001
129: #define INTEL_PTE_WRITE 0x00000002
130: #define INTEL_PTE_USER 0x00000004
131: #define INTEL_PTE_WTHRU 0x00000008
132: #define INTEL_PTE_NCACHE 0x00000010
133: #define INTEL_PTE_REF 0x00000020
134: #define INTEL_PTE_MOD 0x00000040
1.1.1.3 ! root 135: #ifdef MACH_PV_PAGETABLES
! 136: /* Not supported */
! 137: #define INTEL_PTE_GLOBAL 0x00000000
! 138: #else /* MACH_PV_PAGETABLES */
! 139: #define INTEL_PTE_GLOBAL 0x00000100
! 140: #endif /* MACH_PV_PAGETABLES */
1.1 root 141: #define INTEL_PTE_WIRED 0x00000200
1.1.1.3 ! root 142: #ifdef PAE
! 143: #define INTEL_PTE_PFN 0x00007ffffffff000ULL
! 144: #else
1.1 root 145: #define INTEL_PTE_PFN 0xfffff000
1.1.1.3 ! root 146: #endif
1.1 root 147:
148: #define pa_to_pte(a) ((a) & INTEL_PTE_PFN)
1.1.1.3 ! root 149: #ifdef MACH_PSEUDO_PHYS
! 150: #define pte_to_pa(p) ma_to_pa((p) & INTEL_PTE_PFN)
! 151: #else /* MACH_PSEUDO_PHYS */
1.1 root 152: #define pte_to_pa(p) ((p) & INTEL_PTE_PFN)
1.1.1.3 ! root 153: #endif /* MACH_PSEUDO_PHYS */
1.1 root 154: #define pte_increment_pa(p) ((p) += INTEL_OFFMASK+1)
155:
156: /*
157: * Convert page table entry to kernel virtual address
158: */
159: #define ptetokv(a) (phystokv(pte_to_pa(a)))
160:
1.1.1.3 ! root 161: #ifndef __ASSEMBLER__
1.1 root 162: typedef volatile long cpu_set; /* set of CPUs - must be <= 32 */
163: /* changed by other processors */
164:
165: struct pmap {
1.1.1.3 ! root 166: pt_entry_t *dirbase; /* page directory table */
! 167: #if PAE
! 168: pt_entry_t *pdpbase; /* page directory pointer table */
! 169: #endif /* PAE */
1.1 root 170: int ref_count; /* reference count */
171: decl_simple_lock_data(,lock)
172: /* lock on map */
173: struct pmap_statistics stats; /* map statistics */
174: cpu_set cpus_using; /* bitmap of cpus using pmap */
175: };
176:
177: typedef struct pmap *pmap_t;
178:
179: #define PMAP_NULL ((pmap_t) 0)
180:
1.1.1.3 ! root 181: #ifdef MACH_PV_PAGETABLES
! 182: extern void pmap_set_page_readwrite(void *addr);
! 183: extern void pmap_set_page_readonly(void *addr);
! 184: extern void pmap_set_page_readonly_init(void *addr);
! 185: extern void pmap_map_mfn(void *addr, unsigned long mfn);
! 186: extern void pmap_clear_bootstrap_pagetable(pt_entry_t *addr);
! 187: #endif /* MACH_PV_PAGETABLES */
! 188:
! 189: #if PAE
! 190: #define set_pmap(pmap) set_cr3(kvtophys((vm_offset_t)(pmap)->pdpbase))
! 191: #else /* PAE */
! 192: #define set_pmap(pmap) set_cr3(kvtophys((vm_offset_t)(pmap)->dirbase))
! 193: #endif /* PAE */
1.1 root 194:
195: #if NCPUS > 1
196: /*
197: * List of cpus that are actively using mapped memory. Any
198: * pmap update operation must wait for all cpus in this list.
199: * Update operations must still be queued to cpus not in this
200: * list.
201: */
202: cpu_set cpus_active;
203:
204: /*
205: * List of cpus that are idle, but still operating, and will want
206: * to see any kernel pmap updates when they become active.
207: */
208: cpu_set cpus_idle;
209:
210: /*
211: * Quick test for pmap update requests.
212: */
213: volatile
214: boolean_t cpu_update_needed[NCPUS];
215:
216: /*
217: * External declarations for PMAP_ACTIVATE.
218: */
219:
1.1.1.3 ! root 220: void process_pmap_updates(pmap_t);
! 221: void pmap_update_interrupt(void);
1.1 root 222: extern pmap_t kernel_pmap;
223:
1.1.1.2 root 224: #endif /* NCPUS > 1 */
1.1 root 225:
226: /*
1.1.1.3 ! root 227: * Machine dependent routines that are used only for i386/i486.
1.1 root 228: */
229:
230: pt_entry_t *pmap_pte(pmap_t pmap, vm_offset_t addr);
231:
232: /*
233: * Macros for speed.
234: */
235:
236: #if NCPUS > 1
237:
238: /*
239: * For multiple CPUS, PMAP_ACTIVATE and PMAP_DEACTIVATE must manage
240: * fields to control TLB invalidation on other CPUS.
241: */
242:
243: #define PMAP_ACTIVATE_KERNEL(my_cpu) { \
244: \
245: /* \
246: * Let pmap updates proceed while we wait for this pmap. \
247: */ \
248: i_bit_clear((my_cpu), &cpus_active); \
249: \
250: /* \
251: * Lock the pmap to put this cpu in its active set. \
252: * Wait for updates here. \
253: */ \
254: simple_lock(&kernel_pmap->lock); \
255: \
256: /* \
257: * Process invalidate requests for the kernel pmap. \
258: */ \
259: if (cpu_update_needed[(my_cpu)]) \
260: process_pmap_updates(kernel_pmap); \
261: \
262: /* \
263: * Mark that this cpu is using the pmap. \
264: */ \
265: i_bit_set((my_cpu), &kernel_pmap->cpus_using); \
266: \
267: /* \
268: * Mark this cpu active - IPL will be lowered by \
269: * load_context(). \
270: */ \
271: i_bit_set((my_cpu), &cpus_active); \
272: \
273: simple_unlock(&kernel_pmap->lock); \
274: }
275:
276: #define PMAP_DEACTIVATE_KERNEL(my_cpu) { \
277: /* \
278: * Mark pmap no longer in use by this cpu even if \
279: * pmap is locked against updates. \
280: */ \
281: i_bit_clear((my_cpu), &kernel_pmap->cpus_using); \
282: }
283:
284: #define PMAP_ACTIVATE_USER(pmap, th, my_cpu) { \
285: register pmap_t tpmap = (pmap); \
286: \
287: if (tpmap == kernel_pmap) { \
288: /* \
289: * If this is the kernel pmap, switch to its page tables. \
290: */ \
1.1.1.3 ! root 291: set_pmap(tpmap); \
1.1 root 292: } \
293: else { \
294: /* \
295: * Let pmap updates proceed while we wait for this pmap. \
296: */ \
297: i_bit_clear((my_cpu), &cpus_active); \
298: \
299: /* \
300: * Lock the pmap to put this cpu in its active set. \
301: * Wait for updates here. \
302: */ \
303: simple_lock(&tpmap->lock); \
304: \
305: /* \
306: * No need to invalidate the TLB - the entire user pmap \
307: * will be invalidated by reloading dirbase. \
308: */ \
1.1.1.3 ! root 309: set_pmap(tpmap); \
1.1 root 310: \
311: /* \
312: * Mark that this cpu is using the pmap. \
313: */ \
314: i_bit_set((my_cpu), &tpmap->cpus_using); \
315: \
316: /* \
317: * Mark this cpu active - IPL will be lowered by \
318: * load_context(). \
319: */ \
320: i_bit_set((my_cpu), &cpus_active); \
321: \
322: simple_unlock(&tpmap->lock); \
323: } \
324: }
325:
326: #define PMAP_DEACTIVATE_USER(pmap, thread, my_cpu) { \
327: register pmap_t tpmap = (pmap); \
328: \
329: /* \
330: * Do nothing if this is the kernel pmap. \
331: */ \
332: if (tpmap != kernel_pmap) { \
333: /* \
334: * Mark pmap no longer in use by this cpu even if \
335: * pmap is locked against updates. \
336: */ \
337: i_bit_clear((my_cpu), &(pmap)->cpus_using); \
338: } \
339: }
340:
341: #define MARK_CPU_IDLE(my_cpu) { \
342: /* \
343: * Mark this cpu idle, and remove it from the active set, \
344: * since it is not actively using any pmap. Signal_cpus \
345: * will notice that it is idle, and avoid signaling it, \
346: * but will queue the update request for when the cpu \
347: * becomes active. \
348: */ \
349: int s = splvm(); \
350: i_bit_set((my_cpu), &cpus_idle); \
351: i_bit_clear((my_cpu), &cpus_active); \
352: splx(s); \
353: }
354:
355: #define MARK_CPU_ACTIVE(my_cpu) { \
356: \
357: int s = splvm(); \
358: /* \
359: * If a kernel_pmap update was requested while this cpu \
360: * was idle, process it as if we got the interrupt. \
361: * Before doing so, remove this cpu from the idle set. \
362: * Since we do not grab any pmap locks while we flush \
363: * our TLB, another cpu may start an update operation \
364: * before we finish. Removing this cpu from the idle \
365: * set assures that we will receive another update \
366: * interrupt if this happens. \
367: */ \
368: i_bit_clear((my_cpu), &cpus_idle); \
369: \
370: if (cpu_update_needed[(my_cpu)]) \
371: pmap_update_interrupt(); \
372: \
373: /* \
374: * Mark that this cpu is now active. \
375: */ \
376: i_bit_set((my_cpu), &cpus_active); \
377: splx(s); \
378: }
379:
1.1.1.2 root 380: #else /* NCPUS > 1 */
1.1 root 381:
382: /*
383: * With only one CPU, we just have to indicate whether the pmap is
384: * in use.
385: */
386:
387: #define PMAP_ACTIVATE_KERNEL(my_cpu) { \
1.1.1.3 ! root 388: (void) (my_cpu); \
1.1 root 389: kernel_pmap->cpus_using = TRUE; \
390: }
391:
392: #define PMAP_DEACTIVATE_KERNEL(my_cpu) { \
1.1.1.3 ! root 393: (void) (my_cpu); \
1.1 root 394: kernel_pmap->cpus_using = FALSE; \
395: }
396:
397: #define PMAP_ACTIVATE_USER(pmap, th, my_cpu) { \
398: register pmap_t tpmap = (pmap); \
1.1.1.3 ! root 399: (void) (th); \
! 400: (void) (my_cpu); \
1.1 root 401: \
1.1.1.3 ! root 402: set_pmap(tpmap); \
1.1 root 403: if (tpmap != kernel_pmap) { \
404: tpmap->cpus_using = TRUE; \
405: } \
406: }
407:
408: #define PMAP_DEACTIVATE_USER(pmap, thread, cpu) { \
1.1.1.3 ! root 409: (void) (thread); \
! 410: (void) (cpu); \
1.1 root 411: if ((pmap) != kernel_pmap) \
412: (pmap)->cpus_using = FALSE; \
413: }
414:
1.1.1.2 root 415: #endif /* NCPUS > 1 */
1.1 root 416:
417: #define PMAP_CONTEXT(pmap, thread)
418:
419: #define pmap_kernel() (kernel_pmap)
420: #define pmap_resident_count(pmap) ((pmap)->stats.resident_count)
421: #define pmap_phys_address(frame) ((vm_offset_t) (intel_ptob(frame)))
422: #define pmap_phys_to_frame(phys) ((int) (intel_btop(phys)))
423: #define pmap_copy(dst_pmap,src_pmap,dst_addr,len,src_addr)
424: #define pmap_attribute(pmap,addr,size,attr,value) \
425: (KERN_INVALID_ADDRESS)
426:
1.1.1.3 ! root 427: /*
! 428: * Bootstrap the system enough to run with virtual memory.
! 429: * Allocate the kernel page directory and page tables,
! 430: * and direct-map all physical memory.
! 431: * Called with mapping off.
! 432: */
! 433: extern void pmap_bootstrap(void);
! 434:
! 435: extern void pmap_unmap_page_zero (void);
! 436:
! 437: /*
! 438: * pmap_zero_page zeros the specified (machine independent) page.
! 439: */
! 440: extern void pmap_zero_page (vm_offset_t);
! 441:
! 442: /*
! 443: * pmap_copy_page copies the specified (machine independent) pages.
! 444: */
! 445: extern void pmap_copy_page (vm_offset_t, vm_offset_t);
! 446:
! 447: /*
! 448: * kvtophys(addr)
! 449: *
! 450: * Convert a kernel virtual address to a physical address
! 451: */
! 452: extern vm_offset_t kvtophys (vm_offset_t);
! 453:
! 454: #endif /* __ASSEMBLER__ */
1.1 root 455:
1.1.1.2 root 456: #endif /* _PMAP_MACHINE_ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.