|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
4: * All Rights Reserved.
5: *
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.
11: *
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.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
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:
38: #ifndef ASSEMBLER
39:
40: #include <kern/zalloc.h>
41: #include <kern/lock.h>
42: #include <mach/machine/vm_param.h>
43: #include <mach/vm_statistics.h>
44: #include <mach/kern_return.h>
45:
46: /*
47: * Define the generic in terms of the specific
48: */
49:
50: #if i386
51: #define INTEL_PGBYTES I386_PGBYTES
52: #define INTEL_PGSHIFT I386_PGSHIFT
53: #define intel_btop(x) i386_btop(x)
54: #define intel_ptob(x) i386_ptob(x)
55: #define intel_round_page(x) i386_round_page(x)
56: #define intel_trunc_page(x) i386_trunc_page(x)
57: #define trunc_intel_to_vm(x) trunc_i386_to_vm(x)
58: #define round_intel_to_vm(x) round_i386_to_vm(x)
59: #define vm_to_intel(x) vm_to_i386(x)
60: #endif i386
61: #if i860
62: #define INTEL_PGBYTES I860_PGBYTES
63: #define INTEL_PGSHIFT I860_PGSHIFT
64: #define intel_btop(x) i860_btop(x)
65: #define intel_ptob(x) i860_ptob(x)
66: #define intel_round_page(x) i860_round_page(x)
67: #define intel_trunc_page(x) i860_trunc_page(x)
68: #define trunc_intel_to_vm(x) trunc_i860_to_vm(x)
69: #define round_intel_to_vm(x) round_i860_to_vm(x)
70: #define vm_to_intel(x) vm_to_i860(x)
71: #endif i860
72:
73: /*
74: * i386/i486/i860 Page Table Entry
75: */
76:
77: typedef unsigned int pt_entry_t;
78: #define PT_ENTRY_NULL ((pt_entry_t *) 0)
79:
80: #endif ASSEMBLER
81:
82: #define INTEL_OFFMASK 0xfff /* offset within page */
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 */
87:
88: /*
89: * Convert linear offset to page descriptor index
90: */
91: #define lin2pdenum(a) (((a) >> PDESHIFT) & PDEMASK)
92:
93: /*
94: * Convert page descriptor index to linear address
95: */
96: #define pdenum2lin(a) ((vm_offset_t)(a) << PDESHIFT)
97:
98: /*
99: * Convert linear offset to page table index
100: */
101: #define ptenum(a) (((a) >> PTESHIFT) & PTEMASK)
102:
103: #define NPTES (intel_ptob(1)/sizeof(pt_entry_t))
104: #define NPDES (intel_ptob(1)/sizeof(pt_entry_t))
105:
106: /*
107: * Hardware pte bit definitions (to be used directly on the ptes
108: * without using the bit fields).
109: */
110:
111: #if i860
112: #define INTEL_PTE_valid 0x00000001
113: #else
114: #define INTEL_PTE_VALID 0x00000001
115: #endif
116: #define INTEL_PTE_WRITE 0x00000002
117: #define INTEL_PTE_USER 0x00000004
118: #define INTEL_PTE_WTHRU 0x00000008
119: #define INTEL_PTE_NCACHE 0x00000010
120: #define INTEL_PTE_REF 0x00000020
121: #define INTEL_PTE_MOD 0x00000040
122: #define INTEL_PTE_WIRED 0x00000200
123: #define INTEL_PTE_PFN 0xfffff000
124:
125: #if i860
126: #if NOCACHE
127: #define INTEL_PTE_VALID (INTEL_PTE_valid \
128: |INTEL_PTE_WTHRU \
129: |INTEL_PTE_NCACHE \
130: |INTEL_PTE_REF \
131: |INTEL_PTE_MOD \
132: )
133: #else NOCACHE
134: #define INTEL_PTE_VALID (INTEL_PTE_valid \
135: |INTEL_PTE_REF \
136: |INTEL_PTE_MOD \
137: )
138: #endif NOCACHE
139: #endif i860
140:
141: #define pa_to_pte(a) ((a) & INTEL_PTE_PFN)
142: #define pte_to_pa(p) ((p) & INTEL_PTE_PFN)
143: #define pte_increment_pa(p) ((p) += INTEL_OFFMASK+1)
144:
145: /*
146: * Convert page table entry to kernel virtual address
147: */
148: #define ptetokv(a) (phystokv(pte_to_pa(a)))
149:
150: #ifndef ASSEMBLER
151: typedef volatile long cpu_set; /* set of CPUs - must be <= 32 */
152: /* changed by other processors */
153:
154: struct pmap {
155: pt_entry_t *dirbase; /* page directory pointer register */
156: int ref_count; /* reference count */
157: decl_simple_lock_data(,lock)
158: /* lock on map */
159: struct pmap_statistics stats; /* map statistics */
160: cpu_set cpus_using; /* bitmap of cpus using pmap */
161: };
162:
163: typedef struct pmap *pmap_t;
164:
165: #define PMAP_NULL ((pmap_t) 0)
166:
167: #if i860
168: /*#define set_dirbase(dirbase) flush_and_ctxsw(dirbase)*//*akp*/
169: #else
170: #define set_dirbase(dirbase) set_cr3(dirbase)
171: #endif
172:
173: #if NCPUS > 1
174: /*
175: * List of cpus that are actively using mapped memory. Any
176: * pmap update operation must wait for all cpus in this list.
177: * Update operations must still be queued to cpus not in this
178: * list.
179: */
180: cpu_set cpus_active;
181:
182: /*
183: * List of cpus that are idle, but still operating, and will want
184: * to see any kernel pmap updates when they become active.
185: */
186: cpu_set cpus_idle;
187:
188: /*
189: * Quick test for pmap update requests.
190: */
191: volatile
192: boolean_t cpu_update_needed[NCPUS];
193:
194: /*
195: * External declarations for PMAP_ACTIVATE.
196: */
197:
198: void process_pmap_updates();
199: void pmap_update_interrupt();
200: extern pmap_t kernel_pmap;
201:
202: #endif NCPUS > 1
203:
204: /*
205: * Machine dependent routines that are used only for i386/i486/i860.
206: */
207:
208: pt_entry_t *pmap_pte(pmap_t pmap, vm_offset_t addr);
209:
210: /*
211: * Macros for speed.
212: */
213:
214: #if NCPUS > 1
215:
216: /*
217: * For multiple CPUS, PMAP_ACTIVATE and PMAP_DEACTIVATE must manage
218: * fields to control TLB invalidation on other CPUS.
219: */
220:
221: #define PMAP_ACTIVATE_KERNEL(my_cpu) { \
222: \
223: /* \
224: * Let pmap updates proceed while we wait for this pmap. \
225: */ \
226: i_bit_clear((my_cpu), &cpus_active); \
227: \
228: /* \
229: * Lock the pmap to put this cpu in its active set. \
230: * Wait for updates here. \
231: */ \
232: simple_lock(&kernel_pmap->lock); \
233: \
234: /* \
235: * Process invalidate requests for the kernel pmap. \
236: */ \
237: if (cpu_update_needed[(my_cpu)]) \
238: process_pmap_updates(kernel_pmap); \
239: \
240: /* \
241: * Mark that this cpu is using the pmap. \
242: */ \
243: i_bit_set((my_cpu), &kernel_pmap->cpus_using); \
244: \
245: /* \
246: * Mark this cpu active - IPL will be lowered by \
247: * load_context(). \
248: */ \
249: i_bit_set((my_cpu), &cpus_active); \
250: \
251: simple_unlock(&kernel_pmap->lock); \
252: }
253:
254: #define PMAP_DEACTIVATE_KERNEL(my_cpu) { \
255: /* \
256: * Mark pmap no longer in use by this cpu even if \
257: * pmap is locked against updates. \
258: */ \
259: i_bit_clear((my_cpu), &kernel_pmap->cpus_using); \
260: }
261:
262: #define PMAP_ACTIVATE_USER(pmap, th, my_cpu) { \
263: register pmap_t tpmap = (pmap); \
264: \
265: if (tpmap == kernel_pmap) { \
266: /* \
267: * If this is the kernel pmap, switch to its page tables. \
268: */ \
269: set_dirbase(kvtophys(tpmap->dirbase)); \
270: } \
271: else { \
272: /* \
273: * Let pmap updates proceed while we wait for this pmap. \
274: */ \
275: i_bit_clear((my_cpu), &cpus_active); \
276: \
277: /* \
278: * Lock the pmap to put this cpu in its active set. \
279: * Wait for updates here. \
280: */ \
281: simple_lock(&tpmap->lock); \
282: \
283: /* \
284: * No need to invalidate the TLB - the entire user pmap \
285: * will be invalidated by reloading dirbase. \
286: */ \
287: set_dirbase(kvtophys(tpmap->dirbase)); \
288: \
289: /* \
290: * Mark that this cpu is using the pmap. \
291: */ \
292: i_bit_set((my_cpu), &tpmap->cpus_using); \
293: \
294: /* \
295: * Mark this cpu active - IPL will be lowered by \
296: * load_context(). \
297: */ \
298: i_bit_set((my_cpu), &cpus_active); \
299: \
300: simple_unlock(&tpmap->lock); \
301: } \
302: }
303:
304: #define PMAP_DEACTIVATE_USER(pmap, thread, my_cpu) { \
305: register pmap_t tpmap = (pmap); \
306: \
307: /* \
308: * Do nothing if this is the kernel pmap. \
309: */ \
310: if (tpmap != kernel_pmap) { \
311: /* \
312: * Mark pmap no longer in use by this cpu even if \
313: * pmap is locked against updates. \
314: */ \
315: i_bit_clear((my_cpu), &(pmap)->cpus_using); \
316: } \
317: }
318:
319: #define MARK_CPU_IDLE(my_cpu) { \
320: /* \
321: * Mark this cpu idle, and remove it from the active set, \
322: * since it is not actively using any pmap. Signal_cpus \
323: * will notice that it is idle, and avoid signaling it, \
324: * but will queue the update request for when the cpu \
325: * becomes active. \
326: */ \
327: int s = splvm(); \
328: i_bit_set((my_cpu), &cpus_idle); \
329: i_bit_clear((my_cpu), &cpus_active); \
330: splx(s); \
331: }
332:
333: #define MARK_CPU_ACTIVE(my_cpu) { \
334: \
335: int s = splvm(); \
336: /* \
337: * If a kernel_pmap update was requested while this cpu \
338: * was idle, process it as if we got the interrupt. \
339: * Before doing so, remove this cpu from the idle set. \
340: * Since we do not grab any pmap locks while we flush \
341: * our TLB, another cpu may start an update operation \
342: * before we finish. Removing this cpu from the idle \
343: * set assures that we will receive another update \
344: * interrupt if this happens. \
345: */ \
346: i_bit_clear((my_cpu), &cpus_idle); \
347: \
348: if (cpu_update_needed[(my_cpu)]) \
349: pmap_update_interrupt(); \
350: \
351: /* \
352: * Mark that this cpu is now active. \
353: */ \
354: i_bit_set((my_cpu), &cpus_active); \
355: splx(s); \
356: }
357:
358: #else NCPUS > 1
359:
360: /*
361: * With only one CPU, we just have to indicate whether the pmap is
362: * in use.
363: */
364:
365: #define PMAP_ACTIVATE_KERNEL(my_cpu) { \
366: kernel_pmap->cpus_using = TRUE; \
367: }
368:
369: #define PMAP_DEACTIVATE_KERNEL(my_cpu) { \
370: kernel_pmap->cpus_using = FALSE; \
371: }
372:
373: #define PMAP_ACTIVATE_USER(pmap, th, my_cpu) { \
374: register pmap_t tpmap = (pmap); \
375: \
376: set_dirbase(kvtophys(tpmap->dirbase)); \
377: if (tpmap != kernel_pmap) { \
378: tpmap->cpus_using = TRUE; \
379: } \
380: }
381:
382: #define PMAP_DEACTIVATE_USER(pmap, thread, cpu) { \
383: if ((pmap) != kernel_pmap) \
384: (pmap)->cpus_using = FALSE; \
385: }
386:
387: #endif NCPUS > 1
388:
389: #define PMAP_CONTEXT(pmap, thread)
390:
391: #define pmap_kernel() (kernel_pmap)
392: #define pmap_resident_count(pmap) ((pmap)->stats.resident_count)
393: #define pmap_phys_address(frame) ((vm_offset_t) (intel_ptob(frame)))
394: #define pmap_phys_to_frame(phys) ((int) (intel_btop(phys)))
395: #define pmap_copy(dst_pmap,src_pmap,dst_addr,len,src_addr)
396: #define pmap_attribute(pmap,addr,size,attr,value) \
397: (KERN_INVALID_ADDRESS)
398:
399: #endif ASSEMBLER
400:
401: #endif _PMAP_MACHINE_
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.