|
|
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.5 ! root 67: typedef phys_addr_t pt_entry_t;
1.1 root 68: #define PT_ENTRY_NULL ((pt_entry_t *) 0)
69:
1.1.1.3 root 70: #endif /* __ASSEMBLER__ */
1.1 root 71:
72: #define INTEL_OFFMASK 0xfff /* offset within page */
1.1.1.3 root 73: #if PAE
74: #define PDPSHIFT 30 /* page directory pointer */
75: #define PDPNUM 4 /* number of page directory pointers */
76: #define PDPMASK 3 /* mask for page directory pointer index */
77: #define PDESHIFT 21 /* page descriptor shift */
78: #define PDEMASK 0x1ff /* mask for page descriptor index */
79: #define PTESHIFT 12 /* page table shift */
80: #define PTEMASK 0x1ff /* mask for page table index */
81: #else /* PAE */
82: #define PDPNUM 1 /* number of page directory pointers */
1.1 root 83: #define PDESHIFT 22 /* page descriptor shift */
84: #define PDEMASK 0x3ff /* mask for page descriptor index */
85: #define PTESHIFT 12 /* page table shift */
86: #define PTEMASK 0x3ff /* mask for page table index */
1.1.1.3 root 87: #endif /* PAE */
1.1 root 88:
89: /*
90: * Convert linear offset to page descriptor index
91: */
1.1.1.5 ! root 92: #define lin2pdenum(a) (((a) >> PDESHIFT) & PDEMASK)
! 93:
1.1.1.3 root 94: #if PAE
1.1.1.5 ! root 95: /* Special version assuming contiguous page directories. Making it
! 96: include the page directory pointer table index too. */
! 97: #define lin2pdenum_cont(a) (((a) >> PDESHIFT) & 0x7ff)
1.1.1.3 root 98: #else
1.1.1.5 ! root 99: #define lin2pdenum_cont(a) lin2pdenum(a)
1.1.1.3 root 100: #endif
101:
102: /*
103: * Convert linear offset to page directory pointer index
104: */
105: #if PAE
106: #define lin2pdpnum(a) (((a) >> PDPSHIFT) & PDPMASK)
107: #endif
1.1 root 108:
109: /*
110: * Convert page descriptor index to linear address
111: */
112: #define pdenum2lin(a) ((vm_offset_t)(a) << PDESHIFT)
113:
114: /*
115: * Convert linear offset to page table index
116: */
117: #define ptenum(a) (((a) >> PTESHIFT) & PTEMASK)
118:
119: #define NPTES (intel_ptob(1)/sizeof(pt_entry_t))
1.1.1.3 root 120: #define NPDES (PDPNUM * (intel_ptob(1)/sizeof(pt_entry_t)))
1.1 root 121:
122: /*
123: * Hardware pte bit definitions (to be used directly on the ptes
124: * without using the bit fields).
125: */
126:
127: #define INTEL_PTE_VALID 0x00000001
128: #define INTEL_PTE_WRITE 0x00000002
129: #define INTEL_PTE_USER 0x00000004
130: #define INTEL_PTE_WTHRU 0x00000008
131: #define INTEL_PTE_NCACHE 0x00000010
132: #define INTEL_PTE_REF 0x00000020
133: #define INTEL_PTE_MOD 0x00000040
1.1.1.3 root 134: #ifdef MACH_PV_PAGETABLES
135: /* Not supported */
136: #define INTEL_PTE_GLOBAL 0x00000000
137: #else /* MACH_PV_PAGETABLES */
138: #define INTEL_PTE_GLOBAL 0x00000100
139: #endif /* MACH_PV_PAGETABLES */
1.1 root 140: #define INTEL_PTE_WIRED 0x00000200
1.1.1.3 root 141: #ifdef PAE
142: #define INTEL_PTE_PFN 0x00007ffffffff000ULL
143: #else
1.1 root 144: #define INTEL_PTE_PFN 0xfffff000
1.1.1.3 root 145: #endif
1.1 root 146:
147: #define pa_to_pte(a) ((a) & INTEL_PTE_PFN)
1.1.1.3 root 148: #ifdef MACH_PSEUDO_PHYS
149: #define pte_to_pa(p) ma_to_pa((p) & INTEL_PTE_PFN)
150: #else /* MACH_PSEUDO_PHYS */
1.1 root 151: #define pte_to_pa(p) ((p) & INTEL_PTE_PFN)
1.1.1.3 root 152: #endif /* MACH_PSEUDO_PHYS */
1.1 root 153: #define pte_increment_pa(p) ((p) += INTEL_OFFMASK+1)
154:
155: /*
156: * Convert page table entry to kernel virtual address
157: */
158: #define ptetokv(a) (phystokv(pte_to_pa(a)))
159:
1.1.1.3 root 160: #ifndef __ASSEMBLER__
1.1 root 161: typedef volatile long cpu_set; /* set of CPUs - must be <= 32 */
162: /* changed by other processors */
163:
164: struct pmap {
1.1.1.5 ! root 165: #if ! PAE
1.1.1.3 root 166: pt_entry_t *dirbase; /* page directory table */
1.1.1.5 ! root 167: #else
1.1.1.3 root 168: pt_entry_t *pdpbase; /* page directory pointer table */
1.1.1.5 ! root 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:
1.1.1.4 root 195: typedef struct {
196: pt_entry_t *entry;
197: vm_offset_t vaddr;
198: } pmap_mapwindow_t;
199:
200: extern pmap_mapwindow_t *pmap_get_mapwindow(pt_entry_t entry);
201: extern void pmap_put_mapwindow(pmap_mapwindow_t *map);
202:
203: #define PMAP_NMAPWINDOWS 2
204:
1.1 root 205: #if NCPUS > 1
206: /*
207: * List of cpus that are actively using mapped memory. Any
208: * pmap update operation must wait for all cpus in this list.
209: * Update operations must still be queued to cpus not in this
210: * list.
211: */
212: cpu_set cpus_active;
213:
214: /*
215: * List of cpus that are idle, but still operating, and will want
216: * to see any kernel pmap updates when they become active.
217: */
218: cpu_set cpus_idle;
219:
220: /*
221: * Quick test for pmap update requests.
222: */
223: volatile
224: boolean_t cpu_update_needed[NCPUS];
225:
226: /*
227: * External declarations for PMAP_ACTIVATE.
228: */
229:
1.1.1.3 root 230: void process_pmap_updates(pmap_t);
231: void pmap_update_interrupt(void);
1.1 root 232: extern pmap_t kernel_pmap;
233:
1.1.1.2 root 234: #endif /* NCPUS > 1 */
1.1 root 235:
236: /*
1.1.1.3 root 237: * Machine dependent routines that are used only for i386/i486.
1.1 root 238: */
239:
1.1.1.4 root 240: pt_entry_t *pmap_pte(const pmap_t pmap, vm_offset_t addr);
1.1 root 241:
242: /*
243: * Macros for speed.
244: */
245:
246: #if NCPUS > 1
247:
248: /*
249: * For multiple CPUS, PMAP_ACTIVATE and PMAP_DEACTIVATE must manage
250: * fields to control TLB invalidation on other CPUS.
251: */
252:
253: #define PMAP_ACTIVATE_KERNEL(my_cpu) { \
254: \
255: /* \
256: * Let pmap updates proceed while we wait for this pmap. \
257: */ \
258: i_bit_clear((my_cpu), &cpus_active); \
259: \
260: /* \
261: * Lock the pmap to put this cpu in its active set. \
262: * Wait for updates here. \
263: */ \
264: simple_lock(&kernel_pmap->lock); \
265: \
266: /* \
267: * Process invalidate requests for the kernel pmap. \
268: */ \
269: if (cpu_update_needed[(my_cpu)]) \
270: process_pmap_updates(kernel_pmap); \
271: \
272: /* \
273: * Mark that this cpu is using the pmap. \
274: */ \
275: i_bit_set((my_cpu), &kernel_pmap->cpus_using); \
276: \
277: /* \
278: * Mark this cpu active - IPL will be lowered by \
279: * load_context(). \
280: */ \
281: i_bit_set((my_cpu), &cpus_active); \
282: \
283: simple_unlock(&kernel_pmap->lock); \
284: }
285:
286: #define PMAP_DEACTIVATE_KERNEL(my_cpu) { \
287: /* \
288: * Mark pmap no longer in use by this cpu even if \
289: * pmap is locked against updates. \
290: */ \
291: i_bit_clear((my_cpu), &kernel_pmap->cpus_using); \
292: }
293:
294: #define PMAP_ACTIVATE_USER(pmap, th, my_cpu) { \
1.1.1.4 root 295: pmap_t tpmap = (pmap); \
1.1 root 296: \
297: if (tpmap == kernel_pmap) { \
298: /* \
299: * If this is the kernel pmap, switch to its page tables. \
300: */ \
1.1.1.3 root 301: set_pmap(tpmap); \
1.1 root 302: } \
303: else { \
304: /* \
305: * Let pmap updates proceed while we wait for this pmap. \
306: */ \
307: i_bit_clear((my_cpu), &cpus_active); \
308: \
309: /* \
310: * Lock the pmap to put this cpu in its active set. \
311: * Wait for updates here. \
312: */ \
313: simple_lock(&tpmap->lock); \
314: \
315: /* \
316: * No need to invalidate the TLB - the entire user pmap \
317: * will be invalidated by reloading dirbase. \
318: */ \
1.1.1.3 root 319: set_pmap(tpmap); \
1.1 root 320: \
321: /* \
322: * Mark that this cpu is using the pmap. \
323: */ \
324: i_bit_set((my_cpu), &tpmap->cpus_using); \
325: \
326: /* \
327: * Mark this cpu active - IPL will be lowered by \
328: * load_context(). \
329: */ \
330: i_bit_set((my_cpu), &cpus_active); \
331: \
332: simple_unlock(&tpmap->lock); \
333: } \
334: }
335:
336: #define PMAP_DEACTIVATE_USER(pmap, thread, my_cpu) { \
1.1.1.4 root 337: pmap_t tpmap = (pmap); \
1.1 root 338: \
339: /* \
340: * Do nothing if this is the kernel pmap. \
341: */ \
342: if (tpmap != kernel_pmap) { \
343: /* \
344: * Mark pmap no longer in use by this cpu even if \
345: * pmap is locked against updates. \
346: */ \
347: i_bit_clear((my_cpu), &(pmap)->cpus_using); \
348: } \
349: }
350:
351: #define MARK_CPU_IDLE(my_cpu) { \
352: /* \
353: * Mark this cpu idle, and remove it from the active set, \
354: * since it is not actively using any pmap. Signal_cpus \
355: * will notice that it is idle, and avoid signaling it, \
356: * but will queue the update request for when the cpu \
357: * becomes active. \
358: */ \
359: int s = splvm(); \
360: i_bit_set((my_cpu), &cpus_idle); \
361: i_bit_clear((my_cpu), &cpus_active); \
362: splx(s); \
363: }
364:
365: #define MARK_CPU_ACTIVE(my_cpu) { \
366: \
367: int s = splvm(); \
368: /* \
369: * If a kernel_pmap update was requested while this cpu \
370: * was idle, process it as if we got the interrupt. \
371: * Before doing so, remove this cpu from the idle set. \
372: * Since we do not grab any pmap locks while we flush \
373: * our TLB, another cpu may start an update operation \
374: * before we finish. Removing this cpu from the idle \
375: * set assures that we will receive another update \
376: * interrupt if this happens. \
377: */ \
378: i_bit_clear((my_cpu), &cpus_idle); \
379: \
380: if (cpu_update_needed[(my_cpu)]) \
381: pmap_update_interrupt(); \
382: \
383: /* \
384: * Mark that this cpu is now active. \
385: */ \
386: i_bit_set((my_cpu), &cpus_active); \
387: splx(s); \
388: }
389:
1.1.1.2 root 390: #else /* NCPUS > 1 */
1.1 root 391:
392: /*
393: * With only one CPU, we just have to indicate whether the pmap is
394: * in use.
395: */
396:
397: #define PMAP_ACTIVATE_KERNEL(my_cpu) { \
1.1.1.3 root 398: (void) (my_cpu); \
1.1 root 399: kernel_pmap->cpus_using = TRUE; \
400: }
401:
402: #define PMAP_DEACTIVATE_KERNEL(my_cpu) { \
1.1.1.3 root 403: (void) (my_cpu); \
1.1 root 404: kernel_pmap->cpus_using = FALSE; \
405: }
406:
407: #define PMAP_ACTIVATE_USER(pmap, th, my_cpu) { \
1.1.1.4 root 408: pmap_t tpmap = (pmap); \
1.1.1.3 root 409: (void) (th); \
410: (void) (my_cpu); \
1.1 root 411: \
1.1.1.3 root 412: set_pmap(tpmap); \
1.1 root 413: if (tpmap != kernel_pmap) { \
414: tpmap->cpus_using = TRUE; \
415: } \
416: }
417:
418: #define PMAP_DEACTIVATE_USER(pmap, thread, cpu) { \
1.1.1.3 root 419: (void) (thread); \
420: (void) (cpu); \
1.1 root 421: if ((pmap) != kernel_pmap) \
422: (pmap)->cpus_using = FALSE; \
423: }
424:
1.1.1.2 root 425: #endif /* NCPUS > 1 */
1.1 root 426:
427: #define PMAP_CONTEXT(pmap, thread)
428:
429: #define pmap_kernel() (kernel_pmap)
430: #define pmap_resident_count(pmap) ((pmap)->stats.resident_count)
431: #define pmap_phys_address(frame) ((vm_offset_t) (intel_ptob(frame)))
432: #define pmap_phys_to_frame(phys) ((int) (intel_btop(phys)))
433: #define pmap_copy(dst_pmap,src_pmap,dst_addr,len,src_addr)
434: #define pmap_attribute(pmap,addr,size,attr,value) \
435: (KERN_INVALID_ADDRESS)
436:
1.1.1.3 root 437: /*
438: * Bootstrap the system enough to run with virtual memory.
439: * Allocate the kernel page directory and page tables,
440: * and direct-map all physical memory.
441: * Called with mapping off.
442: */
443: extern void pmap_bootstrap(void);
444:
445: extern void pmap_unmap_page_zero (void);
446:
447: /*
448: * pmap_zero_page zeros the specified (machine independent) page.
449: */
1.1.1.5 ! root 450: extern void pmap_zero_page (phys_addr_t);
1.1.1.3 root 451:
452: /*
453: * pmap_copy_page copies the specified (machine independent) pages.
454: */
1.1.1.5 ! root 455: extern void pmap_copy_page (phys_addr_t, phys_addr_t);
1.1.1.3 root 456:
457: /*
458: * kvtophys(addr)
459: *
460: * Convert a kernel virtual address to a physical address
461: */
1.1.1.5 ! root 462: extern phys_addr_t kvtophys (vm_offset_t);
1.1.1.3 root 463:
1.1.1.4 root 464: void pmap_remove_range(
465: pmap_t pmap,
466: vm_offset_t va,
467: pt_entry_t *spte,
468: pt_entry_t *epte);
469:
470: #if NCPUS > 1
471: void signal_cpus(
472: cpu_set use_list,
473: pmap_t pmap,
474: vm_offset_t start,
475: vm_offset_t end);
476: #endif /* NCPUS > 1 */
477:
1.1.1.3 root 478: #endif /* __ASSEMBLER__ */
1.1 root 479:
1.1.1.2 root 480: #endif /* _PMAP_MACHINE_ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.