|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: */ ! 52: ! 53: /* ! 54: * File: pmap.h ! 55: * ! 56: * Authors: Avadis Tevanian, Jr., Michael Wayne Young ! 57: * Date: 1985 ! 58: * ! 59: * Machine-dependent structures for the physical map module. ! 60: */ ! 61: ! 62: #ifndef _PMAP_MACHINE_ ! 63: #define _PMAP_MACHINE_ 1 ! 64: ! 65: #ifndef ASSEMBLER ! 66: ! 67: #include <platforms.h> ! 68: #include <mp_v1_1.h> ! 69: ! 70: #include <mach/kern_return.h> ! 71: #include <mach/machine/vm_types.h> ! 72: #include <mach/vm_prot.h> ! 73: #include <mach/vm_statistics.h> ! 74: #include <mach/machine/vm_param.h> ! 75: #include <kern/kern_types.h> ! 76: #include <kern/thread_act.h> ! 77: #include <kern/lock.h> ! 78: ! 79: /* ! 80: * Define the generic in terms of the specific ! 81: */ ! 82: ! 83: #define INTEL_PGBYTES I386_PGBYTES ! 84: #define INTEL_PGSHIFT I386_PGSHIFT ! 85: #define intel_btop(x) i386_btop(x) ! 86: #define intel_ptob(x) i386_ptob(x) ! 87: #define intel_round_page(x) i386_round_page(x) ! 88: #define intel_trunc_page(x) i386_trunc_page(x) ! 89: #define trunc_intel_to_vm(x) trunc_i386_to_vm(x) ! 90: #define round_intel_to_vm(x) round_i386_to_vm(x) ! 91: #define vm_to_intel(x) vm_to_i386(x) ! 92: ! 93: /* ! 94: * i386/i486/i860 Page Table Entry ! 95: */ ! 96: ! 97: typedef unsigned int pt_entry_t; ! 98: #define PT_ENTRY_NULL ((pt_entry_t *) 0) ! 99: ! 100: #endif /* ASSEMBLER */ ! 101: ! 102: #define INTEL_OFFMASK 0xfff /* offset within page */ ! 103: #define PDESHIFT 22 /* page descriptor shift */ ! 104: #define PDEMASK 0x3ff /* mask for page descriptor index */ ! 105: #define PTESHIFT 12 /* page table shift */ ! 106: #define PTEMASK 0x3ff /* mask for page table index */ ! 107: ! 108: /* ! 109: * Convert kernel virtual address to linear address ! 110: */ ! 111: ! 112: #define kvtolinear(a) ((a)+LINEAR_KERNEL_ADDRESS) ! 113: ! 114: /* ! 115: * Convert address offset to page descriptor index ! 116: */ ! 117: #define pdenum(pmap, a) (((((pmap) == kernel_pmap) ? \ ! 118: kvtolinear(a) : (a)) \ ! 119: >> PDESHIFT) & PDEMASK) ! 120: ! 121: /* ! 122: * Convert page descriptor index to user virtual address ! 123: */ ! 124: #define pdetova(a) ((vm_offset_t)(a) << PDESHIFT) ! 125: ! 126: /* ! 127: * Convert address offset to page table index ! 128: */ ! 129: #define ptenum(a) (((a) >> PTESHIFT) & PTEMASK) ! 130: ! 131: #define NPTES (intel_ptob(1)/sizeof(pt_entry_t)) ! 132: #define NPDES (intel_ptob(1)/sizeof(pt_entry_t)) ! 133: ! 134: /* ! 135: * Hardware pte bit definitions (to be used directly on the ptes ! 136: * without using the bit fields). ! 137: */ ! 138: ! 139: #define INTEL_PTE_VALID 0x00000001 ! 140: #define INTEL_PTE_WRITE 0x00000002 ! 141: #define INTEL_PTE_USER 0x00000004 ! 142: #define INTEL_PTE_WTHRU 0x00000008 ! 143: #define INTEL_PTE_NCACHE 0x00000010 ! 144: #define INTEL_PTE_REF 0x00000020 ! 145: #define INTEL_PTE_MOD 0x00000040 ! 146: #define INTEL_PTE_WIRED 0x00000200 ! 147: #define INTEL_PTE_PFN 0xfffff000 ! 148: ! 149: #define pa_to_pte(a) ((a) & INTEL_PTE_PFN) ! 150: #define pte_to_pa(p) ((p) & INTEL_PTE_PFN) ! 151: #define pte_increment_pa(p) ((p) += INTEL_OFFMASK+1) ! 152: ! 153: /* ! 154: * Convert page table entry to kernel virtual address ! 155: */ ! 156: #define ptetokv(a) (phystokv(pte_to_pa(a))) ! 157: ! 158: #ifndef ASSEMBLER ! 159: typedef volatile long cpu_set; /* set of CPUs - must be <= 32 */ ! 160: /* changed by other processors */ ! 161: ! 162: struct pmap { ! 163: pt_entry_t *dirbase; /* page directory pointer register */ ! 164: vm_offset_t pdirbase; /* phys. address of dirbase */ ! 165: int ref_count; /* reference count */ ! 166: decl_simple_lock_data(,lock) /* lock on map */ ! 167: struct pmap_statistics stats; /* map statistics */ ! 168: cpu_set cpus_using; /* bitmap of cpus using pmap */ ! 169: }; ! 170: ! 171: /* ! 172: * Optimization avoiding some TLB flushes when switching to ! 173: * kernel-loaded threads. This is effective only for i386: ! 174: * Since user task, kernel task and kernel loaded tasks share the ! 175: * same virtual space (with appropriate protections), any pmap ! 176: * allows mapping kernel and kernel loaded tasks. ! 177: * ! 178: * The idea is to avoid switching to another pmap unnecessarily when ! 179: * switching to a kernel-loaded task, or when switching to the kernel ! 180: * itself. ! 181: * ! 182: * We store the pmap we are really using (from which we fetched the ! 183: * dirbase value) in real_pmap[cpu_number()]. ! 184: * ! 185: * Invariant: ! 186: * current_pmap() == real_pmap[cpu_number()] || current_pmap() == kernel_pmap. ! 187: */ ! 188: ! 189: extern struct pmap *real_pmap[NCPUS]; ! 190: ! 191: #include <i386/proc_reg.h> ! 192: /* ! 193: * If switching to the kernel pmap, don't incur the TLB cost of switching ! 194: * to its page tables, since all maps include the kernel map as a subset. ! 195: * Simply record that this CPU is logically on the kernel pmap (see ! 196: * pmap_destroy). ! 197: * ! 198: * Similarly, if switching to a pmap (other than kernel_pmap that is already ! 199: * in use, don't do anything to the hardware, to avoid a TLB flush. ! 200: */ ! 201: ! 202: #if NCPUS > 1 ! 203: #define PMAP_CPU_SET(pmap, my_cpu) i_bit_set(my_cpu, &((pmap)->cpus_using)) ! 204: #define PMAP_CPU_CLR(pmap, my_cpu) i_bit_clear(my_cpu, &((pmap)->cpus_using)) ! 205: #else /* NCPUS > 1 */ ! 206: #define PMAP_CPU_SET(pmap,my_cpu) (pmap)->cpus_using = TRUE ! 207: #define PMAP_CPU_CLR(pmap,my_cpu) (pmap)->cpus_using = FALSE ! 208: #endif /* NCPUS > 1 */ ! 209: ! 210: ! 211: #define set_dirbase(mypmap, my_cpu) { \ ! 212: struct pmap **ppmap = &real_pmap[my_cpu]; \ ! 213: vm_offset_t pdirbase = (mypmap)->pdirbase; \ ! 214: \ ! 215: if (*ppmap == (vm_offset_t)NULL) { \ ! 216: *ppmap = (mypmap); \ ! 217: PMAP_CPU_SET((mypmap), my_cpu); \ ! 218: set_cr3(pdirbase); \ ! 219: } else if ((mypmap) != kernel_pmap && (mypmap) != *ppmap ) { \ ! 220: if (*ppmap != kernel_pmap) \ ! 221: PMAP_CPU_CLR(*ppmap, my_cpu); \ ! 222: *ppmap = (mypmap); \ ! 223: PMAP_CPU_SET((mypmap), my_cpu); \ ! 224: set_cr3(pdirbase); \ ! 225: } \ ! 226: assert((mypmap) == *ppmap || (mypmap) == kernel_pmap); \ ! 227: } ! 228: ! 229: #if NCPUS > 1 ! 230: /* ! 231: * List of cpus that are actively using mapped memory. Any ! 232: * pmap update operation must wait for all cpus in this list. ! 233: * Update operations must still be queued to cpus not in this ! 234: * list. ! 235: */ ! 236: extern cpu_set cpus_active; ! 237: ! 238: /* ! 239: * List of cpus that are idle, but still operating, and will want ! 240: * to see any kernel pmap updates when they become active. ! 241: */ ! 242: extern cpu_set cpus_idle; ! 243: ! 244: ! 245: /* ! 246: * External declarations for PMAP_ACTIVATE. ! 247: */ ! 248: ! 249: extern void process_pmap_updates(struct pmap *pmap); ! 250: extern void pmap_update_interrupt(void); ! 251: ! 252: #endif /* NCPUS > 1 */ ! 253: ! 254: /* ! 255: * Machine dependent routines that are used only for i386/i486/i860. ! 256: */ ! 257: extern vm_offset_t (phystokv)( ! 258: vm_offset_t pa); ! 259: ! 260: extern vm_offset_t (kvtophys)( ! 261: vm_offset_t addr); ! 262: ! 263: extern pt_entry_t *pmap_pte( ! 264: struct pmap *pmap, ! 265: vm_offset_t addr); ! 266: ! 267: extern vm_offset_t pmap_map( ! 268: vm_offset_t virt, ! 269: vm_offset_t start, ! 270: vm_offset_t end, ! 271: vm_prot_t prot); ! 272: ! 273: extern vm_offset_t pmap_map_bd( ! 274: vm_offset_t virt, ! 275: vm_offset_t start, ! 276: vm_offset_t end, ! 277: vm_prot_t prot); ! 278: ! 279: extern void pmap_bootstrap( ! 280: vm_offset_t load_start); ! 281: ! 282: extern boolean_t pmap_valid_page( ! 283: vm_offset_t pa); ! 284: ! 285: extern int pmap_list_resident_pages( ! 286: struct pmap *pmap, ! 287: vm_offset_t *listp, ! 288: int space); ! 289: ! 290: extern void flush_tlb(void); ! 291: ! 292: /* ! 293: * Macros for speed. ! 294: */ ! 295: ! 296: #if NCPUS > 1 ! 297: ! 298: #include <kern/spl.h> ! 299: ! 300: /* ! 301: * For multiple CPUS, PMAP_ACTIVATE and PMAP_DEACTIVATE must manage ! 302: * fields to control TLB invalidation on other CPUS. ! 303: */ ! 304: ! 305: #define PMAP_ACTIVATE_KERNEL(my_cpu) { \ ! 306: \ ! 307: /* \ ! 308: * Let pmap updates proceed while we wait for this pmap. \ ! 309: */ \ ! 310: i_bit_clear((my_cpu), &cpus_active); \ ! 311: \ ! 312: /* \ ! 313: * Lock the pmap to put this cpu in its active set. \ ! 314: * Wait for updates here. \ ! 315: */ \ ! 316: simple_lock(&kernel_pmap->lock); \ ! 317: \ ! 318: /* \ ! 319: * Mark that this cpu is using the pmap. \ ! 320: */ \ ! 321: i_bit_set((my_cpu), &kernel_pmap->cpus_using); \ ! 322: \ ! 323: /* \ ! 324: * Mark this cpu active - IPL will be lowered by \ ! 325: * load_context(). \ ! 326: */ \ ! 327: i_bit_set((my_cpu), &cpus_active); \ ! 328: \ ! 329: simple_unlock(&kernel_pmap->lock); \ ! 330: } ! 331: ! 332: #define PMAP_DEACTIVATE_KERNEL(my_cpu) { \ ! 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), &kernel_pmap->cpus_using); \ ! 338: } ! 339: ! 340: #define PMAP_ACTIVATE_MAP(map, my_cpu) { \ ! 341: register struct pmap *tpmap; \ ! 342: \ ! 343: tpmap = vm_map_pmap(map); \ ! 344: if (tpmap == kernel_pmap) { \ ! 345: /* \ ! 346: * If this is the kernel pmap, switch to its page tables. \ ! 347: */ \ ! 348: set_dirbase(kernel_pmap, my_cpu); \ ! 349: } \ ! 350: else { \ ! 351: /* \ ! 352: * Let pmap updates proceed while we wait for this pmap. \ ! 353: */ \ ! 354: i_bit_clear((my_cpu), &cpus_active); \ ! 355: \ ! 356: /* \ ! 357: * Lock the pmap to put this cpu in its active set. \ ! 358: * Wait for updates here. \ ! 359: */ \ ! 360: simple_lock(&tpmap->lock); \ ! 361: \ ! 362: /* \ ! 363: * No need to invalidate the TLB - the entire user pmap \ ! 364: * will be invalidated by reloading dirbase. \ ! 365: */ \ ! 366: set_dirbase(tpmap, my_cpu); \ ! 367: \ ! 368: /* \ ! 369: * Mark this cpu active - IPL will be lowered by \ ! 370: * load_context(). \ ! 371: */ \ ! 372: i_bit_set((my_cpu), &cpus_active); \ ! 373: \ ! 374: simple_unlock(&tpmap->lock); \ ! 375: } \ ! 376: } ! 377: ! 378: #define PMAP_DEACTIVATE_MAP(map, my_cpu) ! 379: ! 380: #define PMAP_ACTIVATE_USER(th, my_cpu) { \ ! 381: spl_t spl; \ ! 382: \ ! 383: spl = splhigh(); \ ! 384: PMAP_ACTIVATE_MAP(th->map, my_cpu) \ ! 385: splx(spl); \ ! 386: } ! 387: ! 388: #define PMAP_DEACTIVATE_USER(th, my_cpu) { \ ! 389: spl_t spl; \ ! 390: \ ! 391: spl = splhigh(); \ ! 392: PMAP_DEACTIVATE_MAP(th->map, my_cpu) \ ! 393: splx(spl); \ ! 394: } ! 395: ! 396: #define PMAP_SWITCH_CONTEXT(old_th, new_th, my_cpu) { \ ! 397: spl_t spl; \ ! 398: \ ! 399: if (old_th->map != new_th->map) { \ ! 400: spl = splhigh(); \ ! 401: PMAP_DEACTIVATE_MAP(old_th->map, my_cpu); \ ! 402: PMAP_ACTIVATE_MAP(new_th->map, my_cpu); \ ! 403: splx(spl); \ ! 404: } \ ! 405: } ! 406: ! 407: #define PMAP_SWITCH_USER(th, new_map, my_cpu) { \ ! 408: spl_t spl; \ ! 409: \ ! 410: spl = splhigh(); \ ! 411: PMAP_DEACTIVATE_MAP(th->map, my_cpu); \ ! 412: th->map = new_map; \ ! 413: PMAP_ACTIVATE_MAP(th->map, my_cpu); \ ! 414: splx(spl); \ ! 415: } ! 416: ! 417: #if MP_V1_1 ! 418: #define set_led(cpu) ! 419: #define clear_led(cpu) ! 420: #endif /* MP_V1_1 */ ! 421: ! 422: #define MARK_CPU_IDLE(my_cpu) { \ ! 423: /* \ ! 424: * Mark this cpu idle, and remove it from the active set, \ ! 425: * since it is not actively using any pmap. Signal_cpus \ ! 426: * will notice that it is idle, and avoid signaling it, \ ! 427: * but will queue the update request for when the cpu \ ! 428: * becomes active. \ ! 429: */ \ ! 430: int s = splhigh(); \ ! 431: i_bit_set((my_cpu), &cpus_idle); \ ! 432: i_bit_clear((my_cpu), &cpus_active); \ ! 433: splx(s); \ ! 434: set_led(my_cpu); \ ! 435: } ! 436: ! 437: #define MARK_CPU_ACTIVE(my_cpu) { \ ! 438: \ ! 439: int s = splhigh(); \ ! 440: /* \ ! 441: * If a kernel_pmap update was requested while this cpu \ ! 442: * was idle, process it as if we got the interrupt. \ ! 443: * Before doing so, remove this cpu from the idle set. \ ! 444: * Since we do not grab any pmap locks while we flush \ ! 445: * our TLB, another cpu may start an update operation \ ! 446: * before we finish. Removing this cpu from the idle \ ! 447: * set assures that we will receive another update \ ! 448: * interrupt if this happens. \ ! 449: */ \ ! 450: i_bit_clear((my_cpu), &cpus_idle); \ ! 451: \ ! 452: /* \ ! 453: * Mark that this cpu is now active. \ ! 454: */ \ ! 455: i_bit_set((my_cpu), &cpus_active); \ ! 456: splx(s); \ ! 457: clear_led(my_cpu); \ ! 458: } ! 459: ! 460: #else /* NCPUS > 1 */ ! 461: ! 462: /* ! 463: * With only one CPU, we just have to indicate whether the pmap is ! 464: * in use. ! 465: */ ! 466: ! 467: #define PMAP_ACTIVATE_KERNEL(my_cpu) { \ ! 468: kernel_pmap->cpus_using = TRUE; \ ! 469: } ! 470: ! 471: #define PMAP_DEACTIVATE_KERNEL(my_cpu) { \ ! 472: kernel_pmap->cpus_using = FALSE; \ ! 473: } ! 474: ! 475: #define PMAP_ACTIVATE_MAP(map, my_cpu) \ ! 476: set_dirbase(vm_map_pmap(map), my_cpu) ! 477: ! 478: #define PMAP_DEACTIVATE_MAP(map, my_cpu) ! 479: ! 480: #define PMAP_ACTIVATE_USER(th, my_cpu) \ ! 481: PMAP_ACTIVATE_MAP(th->map, my_cpu) ! 482: ! 483: #define PMAP_DEACTIVATE_USER(th, my_cpu) \ ! 484: PMAP_DEACTIVATE_MAP(th->map, my_cpu) ! 485: ! 486: #define PMAP_SWITCH_CONTEXT(old_th, new_th, my_cpu) { \ ! 487: if (old_th->map != new_th->map) { \ ! 488: PMAP_DEACTIVATE_MAP(old_th->map, my_cpu); \ ! 489: PMAP_ACTIVATE_MAP(new_th->map, my_cpu); \ ! 490: } \ ! 491: } ! 492: ! 493: #define PMAP_SWITCH_USER(th, new_map, my_cpu) { \ ! 494: PMAP_DEACTIVATE_MAP(th->map, my_cpu); \ ! 495: th->map = new_map; \ ! 496: PMAP_ACTIVATE_MAP(th->map, my_cpu); \ ! 497: } ! 498: ! 499: #endif /* NCPUS > 1 */ ! 500: ! 501: #define PMAP_CONTEXT(pmap, thread) ! 502: ! 503: #define pmap_kernel_va(VA) \ ! 504: (((VA) >= VM_MIN_KERNEL_ADDRESS) && ((VA) <= VM_MAX_KERNEL_ADDRESS)) ! 505: ! 506: #define pmap_resident_count(pmap) ((pmap)->stats.resident_count) ! 507: #define pmap_phys_address(frame) ((vm_offset_t) (intel_ptob(frame))) ! 508: #define pmap_phys_to_frame(phys) ((int) (intel_btop(phys))) ! 509: #define pmap_copy(dst_pmap,src_pmap,dst_addr,len,src_addr) ! 510: #define pmap_attribute(pmap,addr,size,attr,value) \ ! 511: (KERN_INVALID_ADDRESS) ! 512: #endif /* ASSEMBLER */ ! 513: ! 514: #endif /* _PMAP_MACHINE_ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.