|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1992 NeXT Computer, Inc. ! 27: * ! 28: * Intel386 Family: Private definitions for pmap. ! 29: * ! 30: * HISTORY ! 31: * ! 32: * 10 April 1992 ? at NeXT ! 33: * Created. ! 34: */ ! 35: ! 36: /* ! 37: * For each managed physical page, there is a list of all currently ! 38: * valid virtual mappings of that page. ! 39: */ ! 40: typedef struct pv_entry { ! 41: struct pv_entry * next; /* next pv_entry */ ! 42: pmap_t pmap; /* pmap where mapping lies */ ! 43: vm_offset_t va; /* virtual address for mapping */ ! 44: } pv_head_t, *pv_entry_t; ! 45: ! 46: #define PV_ENTRY_NULL ((pv_entry_t) 0) ! 47: ! 48: zone_t pv_entry_zone; /* zone of pv_entry structures */ ! 49: ! 50: /* ! 51: * First and last physical addresses that we maintain any information ! 52: * for. Initialized to zero so that pmap operations done before ! 53: * pmap_init won't touch any non-existent structures. ! 54: */ ! 55: vm_offset_t vm_first_phys = (vm_offset_t) 0; ! 56: vm_offset_t vm_last_phys = (vm_offset_t) 0; ! 57: #define managed_page(pa) \ ! 58: ((pa) >= vm_first_phys && (pa) < vm_last_phys) ! 59: boolean_t pmap_initialized = FALSE;/* Has pmap_init completed? */ ! 60: ! 61: /* ! 62: * Page descriptor - ! 63: * Maintained for each managed page. ! 64: */ ! 65: typedef struct pg_desc { ! 66: pv_head_t pv_list; /* head of pv list for page */ ! 67: struct pg_exten * pg_exten; /* page extension for page */ ! 68: unsigned int page_attrib :8, /* page attributes: */ ! 69: #define PG_DIRTY 0x01 /* page has been modified */ ! 70: #define PG_REFER 0x02 /* page has been referenced */ ! 71: :0; ! 72: } pg_desc_t; ! 73: ! 74: #define PG_DESC_NULL ((pg_desc_t *) 0) ! 75: ! 76: pg_desc_t *pg_desc_tbl; ! 77: unsigned int pg_first_phys; ! 78: ! 79: #define pg_desc(pa) \ ! 80: (&pg_desc_tbl[phys_to_pfn((unsigned int)(pa) - \ ! 81: pg_first_phys) >> (ptes_per_vm_page - 1)]) ! 82: ! 83: #define pg_desc_pvh(pd) (&(pd)->pv_list) ! 84: ! 85: /* ! 86: * Page extension - ! 87: * Contains information for pages used ! 88: * as page tables or page directories. ! 89: * NB: the 'links' field *must* be first. ! 90: */ ! 91: typedef struct pg_exten { ! 92: queue_chain_t links; /* active/free queue links */ ! 93: struct pg_desc * pg_desc; /* page descriptor for page */ ! 94: unsigned int phys; /* physical address of page */ ! 95: struct pmap * pmap; /* PT: which address map */ ! 96: vm_offset_t offset; /* PT: what offset in map */ ! 97: unsigned int alloc_count :16, /* PT: mappings, PD: pg dirs */ ! 98: wired_count :16; /* PT: wired mappings */ ! 99: unsigned int alloc_bmap :8, /* PD: alloc map */ ! 100: unrefd_age :8, /* PT: # aging ticks */ ! 101: :0; ! 102: } pg_exten_t; ! 103: ! 104: #define PG_EXTEN_NULL ((pg_exten_t *) 0) ! 105: ! 106: zone_t pg_exten_zone; ! 107: ! 108: /* ! 109: * A queue of free page tables is ! 110: * maintained which is emptied by ! 111: * pmap_update(). This strategy is ! 112: * used for two reasons. First, it is ! 113: * inconvenient to actually free the pages ! 114: * at the point in the code where it would ! 115: * be necessary. Secondly, keeping easily ! 116: * available spare page tables around makes ! 117: * pmap expansions quicker. ! 118: */ ! 119: queue_head_t pt_active_queue, pt_free_queue; ! 120: int pt_active_count, pt_free_count; ! 121: int pt_alloc_count; ! 122: ! 123: static __inline__ ! 124: void ! 125: pt_active_add( ! 126: pg_exten_t *pe ! 127: ) ! 128: { ! 129: enqueue_tail(&pt_active_queue, (queue_entry_t)pe); ! 130: pt_active_count++; ! 131: } ! 132: ! 133: static __inline__ ! 134: void ! 135: pt_active_remove( ! 136: pg_exten_t *pe ! 137: ) ! 138: { ! 139: remqueue(&pt_active_queue, (queue_entry_t)pe); ! 140: pt_active_count--; ! 141: } ! 142: ! 143: static __inline__ ! 144: pg_exten_t * ! 145: pt_free_obtain( ! 146: void ! 147: ) ! 148: { ! 149: pg_exten_t *pe; ! 150: ! 151: if (((queue_entry_t)pe = dequeue_head(&pt_free_queue))) ! 152: pt_free_count--; ! 153: ! 154: return (pe); ! 155: } ! 156: ! 157: static __inline__ ! 158: void ! 159: pt_free_add( ! 160: pg_exten_t *pe ! 161: ) ! 162: { ! 163: enqueue_tail(&pt_free_queue, (queue_entry_t)pe); ! 164: pt_free_count++; ! 165: } ! 166: ! 167: /* ! 168: * A queue of pages that contain free ! 169: * page directories is maintained. This ! 170: * is also emptied by pmap_update() (if ! 171: * possible). This added complexity is ! 172: * needed to avoid wasting memory when ! 173: * running with a large MI page size. ! 174: */ ! 175: queue_head_t pd_free_queue; ! 176: int pd_free_count; ! 177: int pd_alloc_count; ! 178: ! 179: static __inline__ ! 180: pg_exten_t * ! 181: pd_free_obtain( ! 182: void ! 183: ) ! 184: { ! 185: if (queue_empty(&pd_free_queue)) ! 186: return (0); ! 187: ! 188: return ((pg_exten_t *) queue_first(&pd_free_queue)); ! 189: } ! 190: ! 191: static __inline__ ! 192: void ! 193: pd_free_add( ! 194: pg_exten_t *pe ! 195: ) ! 196: { ! 197: enqueue_head(&pd_free_queue, (queue_entry_t)pe); ! 198: pd_free_count++; ! 199: } ! 200: ! 201: static __inline__ ! 202: void ! 203: pd_free_remove( ! 204: pg_exten_t *pe ! 205: ) ! 206: { ! 207: remqueue(&pd_free_queue, (queue_entry_t)pe); ! 208: pd_free_count--; ! 209: } ! 210: ! 211: /* ! 212: * A section is defined to be the amount ! 213: * of address space mapped by a single ! 214: * page table. ! 215: */ ! 216: ! 217: /* ! 218: * Machine dependent sections. ! 219: */ ! 220: #define I386_SECTBYTES ((I386_PGBYTES / sizeof (pt_entry_t)) * \ ! 221: I386_PGBYTES) ! 222: #define i386_round_section(x) ((((unsigned int)(x)) + I386_SECTBYTES - 1) & \ ! 223: ~(I386_SECTBYTES - 1)) ! 224: #define i386_trunc_section(x) (((unsigned int)(x)) & ~(I386_SECTBYTES - 1)) ! 225: ! 226: /* ! 227: * Machine independent sections. ! 228: */ ! 229: #define SECTION_SIZE ((PAGE_SIZE / sizeof (pt_entry_t)) * \ ! 230: I386_PGBYTES) ! 231: vm_offset_t section_size; ! 232: #define round_section(x) ((((unsigned int)(x)) + section_size - 1) & \ ! 233: ~(section_size - 1)) ! 234: #define trunc_section(x) (((unsigned int)(x)) & ~(section_size - 1)) ! 235: ! 236: /* ! 237: * Locking and TLB invalidation ! 238: */ ! 239: ! 240: /* ! 241: * Locking Protocols: ! 242: * ! 243: * There are two structures in the pmap module that need locking: ! 244: * the pmaps themselves, and the per-page pv_lists (which are locked ! 245: * by locking the pv_lock_table entry that corresponds to the pv_head ! 246: * for the list in question.) Most routines want to lock a pmap and ! 247: * then do operations in it that require pv_list locking -- however ! 248: * pmap_remove_all and pmap_copy_on_write operate on a physical page ! 249: * basis and want to do the locking in the reverse order, i.e. lock ! 250: * a pv_list and then go through all the pmaps referenced by that list. ! 251: * To protect against deadlock between these two cases, the pmap_lock ! 252: * is used. There are three different locking protocols as a result: ! 253: * ! 254: * 1. pmap operations only (pmap_extract, pmap_access, ...) Lock only ! 255: * the pmap. ! 256: * ! 257: * 2. pmap-based operations (pmap_enter, pmap_remove, ...) Get a read ! 258: * lock on the pmap_lock (shared read), then lock the pmap ! 259: * and finally the pv_lists as needed [i.e. pmap lock before ! 260: * pv_list lock.] ! 261: * ! 262: * 3. pv_list-based operations (pmap_remove_all, pmap_copy_on_write, ...) ! 263: * Get a write lock on the pmap_lock (exclusive write); this ! 264: * also guaranteees exclusive access to the pv_lists. Lock the ! 265: * pmaps as needed. ! 266: * ! 267: * At no time may any routine hold more than one pmap lock or more than ! 268: * one pv_list lock. Because interrupt level routines can allocate ! 269: * mbufs and cause pmap_enter's, the pmap_lock and the lock on the ! 270: * kernel_pmap can only be held at splvm. ! 271: * ! 272: * The dev_addr list is protected by using a write lock on the ! 273: * pmap_lock. Lookups are expected to be cheap. ! 274: */ ! 275: ! 276: #define SPLVM(spl) { spl = splvm(); } ! 277: #define SPLX(spl) { splx(spl); } ! 278: ! 279: #define PMAP_READ_LOCK(pmap, spl) SPLVM(spl) ! 280: #define PMAP_WRITE_LOCK(spl) SPLVM(spl) ! 281: #define PMAP_READ_UNLOCK(pmap, spl) SPLX(spl) ! 282: #define PMAP_WRITE_UNLOCK(spl) SPLX(spl) ! 283: #define PMAP_WRITE_TO_READ_LOCK(pmap) ! 284: ! 285: #define LOCK_PVH(index) ! 286: #define UNLOCK_PVH(index) ! 287: ! 288: #define PMAP_UPDATE_TLBS(pmap, s, e) \ ! 289: pmap_update_tlbs((pmap), (s), (e)) ! 290: ! 291: struct { ! 292: int total; ! 293: int single; ! 294: } tlb_stat; ! 295: ! 296: /* ! 297: * Kernel pmap is statically ! 298: * allocated. ! 299: */ ! 300: struct pmap kernel_pmap_store; ! 301: pmap_t kernel_pmap; ! 302: ! 303: /* ! 304: * Zone to allocate new ! 305: * pmaps from. ! 306: */ ! 307: zone_t pmap_zone; ! 308: ! 309: int ptes_per_vm_page; ! 310: ! 311: static void pmap_expand( ! 312: pmap_t pmap, ! 313: vm_offset_t va); ! 314: static void pmap_allocate_mapping( ! 315: pmap_t pmap, ! 316: vm_offset_t va, ! 317: boolean_t wired); ! 318: static void pmap_deallocate_mappings( ! 319: pmap_t pmap, ! 320: vm_offset_t va, ! 321: int count, ! 322: int unwire_count, ! 323: boolean_t free_table); ! 324: static void pmap_wire_mapping( ! 325: pmap_t pmap, ! 326: vm_offset_t va); ! 327: static void pmap_unwire_mapping( ! 328: pmap_t pmap, ! 329: vm_offset_t va); ! 330: static void pmap_remove_range( ! 331: pmap_t pmap, ! 332: vm_offset_t start, ! 333: vm_offset_t end, ! 334: boolean_t free_table); ! 335: static void pmap_clear_page_attrib( ! 336: vm_offset_t pa, ! 337: int attrib); ! 338: static boolean_t pmap_check_page_attrib( ! 339: vm_offset_t pa, ! 340: int attrib);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.