|
|
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: * This file is used to maintain the virtual to real mappings for a PowerPC machine. ! 24: * The code herein is primarily used to bridge between the pmap layer and the hardware layer. ! 25: * Currently, some of the function of this module is contained within pmap.c. We may want to move ! 26: * all of this into it (or most anyway) for the sake of performance. We shall see as we write it. ! 27: * ! 28: * We also depend upon the structure of the phys_entry control block. We do put some processor ! 29: * specific stuff in there. ! 30: * ! 31: */ ! 32: ! 33: #include <cpus.h> ! 34: #include <debug.h> ! 35: #include <mach_kgdb.h> ! 36: #include <mach_vm_debug.h> ! 37: #include <db_machine_commands.h> ! 38: ! 39: #include <kern/thread.h> ! 40: #include <kern/thread_act.h> ! 41: #include <mach/vm_attributes.h> ! 42: #include <mach/vm_param.h> ! 43: #include <vm/vm_kern.h> ! 44: #include <vm/vm_map.h> ! 45: #include <vm/vm_page.h> ! 46: #include <kern/spl.h> ! 47: ! 48: #include <kern/misc_protos.h> ! 49: #include <ppc/misc_protos.h> ! 50: #include <ppc/proc_reg.h> ! 51: ! 52: #include <vm/pmap.h> ! 53: #include <ppc/pmap.h> ! 54: #include <ppc/pmap_internals.h> ! 55: #include <ppc/mem.h> ! 56: ! 57: #include <ppc/new_screen.h> ! 58: #include <ppc/Firmware.h> ! 59: #include <ppc/mappings.h> ! 60: #include <ppc/miscserv.h> ! 61: #include <ddb/db_output.h> ! 62: ! 63: #define PERFTIMES 0 ! 64: ! 65: #if PERFTIMES && DEBUG ! 66: #define debugLog2(a, b, c) dbgLog2(a, b, c) ! 67: #else ! 68: #define debugLog2(a, b, c) ! 69: #endif ! 70: ! 71: autogenblok *AutoGenList; /* Anchor for the autogeb list */ ! 72: space_t curr_spaceID = 0; /* Highest used space ID */ ! 73: unsigned int incrVSID = 0; /* VSID increment value */ ! 74: unsigned int mappingdeb0 = 0; ! 75: extern unsigned int hash_table_size; ! 76: extern unsigned int debsave0; ! 77: extern unsigned int dbdbdb; /* (TEST/DEBUG) */ ! 78: extern vm_offset_t mem_size; ! 79: /* ! 80: * ppc_prot translates from the mach representation of protections to the PPC version. ! 81: * Calculation of it like this saves a memory reference - and maybe a couple of microseconds. ! 82: * It eliminates the used of this table. ! 83: * unsigned char ppc_prot[8] = { 0, 3, 2, 2, 3, 3, 2, 2 }; ! 84: */ ! 85: ! 86: #define ppc_prot(p) ((0xAFAC >> (p << 1)) & 3) ! 87: ! 88: /* ! 89: * mapping_space(); ! 90: * This function is called to generate an address space ID. This space ID must be unique within ! 91: * the system. For the PowerPC, it is used to build the VSID. We build a VSID in the following ! 92: * way: space ID << 4 | segment. Since a VSID is 24 bits, and out of that, we reserve the last ! 93: * 4, so, we can have 2^20 (2M) unique IDs. Each pmap has a unique space ID, so we should be able ! 94: * to have 2M pmaps at a time, which we couldn't, we'd run out of memory way before then. The ! 95: * problem is that only a certain number of pmaps are kept in a free list and if that is full, ! 96: * they are release. This causes us to lose track of what space IDs are free to be reused. ! 97: * We can do 4 things: 1) not worry about it, 2) keep all free pmaps, 3) rebuild all mappings ! 98: * when the space ID wraps, or 4) scan the list of pmaps and find a free one. ! 99: * ! 100: * Yet another consideration is the hardware use of the VSID. It is used as part of the hash ! 101: * calculation for virtual address lookup. An improperly chosen value could potentially cause ! 102: * too many hashes to hit the same bucket, causing PTEG overflows. The actual hash function ! 103: * is (page index XOR vsid) mod number of ptegs. For a 32MB machine, using the suggested ! 104: * hash table size, there are 2^12 (8192) PTEGs. Remember, though, that the bottom 4 bits ! 105: * are reserved for the segment number, which means that we really have 2^(12-4) 512 space IDs ! 106: * before we start hashing to the same buckets with the same vaddrs. Also, within a space ID, ! 107: * every 8192 pages (32MB) within a segment will hash to the same bucket. That's 8 collisions ! 108: * per segment. So, a scan of every page for 256MB would fill 32 PTEGs completely, but ! 109: * with no overflow. I don't think that this is a problem. ! 110: * ! 111: * There may be a problem with the space ID, though. A new space ID is generate (mainly) ! 112: * whenever there is a fork. There shouldn't really be any problem because (for a 32MB ! 113: * machine) we can have 512 pmaps and still not have hash collisions for the same address. ! 114: * The potential problem, though, is if we get long-term pmaps that have space IDs that are ! 115: * the same modulo 512. We can reduce this problem by having the segment number be bits ! 116: * 0-3 of the space ID rather than 20-23. Doing this means that, in effect, corresponding ! 117: * vaddrs in different segments hash to the same PTEG. While this is somewhat of a problem, ! 118: * I don't think that it is as signifigant as the other, so, I'll make the space ID ! 119: * with segment first. ! 120: * ! 121: * The final, and biggest problem is the wrap, which will happen every 2^20 space IDs. ! 122: * While this is a problem that should only happen in periods counted in weeks, it can and ! 123: * will happen. This is assuming a monotonically increasing space ID. If we were to search ! 124: * for an inactive space ID, there could not be a wrap until there was 2^20 concurrent space IDs. ! 125: * That's pretty unlikely to happen. There couldn't be enough storage to support a million tasks. ! 126: * Another potential solution is to monitor for the wrap, and reorganize the space IDs when it happens. ! 127: * This is rather severe, and would have user-perceivable performance impact. It would be necessary ! 128: * to quiese all other processors, invalidate and purge the entire hash table, and then to reassign ! 129: * all space IDs in active pmaps. It may be better to amortize the problem by keeping pmaps in sorted ! 130: * order and keeping track of the lowest unused space ID. I'll think on this one and do a panic ! 131: * until I got it sussed. ! 132: */ ! 133: ! 134: space_t mapping_space(void) { /* Generate a unique space ID */ ! 135: ! 136: register space_t currSID, nextSID; ! 137: ! 138: while(1) { /* Keep trying until something happens */ ! 139: currSID=curr_spaceID; /* Get a copy of the current ID */ ! 140: if(!(nextSID = ((currSID + incrVSID) & SID_MAX))) { /* Get the next one and check if we wrapped */ ! 141: panic("Address space ID wrapped; Temporarily fatal system error. Add more code here...\n"); /* Die */ ! 142: } ! 143: if(hw_compare_and_store(currSID, nextSID, &curr_spaceID)) { /* Have we found a good one yet? */ ! 144: debugLog2(0, nextSID, 0); /* Log mapping_space call */ ! 145: return (nextSID); /* Yeah, return it... */ ! 146: } /* save the new and exit if not, */ ! 147: } ! 148: } ! 149: ! 150: ! 151: /* ! 152: * mapping_init(); ! 153: * Do anything that needs to be done before the mapping system can be used. ! 154: * Hash table must be initialized before we call this. ! 155: * ! 156: * Calculate the SID increment. Currently we use size^(1/2) + size^(1/4) + 1; ! 157: */ ! 158: ! 159: void mapping_init(void) { ! 160: ! 161: unsigned int tmp; ! 162: ! 163: __asm__ volatile("cntlzw %0, %1" : "=r" (tmp) : "r" (hash_table_size)); /* Get number of leading 0s */ ! 164: ! 165: incrVSID = 1 << ((32 - tmp + 1) >> 1); /* Get ceiling of sqrt of table size */ ! 166: incrVSID |= 1 << ((32 - tmp + 1) >> 2); /* Get ceiling of quadroot of table size */ ! 167: incrVSID |= 1; /* Set bit and add 1 */ ! 168: return; ! 169: ! 170: } ! 171: ! 172: ! 173: /* ! 174: * mapping_remove(space_t space, vm_offset_t va); ! 175: * Given a space ID and virtual address, this routine finds the mapping and removes if from ! 176: * both its PTEG hash list and the physical entry list. The mapping block will be added to ! 177: * the free list. If the free list threshold is reached, garbage collection will happen. ! 178: * We also kick back a return code to say whether or not we had one to remove. ! 179: * ! 180: * We have a strict ordering here: the mapping must be removed from the PTEG hash list before ! 181: * it can be removed from the physical entry list. This allows us to get by with only the PTEG ! 182: * hash lock at page fault time. The physical entry lock must be held while we remove the mapping ! 183: * from both lists. The PTEG lock is one of the lowest level locks. No PTE fault, interruptions, ! 184: * losing control, getting other locks, etc., are allowed when you hold it. You do, and you die. ! 185: * It's just that simple! ! 186: * ! 187: * When the phys_entry lock is held, the mappings chained to that one are guaranteed to stay around. ! 188: * However, a mapping's order on the PTEG hash chain is not. The interrupt handler uses the PTEG ! 189: * lock to control the hash cahin and may move the position of the mapping for MRU calculations. ! 190: * ! 191: * Note that mappings do not need to point to a physical entry. When they don't, it indicates ! 192: * the mapping is outside of physical memory and usually refers to a memory mapped device of ! 193: * some sort. Naturally, we can't lock what we don't have, so the phys entry lock and unlock ! 194: * routines return normally, but don't do anything. ! 195: */ ! 196: ! 197: boolean_t mapping_remove(space_t space, vm_offset_t va) { /* Remove a single mapping for this VADDR ! 198: Returns TRUE if a mapping was found to remove */ ! 199: ! 200: mapping *mp, *mpv; ! 201: spl_t s; ! 202: ! 203: debugLog2(1, va, space); /* start mapping_remove */ ! 204: s=splhigh(); /* Don't bother me */ ! 205: ! 206: mp = hw_lock_phys_vir(space, va); /* Lock the physical entry for this mapping */ ! 207: ! 208: if(!mp) { /* Did we find one? */ ! 209: splx(s); /* Restore the interrupt level */ ! 210: debugLog2(2, 0, 0); /* end mapping_remove */ ! 211: return FALSE; /* Didn't find any, return FALSE... */ ! 212: } ! 213: if((unsigned int)mp&1) { /* Did we timeout? */ ! 214: panic("mapping_remove: timeout locking physical entry\n"); /* Yeah, scream about it! */ ! 215: splx(s); /* Restore the interrupt level */ ! 216: return FALSE; /* Bad hair day, return FALSE... */ ! 217: } ! 218: ! 219: mpv = hw_cpv(mp); /* Get virtual address of mapping */ ! 220: if(mpv->pmap) { /* Check for a pmap */ ! 221: #if DEBUG ! 222: if(hw_atomic_sub(&mpv->pmap->stats.resident_count, 1) < 0) panic("pmap resident count went negative\n"); ! 223: #else ! 224: (void)hw_atomic_sub(&mpv->pmap->stats.resident_count, 1); /* Decrement the resident page count */ ! 225: #endif ! 226: } ! 227: ! 228: hw_rem_map(mp); /* Remove the corresponding mapping */ ! 229: ! 230: if(mpv->physent)hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK); /* Unlock physical entry associated with mapping */ ! 231: ! 232: splx(s); /* Was there something you needed? */ ! 233: ! 234: mapping_free(mpv); /* Add mapping to the free list */ ! 235: debugLog2(2, 1, 0); /* end mapping_remove */ ! 236: return TRUE; /* Tell them we did it */ ! 237: } ! 238: ! 239: /* ! 240: * mapping_purge(struct phys_entry *pp) - release all mappings for this physent to the free list ! 241: * ! 242: * This guy releases any mappings that exist for a physical page. ! 243: * We get the lock on the phys_entry, and hold it through out this whole routine. ! 244: * That way, no one can change the queue out from underneath us. We keep fetching ! 245: * the physents mapping anchor until it is null, then we're done. ! 246: * ! 247: * For each mapping, we call the remove routine to remove it from the PTEG hash list and ! 248: * decriment the pmap's residency count. Then we release the mapping back to the free list. ! 249: * ! 250: */ ! 251: ! 252: void mapping_purge(struct phys_entry *pp) { /* Remove all mappings for this physent */ ! 253: ! 254: mapping *mp, *mpv; ! 255: spl_t s; ! 256: ! 257: s=splhigh(); /* Don't bother me */ ! 258: debugLog2(3, pp->pte1, 0); /* start mapping_purge */ ! 259: ! 260: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Lock the physical entry */ ! 261: panic("\nmapping_purge: Timeout attempting to lock physical entry at %08X: %08X %08X\n", ! 262: pp, pp->phys_link, pp->pte1); /* Complain about timeout */ ! 263: } ! 264: ! 265: while(mp = (mapping *)((unsigned int)pp->phys_link & ~PHYS_FLAGS)) { /* Keep going so long as there's another */ ! 266: ! 267: mpv = hw_cpv(mp); /* Get the virtual address */ ! 268: if(mpv->pmap) { /* See if there is a pmap to worry about */ ! 269: #if DEBUG ! 270: if(hw_atomic_sub(&mpv->pmap->stats.resident_count, 1) < 0) panic("pmap resident count went negative\n"); ! 271: #else ! 272: (void)hw_atomic_sub(&mpv->pmap->stats.resident_count, 1); /* Decrement the resident page count */ ! 273: #endif ! 274: } ! 275: ! 276: hw_rem_map(mp); /* Remove the mapping */ ! 277: mapping_free(mpv); /* Add mapping to the free list */ ! 278: } ! 279: ! 280: hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* We're done, unlock the physical entry */ ! 281: ! 282: debugLog2(4, pp->pte1, 0); /* end mapping_purge */ ! 283: splx(s); /* Was there something you needed? */ ! 284: return; /* Tell them we did it */ ! 285: } ! 286: ! 287: ! 288: /* ! 289: * mapping_make(pmap, space, pp, va, spa, prot, attr) - map a virtual address to a real one ! 290: * ! 291: * This routine takes the given parameters, builds a mapping block, and queues it into the ! 292: * correct lists. ! 293: * ! 294: * The pmap and pp parameters can be null. This allows us to make a mapping that is not ! 295: * associated with any physical page or pmap. We may need this for certain I/O areas. ! 296: * ! 297: * If the pmap is null, we don't diddle with it, i.e., the residency counts. ! 298: * If the phys_entry address is null, we neither lock or chain into it. ! 299: */ ! 300: ! 301: mapping *mapping_make(pmap_t pmap, space_t space, struct phys_entry *pp, vm_offset_t va, vm_offset_t pa, vm_prot_t prot, int attr) { /* Make an address mapping */ ! 302: ! 303: register mapping *mp, *mpv; ! 304: spl_t s; ! 305: ! 306: debugLog2(5, va, pa); /* start mapping_purge */ ! 307: mpv = mapping_alloc(); /* Get a spare mapping block */ ! 308: ! 309: mpv->pmap = pmap; /* Initialize the pmap pointer */ ! 310: mpv->physent = pp; /* Initialize the pointer to the physical entry */ ! 311: mpv->PTEr = ((unsigned int)pa & ~(PAGE_SIZE - 1)) | attr<<3 | ppc_prot(prot); /* Build the real portion of the PTE */ ! 312: mpv->PTEv = (((unsigned int)va >> 1) & 0x78000000) | (space << 7) | (((unsigned int)va >> 22) & 0x0000003F); /* Build the VSID */ ! 313: ! 314: s=splhigh(); /* Don't bother from now on */ ! 315: ! 316: mp = hw_cvp(mpv); /* Get the physical address of this */ ! 317: ! 318: if(pp) { /* Is there a physical entry? */ ! 319: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Lock the physical entry */ ! 320: panic("\nmapping_make: Timeout attempting to lock physical entry at %08X: %08X %08X\n", ! 321: pp, pp->phys_link, pp->pte1); /* Complain about timeout */ ! 322: } ! 323: ! 324: mpv->next = (mapping *)((unsigned int)pp->phys_link & ~PHYS_FLAGS); /* Move the old anchor to the new mappings forward */ ! 325: pp->phys_link = (mapping *)((unsigned int)mp | (unsigned int)pp->phys_link & PHYS_FLAGS); /* Point the anchor at us. Now we're on the list (keep the flags) */ ! 326: } ! 327: ! 328: hw_add_map(mp, space, va); /* Stick it on the PTEG hash list */ ! 329: ! 330: if(pmap) { /* If there is a pmap, adjust the residency count */ ! 331: (void)hw_atomic_add(&mpv->pmap->stats.resident_count, 1); /* Increment the resident page count */ ! 332: } ! 333: ! 334: if(pp)hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* If we have one, unlock the physical entry */ ! 335: ! 336: splx(s); /* Ok for interruptions now */ ! 337: debugLog2(6, space, prot); /* end mapping_purge */ ! 338: return mpv; /* Leave... */ ! 339: } ! 340: ! 341: ! 342: /* ! 343: * mapping_remap(space_t space, vm_offset_t from, vm_offset_t to) - remap a physical address to a different virtual address ! 344: * ! 345: * This routine takes the given parameters, finds the mapping for the "from" address ! 346: * and removes it. Then it modifies the virtual address and adds it back. ! 347: * ! 348: * It returns failure if the "from" address is not mapped. ! 349: */ ! 350: ! 351: int mapping_remap(space_t space, vm_offset_t from, vm_offset_t to) { /* Remap an address mapping */ ! 352: ! 353: register mapping *mp, *mpv; ! 354: spl_t s; ! 355: ! 356: s=splhigh(); /* Don't bother from now on */ ! 357: ! 358: mp = hw_lock_phys_vir(space, from); /* Lock the physical entry for this mapping */ ! 359: debugLog2(7, from, to); /* start remap */ ! 360: if(!mp) { /* Did we find one? */ ! 361: splx(s); /* Restore the interrupt level */ ! 362: return FALSE; /* Didn't find source, return FALSE... */ ! 363: } ! 364: if((unsigned int)mp&1) { /* Did we timeout? */ ! 365: panic("mapping_remap: timeout locking physical entry\n"); /* Yeah, scream about it! */ ! 366: splx(s); /* Restore the interrupt level */ ! 367: return FALSE; /* Bad hair day, return FALSE... */ ! 368: } ! 369: ! 370: hw_rem_map(mp); /* Remove from the old address. Removes from both PTEG and physent lists */ ! 371: ! 372: mpv = hw_cpv(mp); /* Convert to virtual address */ ! 373: ! 374: mpv->PTEv = (((unsigned int)to >> 1) & 0x78000000) | ! 375: (space << 7) | (((unsigned int)to >> 22) & 0x0000003F); /* Rebuild the VSID */ ! 376: ! 377: if(mpv->physent) { /* Is there a physical entry? */ ! 378: mpv->next = (mapping *)((unsigned int)mpv->physent->phys_link & ~PHYS_FLAGS); /* Move the old anchor to the new mappings forward */ ! 379: mpv->physent->phys_link = (mapping *)((unsigned int)mp | ((unsigned int)mpv->physent->phys_link & PHYS_FLAGS)); /* Point the anchor at us. Now we're back on the list (keep the flags) */ ! 380: } ! 381: ! 382: hw_add_map(mp, space, to); /* Map it to the new one */ ! 383: ! 384: if(mp->physent)hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK); /* Unlock physical entry associated with mapping */ ! 385: ! 386: debugLog2(8, space, 0); /* end remap */ ! 387: splx(s); /* Ok for interruptions now */ ! 388: return TRUE; /* Leave... */ ! 389: } ! 390: ! 391: ! 392: /* ! 393: * void mapping_protect(phys_entry *pp, vm_prot_t prot, boolean_t locked) - change the protection of a physical page ! 394: * ! 395: * This routine takes a physical entry and runs through all mappings attached to it and changes ! 396: * the protection. If there are PTEs associated with the mappings, they will be invalidated before ! 397: * the protection is changed. We don't try to save the PTE. We won't worry about the LRU calculations ! 398: * either (I don't think, maybe I'll change my mind later). There is no limitation on changes, e.g., ! 399: * higher to lower, lower to higher. ! 400: * ! 401: * If locked is true, the physent is already locked and should not be unlocked at exit. ! 402: * ! 403: * Interruptions should be disabled at entry. ! 404: */ ! 405: ! 406: void mapping_protect(struct phys_entry *pp, vm_prot_t prot, boolean_t locked) { /* Change protection of all mappings to page */ ! 407: ! 408: debugLog2(9, pp->pte1, prot); /* end remap */ ! 409: if(!locked) { /* Do we need to lock the physent? */ ! 410: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Lock the physical entry */ ! 411: panic("\nmapping_protect: Timeout attempting to lock physical entry at %08X: %08X %08X\n", ! 412: pp, pp->phys_link, pp->pte1); /* Complain about timeout */ ! 413: } ! 414: } ! 415: ! 416: hw_prot(pp, ppc_prot(prot)); /* Go set the protection on this physical page */ ! 417: ! 418: if(!locked) hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* We're done, unlock the physical entry */ ! 419: debugLog2(10, pp->pte1, 0); /* end remap */ ! 420: ! 421: return; /* Leave... */ ! 422: } ! 423: ! 424: /* ! 425: * mapping_phys_attr(struct phys_entry *pp, vm_prot_t prot, unsigned int wimg) Sets the default physical page attributes ! 426: * ! 427: * This routine takes a physical entry and sets the physical attributes. There can be no mappings ! 428: * associated with this page when we do it. ! 429: */ ! 430: ! 431: void mapping_phys_attr(struct phys_entry *pp, vm_prot_t prot, unsigned int wimg) { /* Sets the default physical page attributes */ ! 432: ! 433: debugLog2(11, pp->pte1, prot); /* end remap */ ! 434: ! 435: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Lock the physical entry */ ! 436: panic("\nmapping_phys_attr: Timeout attempting to lock physical entry at %08X: %08X %08X\n", ! 437: pp, pp->phys_link, pp->pte1); /* Complain about timeout */ ! 438: } ! 439: ! 440: // if(pp->phys_link) panic("\nmapping_phys_attr: attempt to change default attributes when mappings exist!\n"); ! 441: ! 442: hw_phys_attr(pp, ppc_prot(prot), wimg); /* Go set the default WIMG and protection */ ! 443: ! 444: hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* We're done, unlock the physical entry */ ! 445: debugLog2(12, pp->pte1, wimg); /* end remap */ ! 446: ! 447: return; /* Leave... */ ! 448: } ! 449: ! 450: /* ! 451: * void mapping_invall(phys_entry *pp) - invalidates all ptes associated with a page ! 452: * ! 453: * This routine takes a physical entry and runs through all mappings attached to it and invalidates ! 454: * any PTEs it finds. ! 455: * ! 456: * Interruptions must be disabled and the physical entry locked at entry. ! 457: */ ! 458: ! 459: void mapping_invall(struct phys_entry *pp) { /* Clear all PTEs pointing to a physical page */ ! 460: ! 461: hw_inv_all(pp); /* Go set the change bit of a physical page */ ! 462: ! 463: return; /* Leave... */ ! 464: } ! 465: ! 466: ! 467: /* ! 468: * void mapping_clr_mod(phys_entry *pp) - clears the change bit of a physical page ! 469: * ! 470: * This routine takes a physical entry and runs through all mappings attached to it and turns ! 471: * off the change bit. If there are PTEs associated with the mappings, they will be invalidated before ! 472: * the change bit is changed. We don't try to save the PTE. We won't worry about the LRU calculations ! 473: * either (I don't think, maybe I'll change my mind later). ! 474: * ! 475: * Interruptions must be disabled and the physical entry locked at entry. ! 476: */ ! 477: ! 478: void mapping_clr_mod(struct phys_entry *pp) { /* Clears the change bit of a physical page */ ! 479: ! 480: hw_clr_mod(pp); /* Go clear the change bit of a physical page */ ! 481: return; /* Leave... */ ! 482: } ! 483: ! 484: ! 485: /* ! 486: * void mapping_set_mod(phys_entry *pp) - set the change bit of a physical page ! 487: * ! 488: * This routine takes a physical entry and runs through all mappings attached to it and turns ! 489: * on the change bit. If there are PTEs associated with the mappings, they will be invalidated before ! 490: * the change bit is changed. We don't try to save the PTE. We won't worry about the LRU calculations ! 491: * either (I don't think, maybe I'll change my mind later). ! 492: * ! 493: * Interruptions must be disabled and the physical entry locked at entry. ! 494: */ ! 495: ! 496: void mapping_set_mod(struct phys_entry *pp) { /* Sets the change bit of a physical page */ ! 497: ! 498: hw_set_mod(pp); /* Go set the change bit of a physical page */ ! 499: return; /* Leave... */ ! 500: } ! 501: ! 502: ! 503: /* ! 504: * void mapping_clr_ref(struct phys_entry *pp) - clears the reference bit of a physical page ! 505: * ! 506: * This routine takes a physical entry and runs through all mappings attached to it and turns ! 507: * off the reference bit. If there are PTEs associated with the mappings, they will be invalidated before ! 508: * the reference bit is changed. We don't try to save the PTE. We won't worry about the LRU calculations ! 509: * either (I don't think, maybe I'll change my mind later). ! 510: * ! 511: * Interruptions must be disabled at entry. ! 512: */ ! 513: ! 514: void mapping_clr_ref(struct phys_entry *pp) { /* Clears the reference bit of a physical page */ ! 515: ! 516: mapping *mp; ! 517: ! 518: debugLog2(13, pp->pte1, 0); /* end remap */ ! 519: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Lock the physical entry for this mapping */ ! 520: panic("Lock timeout getting lock on physical entry\n"); /* Just die... */ ! 521: } ! 522: hw_clr_ref(pp); /* Go clear the reference bit of a physical page */ ! 523: hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* Unlock physical entry */ ! 524: debugLog2(14, pp->pte1, 0); /* end remap */ ! 525: return; /* Leave... */ ! 526: } ! 527: ! 528: ! 529: /* ! 530: * void mapping_set_ref(phys_entry *pp) - set the reference bit of a physical page ! 531: * ! 532: * This routine takes a physical entry and runs through all mappings attached to it and turns ! 533: * on the reference bit. If there are PTEs associated with the mappings, they will be invalidated before ! 534: * the reference bit is changed. We don't try to save the PTE. We won't worry about the LRU calculations ! 535: * either (I don't think, maybe I'll change my mind later). ! 536: * ! 537: * Interruptions must be disabled and the physical entry locked at entry. ! 538: */ ! 539: ! 540: void mapping_set_ref(struct phys_entry *pp) { /* Sets the reference bit of a physical page */ ! 541: ! 542: hw_set_ref(pp); /* Go set the reference bit of a physical page */ ! 543: return; /* Leave... */ ! 544: } ! 545: ! 546: ! 547: /* ! 548: * void mapping_tst_mod(phys_entry *pp) - test the change bit of a physical page ! 549: * ! 550: * This routine takes a physical entry and runs through all mappings attached to it and tests ! 551: * the changed bit. If there are PTEs associated with the mappings, they will be invalidated before ! 552: * the changed bit is tested. We don't try to save the PTE. We won't worry about the LRU calculations ! 553: * either (I don't think, maybe I'll change my mind later). ! 554: * ! 555: * Interruptions must be disabled and the physical entry locked at entry. ! 556: */ ! 557: ! 558: boolean_t mapping_tst_mod(struct phys_entry *pp) { /* Tests the change bit of a physical page */ ! 559: ! 560: return(hw_tst_mod(pp)); /* Go test the change bit of a physical page */ ! 561: } ! 562: ! 563: ! 564: /* ! 565: * void mapping_tst_ref(phys_entry *pp) - tests the reference bit of a physical page ! 566: * ! 567: * This routine takes a physical entry and runs through all mappings attached to it and tests ! 568: * the reference bit. If there are PTEs associated with the mappings, they will be invalidated before ! 569: * the reference bit is changed. We don't try to save the PTE. We won't worry about the LRU calculations ! 570: * either (I don't think, maybe I'll change my mind later). ! 571: * ! 572: * Interruptions must be disabled and the physical entry locked at entry. ! 573: */ ! 574: ! 575: boolean_t mapping_tst_ref(struct phys_entry *pp) { /* Tests the reference bit of a physical page */ ! 576: ! 577: return(hw_tst_ref(pp)); /* Go test the reference bit of a physical page */ ! 578: } ! 579: ! 580: ! 581: /* ! 582: * void mapping_phys_init(physent, wimg) - fills in the default processor dependent areas of the phys ent ! 583: * ! 584: * Currently, this sets the default word 1 of the PTE. The only bits set are the WIMG bits ! 585: */ ! 586: ! 587: void mapping_phys_init(struct phys_entry *pp, unsigned int pa, unsigned int wimg) { /* Initializes hw specific storage attributes */ ! 588: ! 589: pp->pte1 = (pa & -PAGE_SIZE) | ((wimg << 3) & 0x00000078); /* Set the WIMG and phys addr in the default PTE1 */ ! 590: ! 591: return; /* Leave... */ ! 592: } ! 593: ! 594: ! 595: /* ! 596: * mapping_adjust(void) - Releases free mapping blocks and/or allocates new ones ! 597: * ! 598: * This routine frees any mapping blocks queued to mapCtl.mapcrel. It also checks ! 599: * the number of free mappings remaining, and if below a threshold, replenishes them. ! 600: * The list will be replenshed from mapCtl.mapcrel if there are enough. Otherwise, ! 601: * a new one is allocated. ! 602: * ! 603: * This routine allocates and/or memory and must be called from a safe place. ! 604: * Currently, vm_pageout_scan is the safest place. We insure that the ! 605: */ ! 606: ! 607: thread_call_t mapping_adjust_call; ! 608: static thread_call_data_t mapping_adjust_call_data; ! 609: ! 610: void mapping_adjust(void) { /* Adjust free mappings */ ! 611: ! 612: kern_return_t retr; ! 613: mappingblok *mb, *mbn; ! 614: spl_t s; ! 615: int allocsize, i; ! 616: ! 617: if(mapCtl.mapcmin <= MAPPERBLOK) { /* Do the first time only */ ! 618: mapCtl.mapcmin = mem_size >> 12; /* Make sure we have enough for all of physical memory */ ! 619: #if DEBUG ! 620: kprintf("mapping_adjust: minimum entries rqrd = %08X\n", mapCtl.mapcmin); ! 621: kprintf("mapping_adjust: free = %08X; in use = %08X; release = %08X\n", ! 622: mapCtl.mapcfree, mapCtl.mapcinuse, mapCtl.mapcreln); ! 623: #endif ! 624: } ! 625: ! 626: s = splhigh(); /* Don't bother from now on */ ! 627: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ ! 628: panic("mapping_adjust - timeout getting control lock (1)\n"); /* Tell all and die */ ! 629: } ! 630: ! 631: if (mapping_adjust_call == NULL) { ! 632: thread_call_setup(&mapping_adjust_call_data, mapping_adjust, NULL); ! 633: mapping_adjust_call = &mapping_adjust_call_data; ! 634: } ! 635: ! 636: while(1) { /* Keep going until we've got enough */ ! 637: ! 638: allocsize = mapCtl.mapcmin - mapCtl.mapcfree; /* Figure out how much we need */ ! 639: if(allocsize < 1) break; /* Leave if we have all we need */ ! 640: ! 641: if((unsigned int)(mbn = mapCtl.mapcrel)) { /* Can we rescue a free one? */ ! 642: mapCtl.mapcrel = mbn->nextblok; /* Dequeue it */ ! 643: mapCtl.mapcreln--; /* Back off the count */ ! 644: allocsize = MAPPERBLOK; /* Show we allocated one block */ ! 645: } ! 646: else { /* No free ones, try to get it */ ! 647: ! 648: allocsize = (allocsize + MAPPERBLOK - 1) / MAPPERBLOK; /* Get the number of pages we need */ ! 649: if(allocsize > (mapCtl.mapcfree / 2)) allocsize = (mapCtl.mapcfree / 2); /* Don't try for anything that we can't comfortably map */ ! 650: ! 651: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ ! 652: splx(s); /* Restore 'rupts */ ! 653: ! 654: for(; allocsize > 0; allocsize >>= 1) { /* Try allocating in descending halves */ ! 655: retr = kmem_alloc_wired(kernel_map, (vm_offset_t *)&mbn, PAGE_SIZE * allocsize); /* Find a virtual address to use */ ! 656: if((retr != KERN_SUCCESS) && (allocsize == 1)) { /* Did we find any memory at all? */ ! 657: panic("Whoops... Not a bit of wired memory left for anyone\n"); ! 658: } ! 659: if(retr == KERN_SUCCESS) break; /* We got some memory, bail out... */ ! 660: } ! 661: ! 662: allocsize = allocsize * MAPPERBLOK; /* Convert pages to number of maps allocated */ ! 663: s = splhigh(); /* Don't bother from now on */ ! 664: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ ! 665: panic("mapping_adjust - timeout getting control lock (2)\n"); /* Tell all and die */ ! 666: } ! 667: } ! 668: for(; allocsize > 0; allocsize -= MAPPERBLOK) { /* Release one block at a time */ ! 669: mapping_free_init((vm_offset_t)mbn, 0, 1); /* Initialize a non-permanent block */ ! 670: mbn = (mappingblok *)((unsigned int)mbn + PAGE_SIZE); /* Point to the next slot */ ! 671: } ! 672: } ! 673: ! 674: if(mapCtl.mapcholdoff) { /* Should we hold off this release? */ ! 675: mapCtl.mapcrecurse = 0; /* We are done now */ ! 676: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ ! 677: splx(s); /* Restore 'rupts */ ! 678: return; /* Return... */ ! 679: } ! 680: ! 681: mbn = mapCtl.mapcrel; /* Get first pending release block */ ! 682: mapCtl.mapcrel = 0; /* Dequeue them */ ! 683: mapCtl.mapcreln = 0; /* Set count to 0 */ ! 684: ! 685: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ ! 686: splx(s); /* Restore 'rupts */ ! 687: ! 688: while((unsigned int)mbn) { /* Toss 'em all */ ! 689: mb = mbn->nextblok; /* Get the next */ ! 690: kmem_free(kernel_map, (vm_offset_t) mbn, PAGE_SIZE); /* Release this mapping block */ ! 691: mbn = mb; /* Chain to the next */ ! 692: } ! 693: ! 694: __asm__ volatile("sync"); /* Make sure all is well */ ! 695: mapCtl.mapcrecurse = 0; /* We are done now */ ! 696: return; ! 697: } ! 698: ! 699: /* ! 700: * mapping_free(mapping *mp) - release a mapping to the free list ! 701: * ! 702: * This routine takes a mapping and adds it to the free list. ! 703: * If this mapping make the block non-empty, we queue it to the free block list. ! 704: * NOTE: we might want to queue it to the end to keep quelch the pathalogical ! 705: * case when we get a mapping and free it repeatedly causing the block to chain and unchain. ! 706: * If this release fills a block and we are above the threshold, we release the block ! 707: */ ! 708: ! 709: void mapping_free(struct mapping *mp) { /* Release a mapping */ ! 710: ! 711: mappingblok *mb, *mbn; ! 712: spl_t s; ! 713: unsigned int full, mindx; ! 714: ! 715: mindx = ((unsigned int)mp & (PAGE_SIZE - 1)) >> 5; /* Get index to mapping */ ! 716: mb = (mappingblok *)((unsigned int)mp & -PAGE_SIZE); /* Point to the mapping block */ ! 717: ! 718: s = splhigh(); /* Don't bother from now on */ ! 719: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ ! 720: panic("mapping_free - timeout getting control lock\n"); /* Tell all and die */ ! 721: } ! 722: ! 723: full = !(mb->mapblokfree[0] | mb->mapblokfree[1] | mb->mapblokfree[2] | mb->mapblokfree[3]); /* See if full now */ ! 724: mb->mapblokfree[mindx >> 5] |= (0x80000000 >> (mindx & 31)); /* Flip on the free bit */ ! 725: ! 726: if(full) { /* If it was full before this: */ ! 727: mb->nextblok = mapCtl.mapcnext; /* Move head of list to us */ ! 728: mapCtl.mapcnext = mb; /* Chain us to the head of the list */ ! 729: } ! 730: ! 731: mapCtl.mapcfree++; /* Bump free count */ ! 732: mapCtl.mapcinuse--; /* Decriment in use count */ ! 733: ! 734: mapCtl.mapcfreec++; /* Count total calls */ ! 735: ! 736: if(mapCtl.mapcfree > mapCtl.mapcmin) { /* Should we consider releasing this? */ ! 737: if(((mb->mapblokfree[0] | 0x80000000) & mb->mapblokfree[1] & mb->mapblokfree[2] & mb->mapblokfree[3]) ! 738: == 0xFFFFFFFF) { /* See if empty now */ ! 739: ! 740: if(mapCtl.mapcnext == mb) { /* Are we first on the list? */ ! 741: mapCtl.mapcnext = mb->nextblok; /* Unchain us */ ! 742: if(!((unsigned int)mapCtl.mapcnext)) mapCtl.mapclast = 0; /* If last, remove last */ ! 743: } ! 744: else { /* We're not first */ ! 745: for(mbn = mapCtl.mapcnext; mbn != 0; mbn = mbn->nextblok) { /* Search for our block */ ! 746: if(mbn->nextblok == mb) break; /* Is the next one our's? */ ! 747: } ! 748: if(!mbn) panic("mapping_free: attempt to release mapping block (%08X) not on list\n", mp); ! 749: mbn->nextblok = mb->nextblok; /* Dequeue us */ ! 750: if(mapCtl.mapclast == mb) mapCtl.mapclast = mbn; /* If last, make our predecessor last */ ! 751: } ! 752: ! 753: if(mb->mapblokflags & mbPerm) { /* Is this permanently assigned? */ ! 754: mb->nextblok = mapCtl.mapcnext; /* Move chain head to us */ ! 755: mapCtl.mapcnext = mb; /* Chain us to the head */ ! 756: if(!((unsigned int)mb->nextblok)) mapCtl.mapclast = mb; /* If last, make us so */ ! 757: } ! 758: else { ! 759: mapCtl.mapcfree -= MAPPERBLOK; /* Remove the block from the free count */ ! 760: mapCtl.mapcreln++; /* Count on release list */ ! 761: mb->nextblok = mapCtl.mapcrel; /* Move pointer */ ! 762: mapCtl.mapcrel = mb; /* Chain us in front */ ! 763: } ! 764: } ! 765: } ! 766: ! 767: if(mapCtl.mapcreln > MAPFRTHRSH) { /* Do we have way too many releasable mappings? */ ! 768: if(hw_compare_and_store(0, 1, &mapCtl.mapcrecurse)) { /* Make sure we aren't recursing */ ! 769: thread_call_enter(mapping_adjust_call); /* Go toss some */ ! 770: } ! 771: } ! 772: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ ! 773: splx(s); /* Restore 'rupts */ ! 774: ! 775: return; /* Bye, dude... */ ! 776: } ! 777: ! 778: ! 779: /* ! 780: * mapping_alloc(void) - obtain a mapping from the free list ! 781: * ! 782: * This routine takes a mapping off of the free list and returns it's address. ! 783: * ! 784: * We do this by finding a free entry in the first block and allocating it. ! 785: * If this allocation empties the block, we remove it from the free list. ! 786: * If this allocation drops the total number of free entries below a threshold, ! 787: * we allocate a new block. ! 788: * ! 789: */ ! 790: ! 791: mapping *mapping_alloc(void) { /* Obtain a mapping */ ! 792: ! 793: register mapping *mp; ! 794: mappingblok *mb, *mbn; ! 795: spl_t s; ! 796: int mindx; ! 797: kern_return_t retr; ! 798: ! 799: s = splhigh(); /* Don't bother from now on */ ! 800: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ ! 801: panic("mapping_alloc - timeout getting control lock\n"); /* Tell all and die */ ! 802: } ! 803: ! 804: if(!(mb = mapCtl.mapcnext)) { /* Get the first block entry */ ! 805: panic("mapping_alloc - free mappings exhausted\n"); /* Whine and moan */ ! 806: } ! 807: ! 808: ! 809: if(!(mindx = mapalc(mb))) { /* Allocate a slot */ ! 810: panic("mapping_alloc - empty mapping block detected at %08X\n", mb); /* Not allowed to find none */ ! 811: } ! 812: ! 813: if(mindx < 0) { /* Did we just take the last one */ ! 814: mindx = -mindx; /* Make positive */ ! 815: mapCtl.mapcnext = mb->nextblok; /* Remove us from the list */ ! 816: if(!((unsigned int)mapCtl.mapcnext)) mapCtl.mapclast = 0; /* Removed the last one */ ! 817: } ! 818: ! 819: mapCtl.mapcfree--; /* Decrement free count */ ! 820: mapCtl.mapcinuse++; /* Bump in use count */ ! 821: ! 822: mapCtl.mapcallocc++; /* Count total calls */ ! 823: ! 824: /* ! 825: * Note: in the following code, we will attempt to rescue blocks only one at a time. ! 826: * Eventually, after a few more mapping_alloc calls, we will catch up. If there are none ! 827: * rescueable, we will kick the misc scan who will allocate some for us. We only do this ! 828: * if we haven't already done it. ! 829: * For early boot, we are set up to only rescue one block at a time. This is because we prime ! 830: * the release list with as much as we need until threads start. ! 831: */ ! 832: if(mapCtl.mapcfree < mapCtl.mapcmin) { /* See if we need to replenish */ ! 833: if(mbn = mapCtl.mapcrel) { /* Try to rescue a block from impending doom */ ! 834: mapCtl.mapcrel = mbn->nextblok; /* Pop the queue */ ! 835: mapCtl.mapcreln--; /* Back off the count */ ! 836: mapping_free_init((vm_offset_t)mbn, 0, 1); /* Initialize a non-permanent block */ ! 837: } ! 838: else { /* We need to replenish */ ! 839: if(hw_compare_and_store(0, 1, &mapCtl.mapcrecurse)) { /* Make sure we aren't recursing */ ! 840: thread_call_enter(mapping_adjust_call); /* Go allocate some more */ ! 841: } ! 842: } ! 843: } ! 844: ! 845: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ ! 846: splx(s); /* Restore 'rupts */ ! 847: ! 848: mp = &((mapping *)mb)[mindx]; /* Point to the allocated mapping */ ! 849: __asm__ volatile("dcbz 0,%0" : : "r" (mp)); /* Clean it up */ ! 850: return mp; /* Send it back... */ ! 851: } ! 852: ! 853: ! 854: /* ! 855: * void mapping_free_init(mb, perm) - Adds a block of storage to the free mapping list ! 856: * ! 857: * The mapping block is a page size area on a page boundary. It contains 1 header and 127 ! 858: * mappings. This call adds and initializes a block for use. ! 859: * ! 860: * The header contains a chain link, bit maps, a virtual to real translation mask, and ! 861: * some statistics. Bit maps map each slot on the page (bit 0 is not used because it ! 862: * corresponds to the header). The translation mask is the XOR of the virtual and real ! 863: * addresses (needless to say, the block must be wired). ! 864: * ! 865: * We handle these mappings the same way as saveareas: the block is only on the chain so ! 866: * long as there are free entries in it. ! 867: * ! 868: * Empty blocks are garbage collected when there are at least mapCtl.mapcmin pages worth of free ! 869: * mappings. Blocks marked PERM won't ever be released. ! 870: * ! 871: * If perm is negative, the mapping is initialized, but immediately queued to the mapCtl.mapcrel ! 872: * list. We do this only at start up time. This is done because we only allocate blocks ! 873: * in the pageout scan and it doesn't start up until after we run out of the initial mappings. ! 874: * Therefore, we need to preallocate a bunch, but we don't want them to be permanent. If we put ! 875: * them on the release queue, the allocate routine will rescue them. Then when the ! 876: * pageout scan starts, all extra ones will be released. ! 877: * ! 878: */ ! 879: ! 880: ! 881: void mapping_free_init(vm_offset_t mbl, int perm, boolean_t locked) { ! 882: /* Set's start and end of a block of mappings ! 883: perm indicates if the block can be released ! 884: or goes straight to the release queue . ! 885: locked indicates if the lock is held already */ ! 886: ! 887: mappingblok *mb; ! 888: spl_t s; ! 889: int i; ! 890: unsigned int raddr; ! 891: ! 892: mb = (mappingblok *)mbl; /* Start of area */ ! 893: ! 894: ! 895: if(perm >= 0) { /* See if we need to initialize the block */ ! 896: if(perm) { ! 897: raddr = (unsigned int)mbl; /* Perm means V=R */ ! 898: mb->mapblokflags = mbPerm; /* Set perm */ ! 899: } ! 900: else { ! 901: raddr = kvtophys(mbl); /* Get real address */ ! 902: mb->mapblokflags = 0; /* Set not perm */ ! 903: } ! 904: ! 905: mb->mapblokvrswap = raddr ^ (unsigned int)mbl; /* Form translation mask */ ! 906: ! 907: mb->mapblokfree[0] = 0x7FFFFFFF; /* Set first 32 (minus 1) free */ ! 908: mb->mapblokfree[1] = 0xFFFFFFFF; /* Set next 32 free */ ! 909: mb->mapblokfree[2] = 0xFFFFFFFF; /* Set next 32 free */ ! 910: mb->mapblokfree[3] = 0xFFFFFFFF; /* Set next 32 free */ ! 911: } ! 912: ! 913: s = splhigh(); /* Don't bother from now on */ ! 914: if(!locked) { /* Do we need the lock? */ ! 915: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ ! 916: panic("mapping_free_init - timeout getting control lock\n"); /* Tell all and die */ ! 917: } ! 918: } ! 919: ! 920: if(perm < 0) { /* Direct to release queue? */ ! 921: mb->nextblok = mapCtl.mapcrel; /* Move forward pointer */ ! 922: mapCtl.mapcrel = mb; /* Queue us on in */ ! 923: mapCtl.mapcreln++; /* Count the free block */ ! 924: } ! 925: else { /* Add to the free list */ ! 926: ! 927: mb->nextblok = 0; /* We always add to the end */ ! 928: mapCtl.mapcfree += MAPPERBLOK; /* Bump count */ ! 929: ! 930: if(!((unsigned int)mapCtl.mapcnext)) { /* First entry on list? */ ! 931: mapCtl.mapcnext = mapCtl.mapclast = mb; /* Chain to us */ ! 932: } ! 933: else { /* We are not the first */ ! 934: mapCtl.mapclast->nextblok = mb; /* Point the last to us */ ! 935: mapCtl.mapclast = mb; /* We are now last */ ! 936: } ! 937: } ! 938: ! 939: if(!locked) { /* Do we need to unlock? */ ! 940: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ ! 941: } ! 942: splx(s); /* Restore 'rupts */ ! 943: return; /* All done, leave... */ ! 944: } ! 945: ! 946: ! 947: /* ! 948: * void mapping_prealloc(unsigned int) - Preallocates mapppings for large request ! 949: * ! 950: * No locks can be held, because we allocate memory here. ! 951: * This routine needs a corresponding mapping_relpre call to remove the ! 952: * hold off flag so that the adjust routine will free the extra mapping ! 953: * blocks on the release list. I don't like this, but I don't know ! 954: * how else to do this for now... ! 955: * ! 956: */ ! 957: ! 958: void mapping_prealloc(unsigned int size) { /* Preallocates mapppings for large request */ ! 959: ! 960: int nmapb, i; ! 961: kern_return_t retr; ! 962: mappingblok *mbn; ! 963: spl_t s; ! 964: ! 965: s = splhigh(); /* Don't bother from now on */ ! 966: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ ! 967: panic("mapping_prealloc - timeout getting control lock\n"); /* Tell all and die */ ! 968: } ! 969: ! 970: nmapb = (size >> 12) + mapCtl.mapcmin; /* Get number of entries needed for this and the minimum */ ! 971: ! 972: mapCtl.mapcholdoff++; /* Bump the hold off count */ ! 973: ! 974: if((nmapb = (nmapb - mapCtl.mapcfree)) <= 0) { /* Do we already have enough? */ ! 975: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ ! 976: splx(s); /* Restore 'rupts */ ! 977: return; ! 978: } ! 979: ! 980: nmapb = (nmapb + MAPPERBLOK - 1) / MAPPERBLOK; /* Get number of blocks to get */ ! 981: ! 982: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ ! 983: splx(s); /* Restore 'rupts */ ! 984: ! 985: for(i = 0; i < nmapb; i++) { /* Allocate 'em all */ ! 986: retr = kmem_alloc_wired(kernel_map, (vm_offset_t *)&mbn, PAGE_SIZE); /* Find a virtual address to use */ ! 987: if(retr != KERN_SUCCESS) { /* Did we get some memory? */ ! 988: panic("Whoops... Not a bit of wired memory left for anyone\n"); ! 989: } ! 990: mapping_free_init((vm_offset_t)mbn, -1, 0); /* Initialize on to the release queue */ ! 991: } ! 992: } ! 993: ! 994: /* ! 995: * void mapping_relpre(void) - Releases preallocation release hold off ! 996: * ! 997: * This routine removes the ! 998: * hold off flag so that the adjust routine will free the extra mapping ! 999: * blocks on the release list. I don't like this, but I don't know ! 1000: * how else to do this for now... ! 1001: * ! 1002: */ ! 1003: ! 1004: void mapping_relpre(void) { /* Releases release hold off */ ! 1005: ! 1006: spl_t s; ! 1007: ! 1008: s = splhigh(); /* Don't bother from now on */ ! 1009: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ ! 1010: panic("mapping_relpre - timeout getting control lock\n"); /* Tell all and die */ ! 1011: } ! 1012: if(--mapCtl.mapcholdoff < 0) { /* Back down the hold off count */ ! 1013: panic("mapping_relpre: hold-off count went negative\n"); ! 1014: } ! 1015: ! 1016: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ ! 1017: splx(s); /* Restore 'rupts */ ! 1018: } ! 1019: ! 1020: /* ! 1021: * void mapping_free_prime(void) - Primes the mapping block release list ! 1022: * ! 1023: * See mapping_free_init. ! 1024: * No locks can be held, because we allocate memory here. ! 1025: * One processor running only. ! 1026: * ! 1027: */ ! 1028: ! 1029: void mapping_free_prime(void) { /* Primes the mapping block release list */ ! 1030: ! 1031: int nmapb, i; ! 1032: kern_return_t retr; ! 1033: mappingblok *mbn; ! 1034: ! 1035: nmapb = (mapCtl.mapcfree + mapCtl.mapcinuse + MAPPERBLOK - 1) / MAPPERBLOK; /* Get permanent allocation */ ! 1036: nmapb = nmapb * 4; /* Get 4 times our initial allocation */ ! 1037: ! 1038: #if DEBUG ! 1039: kprintf("mapping_free_prime: free = %08X; in use = %08X; priming = %08X\n", ! 1040: mapCtl.mapcfree, mapCtl.mapcinuse, nmapb); ! 1041: #endif ! 1042: ! 1043: for(i = 0; i < nmapb; i++) { /* Allocate 'em all */ ! 1044: retr = kmem_alloc_wired(kernel_map, (vm_offset_t *)&mbn, PAGE_SIZE); /* Find a virtual address to use */ ! 1045: if(retr != KERN_SUCCESS) { /* Did we get some memory? */ ! 1046: panic("Whoops... Not a bit of wired memory left for anyone\n"); ! 1047: } ! 1048: mapping_free_init((vm_offset_t)mbn, -1, 0); /* Initialize onto release queue */ ! 1049: } ! 1050: } ! 1051: ! 1052: /* ! 1053: * vm_offset_t mapping_p2v(space_t space, phys_entry *pp) - Finds first virtual mapping of a physical page in a space ! 1054: * ! 1055: * Gets a lock on the physical entry. Then it searches the list of attached mappings for one with ! 1056: * the same space. If it finds it, it returns the virtual address. ! 1057: */ ! 1058: ! 1059: vm_offset_t mapping_p2v(space_t space, struct phys_entry *pp) { /* Finds first virtual mapping of a physical page in a space */ ! 1060: ! 1061: spl_t s; ! 1062: register mapping *mp, *mpv; ! 1063: vm_offset_t va; ! 1064: ! 1065: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Try to get the lock on the physical entry */ ! 1066: splx(s); /* Restore 'rupts */ ! 1067: panic("mapping_p2v: timeout getting lock on physent\n"); /* Arrrgghhhh! */ ! 1068: return(0); /* Should die before here */ ! 1069: } ! 1070: ! 1071: va = 0; /* Assume failure */ ! 1072: ! 1073: for(mpv = hw_cpv(pp->phys_link); mpv; mp = hw_cpv(mp->next)) { /* Scan 'em all */ ! 1074: ! 1075: if(!(((mpv->PTEv >> 7) & 0x000FFFFF) == space)) continue; /* Skip all the rest if this is not the right space... */ ! 1076: ! 1077: va = ((((unsigned int)mpv->PTEhash & -64) << 5) ^ (space << 12)) & 0x003FF000; /* Backward hash to the wrapped VADDR */ ! 1078: va = va | ((mpv->PTEv << 8) & 0xF0000000); /* Move in the segment number */ ! 1079: va = va | ((mpv->PTEv << 22) & 0x0FC00000); /* Add in the API for the top of the address */ ! 1080: break; /* We're done now, pass virtual address back */ ! 1081: } ! 1082: ! 1083: hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* Unlock the physical entry */ ! 1084: splx(s); /* Restore 'rupts */ ! 1085: return(va); /* Return the result or 0... */ ! 1086: } ! 1087: ! 1088: /* ! 1089: * kvtophys(addr) ! 1090: * ! 1091: * Convert a kernel virtual address to a physical address ! 1092: */ ! 1093: vm_offset_t kvtophys(vm_offset_t va) { ! 1094: ! 1095: register mapping *mp, *mpv; ! 1096: register vm_offset_t pa; ! 1097: spl_t s; ! 1098: ! 1099: s=splhigh(); /* Don't bother from now on */ ! 1100: mp = hw_lock_phys_vir(PPC_SID_KERNEL, va); /* Find mapping and lock the physical entry for this mapping */ ! 1101: ! 1102: if((unsigned int)mp&1) { /* Did the lock on the phys entry time out? */ ! 1103: splx(s); /* Restore 'rupts */ ! 1104: panic("kvtophys: timeout obtaining lock on physical entry (vaddr=%08X)\n", va); /* Scream bloody murder! */ ! 1105: return 0; ! 1106: } ! 1107: ! 1108: if(!mp) { /* If it was not found, or no physical entry */ ! 1109: splx(s); /* Restore 'rupts */ ! 1110: return 0; /* Return 0 */ ! 1111: } ! 1112: ! 1113: mpv = hw_cpv(mp); /* Convert to virtual addressing */ ! 1114: ! 1115: if(!mpv->physent) { /* Was there a physical entry? */ ! 1116: pa = (vm_offset_t)((mpv->PTEr & -PAGE_SIZE) | ((unsigned int)va & (PAGE_SIZE-1))); /* Get physical address from physent */ ! 1117: } ! 1118: else { ! 1119: pa = (vm_offset_t)((mpv->physent->pte1 & -PAGE_SIZE) | ((unsigned int)va & (PAGE_SIZE-1))); /* Get physical address from physent */ ! 1120: hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK); /* Unlock the physical entry */ ! 1121: } ! 1122: ! 1123: splx(s); /* Restore 'rupts */ ! 1124: return pa; /* Return the physical address... */ ! 1125: } ! 1126: ! 1127: /* ! 1128: * phystokv(addr) ! 1129: * ! 1130: * Convert a physical address to a kernel virtual address if ! 1131: * there is a mapping, otherwise return NULL ! 1132: */ ! 1133: ! 1134: vm_offset_t phystokv(vm_offset_t pa) { ! 1135: ! 1136: struct phys_entry *pp; ! 1137: vm_offset_t va; ! 1138: ! 1139: pp = pmap_find_physentry(pa); /* Find the physical entry */ ! 1140: if (PHYS_NULL == pp) { ! 1141: return (vm_offset_t)NULL; /* If none, return null */ ! 1142: } ! 1143: if(!(va=mapping_p2v(PPC_SID_KERNEL, pp))) { ! 1144: return 0; /* Can't find it, return 0... */ ! 1145: } ! 1146: return (va | (pa & (PAGE_SIZE-1))); /* Build and return VADDR... */ ! 1147: ! 1148: } ! 1149: ! 1150: /* ! 1151: * Enters translations into the autogen maps. ! 1152: * ! 1153: * Not implemented yet, just stubbed out... ! 1154: */ ! 1155: ! 1156: boolean_t autogen_map(space_t space, vm_offset_t va, vm_offset_t spa, vm_offset_t epa, vm_prot_t prot, int attr) { /* Build an autogen area */ ! 1157: ! 1158: return(0); /* Just return false for now */ ! 1159: } ! 1160: ! 1161: ! 1162: /* ! 1163: * Dumps out the mapping stuff associated with a virtual address ! 1164: */ ! 1165: void dumpaddr(space_t space, vm_offset_t va) { ! 1166: ! 1167: mapping *mp, *mpv; ! 1168: vm_offset_t pa; ! 1169: spl_t s; ! 1170: ! 1171: s=splhigh(); /* Don't bother me */ ! 1172: ! 1173: mp = hw_lock_phys_vir(space, va); /* Lock the physical entry for this mapping */ ! 1174: if(!mp) { /* Did we find one? */ ! 1175: splx(s); /* Restore the interrupt level */ ! 1176: printf("dumpaddr: virtual address (%08X) not mapped\n", va); ! 1177: return; /* Didn't find any, return FALSE... */ ! 1178: } ! 1179: if((unsigned int)mp&1) { /* Did we timeout? */ ! 1180: panic("dumpaddr: timeout locking physical entry for virtual address (%08X)\n", va); /* Yeah, scream about it! */ ! 1181: splx(s); /* Restore the interrupt level */ ! 1182: return; /* Bad hair day, return FALSE... */ ! 1183: } ! 1184: printf("dumpaddr: space=%08X; vaddr=%08X\n", space, va); /* Say what address were dumping */ ! 1185: mpv = hw_cpv(mp); /* Get virtual address of mapping */ ! 1186: dumpmapping(mpv); ! 1187: if(mpv->physent) { ! 1188: dumppca(mpv); ! 1189: hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK); /* Unlock physical entry associated with mapping */ ! 1190: } ! 1191: splx(s); /* Was there something you needed? */ ! 1192: return; /* Tell them we did it */ ! 1193: } ! 1194: ! 1195: ! 1196: ! 1197: /* ! 1198: * Prints out a mapping control block ! 1199: * ! 1200: */ ! 1201: ! 1202: void dumpmapping(struct mapping *mp) { /* Dump out a mapping */ ! 1203: ! 1204: printf("Dump of mapping block: %08X\n", mp); /* Header */ ! 1205: printf(" next: %08X\n", mp->next); ! 1206: printf(" hashnext: %08X\n", mp->hashnext); ! 1207: printf(" PTEhash: %08X\n", mp->PTEhash); ! 1208: printf(" PTEent: %08X\n", mp->PTEent); ! 1209: printf(" physent: %08X\n", mp->physent); ! 1210: printf(" PTEv: %08X\n", mp->PTEv); ! 1211: printf(" PTEr: %08X\n", mp->PTEr); ! 1212: printf(" pmap: %08X\n", mp->pmap); ! 1213: ! 1214: if(mp->physent) { /* Print physent if it exists */ ! 1215: printf("Associated physical entry: %08X %08X\n", mp->physent->phys_link, mp->physent->pte1); ! 1216: } ! 1217: else { ! 1218: printf("Associated physical entry: none\n"); ! 1219: } ! 1220: ! 1221: dumppca(mp); /* Dump out the PCA information */ ! 1222: ! 1223: return; ! 1224: } ! 1225: ! 1226: /* ! 1227: * Prints out a PTEG control area ! 1228: * ! 1229: */ ! 1230: ! 1231: void dumppca(struct mapping *mp) { /* PCA */ ! 1232: ! 1233: PCA *pca; ! 1234: unsigned int *pteg; ! 1235: ! 1236: pca = (PCA *)((unsigned int)mp->PTEhash&-64); /* Back up to the start of the PCA */ ! 1237: pteg=(unsigned int *)((unsigned int)pca-(((hash_table_base&0x0000FFFF)+1)<<16)); ! 1238: printf(" Dump of PCA: %08X\n", pca); /* Header */ ! 1239: printf(" PCAlock: %08X\n", pca->PCAlock); ! 1240: printf(" PCAallo: %08X\n", pca->flgs.PCAallo); ! 1241: printf(" PCAhash: %08X %08X %08X %08X\n", pca->PCAhash[0], pca->PCAhash[1], pca->PCAhash[2], pca->PCAhash[3]); ! 1242: printf(" %08X %08X %08X %08X\n", pca->PCAhash[4], pca->PCAhash[5], pca->PCAhash[6], pca->PCAhash[7]); ! 1243: printf("Dump of PTEG: %08X\n", pteg); /* Header */ ! 1244: printf(" %08X %08X %08X %08X\n", pteg[0], pteg[1], pteg[2], pteg[3]); ! 1245: printf(" %08X %08X %08X %08X\n", pteg[4], pteg[5], pteg[6], pteg[7]); ! 1246: printf(" %08X %08X %08X %08X\n", pteg[8], pteg[9], pteg[10], pteg[11]); ! 1247: printf(" %08X %08X %08X %08X\n", pteg[12], pteg[13], pteg[14], pteg[15]); ! 1248: return; ! 1249: } ! 1250: ! 1251: /* ! 1252: * Dumps starting with a physical entry ! 1253: */ ! 1254: ! 1255: void dumpphys(struct phys_entry *pp) { /* Dump from physent */ ! 1256: ! 1257: mapping *mp; ! 1258: PCA *pca; ! 1259: unsigned int *pteg; ! 1260: ! 1261: printf("Dump from physical entry %08X: %08X %08X\n", pp, pp->phys_link, pp->pte1); ! 1262: mp = hw_cpv(pp->phys_link); ! 1263: while(mp) { ! 1264: dumpmapping(mp); ! 1265: dumppca(mp); ! 1266: mp = hw_cpv(mp->next); ! 1267: } ! 1268: ! 1269: return; ! 1270: } ! 1271: ! 1272: /* ! 1273: * void ignore_zero_fault(boolean_t) - Sets up to ignore or honor any fault on ! 1274: * page 0 access for the current thread. ! 1275: * ! 1276: * If parameter is TRUE, faults are ignored ! 1277: * If parameter is FALSE, faults are honored ! 1278: * ! 1279: */ ! 1280: ! 1281: void ignore_zero_fault(boolean_t type) { /* Sets up to ignore or honor any fault on page 0 access for the current thread */ ! 1282: ! 1283: if(type) current_act()->mact.specFlags |= ignoreZeroFault; /* Ignore faults on page 0 */ ! 1284: else current_act()->mact.specFlags &= ~ignoreZeroFault; /* Honor faults on page 0 */ ! 1285: ! 1286: return; /* Return the result or 0... */ ! 1287: } ! 1288: ! 1289: ! 1290: ! 1291: ! 1292: ! 1293: ! 1294: ! 1295:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.