|
|
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 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 ! 27: * All Rights Reserved ! 28: * ! 29: * Permission to use, copy, modify, and distribute this software and ! 30: * its documentation for any purpose and without fee is hereby granted, ! 31: * provided that the above copyright notice appears in all copies and ! 32: * that both the copyright notice and this permission notice appear in ! 33: * supporting documentation. ! 34: * ! 35: * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ! 36: * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ! 37: * FOR A PARTICULAR PURPOSE. ! 38: * ! 39: * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR ! 40: * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ! 41: * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, ! 42: * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION ! 43: * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ! 44: */ ! 45: /* ! 46: * MKLINUX-1.0DR2 ! 47: */ ! 48: ! 49: /* A marvelous selection of support routines for virtual memory */ ! 50: ! 51: ! 52: #include <debug.h> ! 53: #include <mach_vm_debug.h> ! 54: ! 55: #include <kern/thread.h> ! 56: #include <mach/vm_attributes.h> ! 57: #include <mach/vm_param.h> ! 58: #include <kernserv/machine/spl.h> ! 59: ! 60: /*#include <kern/misc_protos.h>*/ ! 61: /*#include <ppc/misc_protos.h>*/ ! 62: /*#include <ppc/gdb_defs.h> /* for kgdb_kernel_in_pmap used in assert */ ! 63: #include <machdep/ppc/proc_reg.h> ! 64: #include <machdep/ppc/mem.h> ! 65: #include <machdep/ppc/pmap.h> ! 66: #include <machdep/ppc/pmap_internals.h> ! 67: ! 68: /* [email protected] 2/12/97 */ ! 69: #define NULL ((void *) 0) ! 70: ! 71: /* These refer to physical addresses and are set and referenced elsewhere */ ! 72: ! 73: unsigned int hash_table_base; ! 74: unsigned int hash_table_size; ! 75: ! 76: unsigned int hash_function_mask; ! 77: ! 78: #if MACH_VM_DEBUG ! 79: #define DPRINTF(x) kprintf(x) ! 80: #else ! 81: #define DPRINTF(x) ! 82: #endif /* MACH_VM_DEBUG */ ! 83: ! 84: /* Prototypes for static functions */ ! 85: ! 86: static pte_t *find_pte_in_pteg(pte_t* pte, unsigned int match); ! 87: ! 88: /* gather statistics about hash table usage */ ! 89: ! 90: #if DEBUG ! 91: #define MEM_STATS 1 ! 92: #else ! 93: #define MEM_STATS 0 ! 94: #endif /* DEBUG */ ! 95: ! 96: #if MEM_STATS ! 97: /* hash table usage information */ ! 98: struct hash_table_stats { ! 99: int find_pte_in_pteg_calls; ! 100: int find_pte_in_pteg_not_found; ! 101: int find_pte_in_pteg_location[8]; ! 102: struct find_or_alloc_calls { ! 103: int found_primary; ! 104: int found_secondary; ! 105: int alloc_primary; ! 106: int alloc_secondary; ! 107: int overflow; ! 108: int not_found; ! 109: } find_or_alloc_calls[2]; ! 110: ! 111: } hash_table_stats; ! 112: #endif /* MEM_STATS */ ! 113: ! 114: /* Set up the machine registers for the given hash table. ! 115: * The table has already been zeroed. ! 116: */ ! 117: ! 118: void hash_table_init(unsigned int base, unsigned int size) ! 119: { ! 120: register pte_t* pte; ! 121: unsigned int mask; ! 122: int i; ! 123: ! 124: #if MACH_VM_DEBUG ! 125: if (size % (64*1024)) { ! 126: DPRINTF(("ERROR! size = 0x%x\n",size)); ! 127: enterDebugger("FATAL"); ! 128: } ! 129: if (base % size) { ! 130: DPRINTF(("ERROR! base not multiple of size\n")); ! 131: DPRINTF(("base = 0x%08x, size=%dK \n",base,size/1024)); ! 132: enterDebugger("FATAL"); ! 133: } ! 134: #endif ! 135: ! 136: #if PTE_EMPTY != 0 ! 137: /* We do not use zero values for marking empty PTE slots. This ! 138: * initialisation could be sped up, but it's only called once. ! 139: * the hash table has already been bzeroed. ! 140: */ ! 141: for (pte = (pte_t *) base; (unsigned int)pte < (base+size); pte++) { ! 142: pte->pte0.word = PTE_EMPTY; ! 143: } ! 144: #endif /* PTE_EMPTY != 0 */ ! 145: ! 146: mask = 0; ! 147: for (i = 1; i < (size >> 16); i *= 2) ! 148: mask = (mask << 1) | 1; ! 149: ! 150: mtsdr1(hash_table_base | mask); ! 151: ! 152: isync(); ! 153: ! 154: hash_function_mask = (mask << 16) | 0xFFC0; ! 155: } ! 156: ! 157: /* Given the address of a pteg and the pte0 to match, this returns ! 158: * the address of the matching pte or PTE_NULL. Can be used to search ! 159: * for an empty pte by using PTE_EMPTY as the matching parameter. ! 160: */ ! 161: ! 162: static __inline__ pte_t * ! 163: find_pte_in_pteg(pte_t* pte, unsigned int match) ! 164: { ! 165: register int i; ! 166: ! 167: #if MEM_STATS ! 168: hash_table_stats.find_pte_in_pteg_calls++; ! 169: #define INC_STAT(LOC) hash_table_stats.find_pte_in_pteg_location[LOC]++ ! 170: #else /* MEM_STATS */ ! 171: #define INC_STAT(LOC) ! 172: #endif /* MEM_STATS */ ! 173: ! 174: /* unrolled for speed */ ! 175: if (pte[0].pte0.word == match) { INC_STAT(0); return &pte[0]; } ! 176: if (pte[1].pte0.word == match) { INC_STAT(1); return &pte[1]; } ! 177: if (pte[2].pte0.word == match) { INC_STAT(2); return &pte[2]; } ! 178: if (pte[3].pte0.word == match) { INC_STAT(3); return &pte[3]; } ! 179: if (pte[4].pte0.word == match) { INC_STAT(4); return &pte[4]; } ! 180: if (pte[5].pte0.word == match) { INC_STAT(5); return &pte[5]; } ! 181: if (pte[6].pte0.word == match) { INC_STAT(6); return &pte[6]; } ! 182: if (pte[7].pte0.word == match) { INC_STAT(7); return &pte[7]; } ! 183: ! 184: #if MEM_STATS ! 185: hash_table_stats.find_pte_in_pteg_not_found++; ! 186: #endif /* MEM_STATS */ ! 187: return PTE_NULL; ! 188: } ! 189: ! 190: /* Given a space identifier and a virtual address, this returns the ! 191: * address of the pte describing this virtual page. ! 192: * ! 193: * If allocate is FALSE, the function will return PTE_NULL if not found ! 194: * ! 195: * If allocate is TRUE the function will create a new PTE entry marked ! 196: * as invalid with only pte0 set up (ie no physical info or ! 197: * protection/change info) ! 198: */ ! 199: ! 200: pte_t * ! 201: find_or_allocate_pte(space_t sid, vm_offset_t v_addr, boolean_t allocate) ! 202: { ! 203: register vm_offset_t primary_hash, secondary_hash; ! 204: register pte0_t primary_match, secondary_match; ! 205: register pte_t *pte; ! 206: register unsigned int segment_id; ! 207: ! 208: /* Horrible hack "(union *)&var-> " to retype to union */ ! 209: segment_id = (sid << 4) | (v_addr >> 28); ! 210: ! 211: primary_hash = segment_id ^ ((va_full_t *)&v_addr)->page_index; ! 212: ! 213: primary_hash = hash_table_base + ! 214: ((primary_hash << 6) & hash_function_mask); ! 215: ! 216: /* Firstly check out the primary pteg */ ! 217: ! 218: #if 0 && MACH_VM_DEBUG ! 219: if (sid) { ! 220: DPRINTF(("PRIMARY HASH OF SID 0x%x and addr 0x%x = 0x%x**********\n", ! 221: sid, v_addr, primary_hash)); ! 222: } ! 223: #endif ! 224: ! 225: /* TODO NMGS could be faster if all put on one line with shifts etc, ! 226: * does -O2 optimise this? ! 227: */ ! 228: ! 229: primary_match.bits.valid = 1; ! 230: /* virtual segment id = concat of space id + seg reg no */ ! 231: primary_match.bits.segment_id = segment_id; ! 232: primary_match.bits.hash_id = 0; ! 233: primary_match.bits.page_index = ((va_abbrev_t *)&v_addr)->page_index; ! 234: ! 235: ! 236: pte = find_pte_in_pteg((pte_t *) primary_hash, primary_match.word); ! 237: ! 238: if (pte != PTE_NULL) { ! 239: #if MEM_STATS ! 240: hash_table_stats.find_or_alloc_calls[allocate].found_primary++; ! 241: #endif /* MEM_STATS */ ! 242: assert (pte->pte0.word != PTE_EMPTY); ! 243: return pte; ! 244: } ! 245: ! 246: #if 0 && MACH_VM_DEBUG ! 247: DPRINTF(("find_pte : searching secondary hash\n")); ! 248: #endif ! 249: ! 250: /* pte wasn't found in primary hash location, check secondary */ ! 251: ! 252: secondary_match = primary_match; ! 253: secondary_match.bits.hash_id = 1; /* Indicate secondary hash */ ! 254: ! 255: secondary_hash = primary_hash ^ hash_function_mask; ! 256: ! 257: pte = find_pte_in_pteg((pte_t *) secondary_hash, secondary_match.word); ! 258: ! 259: #if MEM_STATS ! 260: if (pte != PTE_NULL) ! 261: hash_table_stats.find_or_alloc_calls[allocate].found_secondary++; ! 262: if ((pte == PTE_NULL) && !allocate) ! 263: hash_table_stats.find_or_alloc_calls[allocate].not_found++; ! 264: #endif /* MEM_STATS */ ! 265: ! 266: if ((pte == PTE_NULL) && allocate) { ! 267: /* pte wasn't found - find one ourselves and fill in ! 268: * the pte0 entry (mark as invalid though?) ! 269: */ ! 270: pte = find_pte_in_pteg((pte_t *) primary_hash, PTE_EMPTY); ! 271: if (pte != PTE_NULL) { ! 272: /* Found in primary location, set up pte0 */ ! 273: ! 274: primary_match.bits.valid = 0; ! 275: pte->pte0.word = primary_match.word; ! 276: #if MEM_STATS ! 277: hash_table_stats.find_or_alloc_calls[allocate].alloc_primary++; ! 278: #endif /* MEM_STATS */ ! 279: ! 280: } else { ! 281: pte = find_pte_in_pteg((pte_t *) secondary_hash, ! 282: PTE_EMPTY); ! 283: if (pte != PTE_NULL) { ! 284: /* Found in secondary */ ! 285: secondary_match.bits.valid = 0; ! 286: pte->pte0.word = secondary_match.word; ! 287: #if MEM_STATS ! 288: hash_table_stats.find_or_alloc_calls[allocate].alloc_secondary++; ! 289: #endif /* MEM_STATS */ ! 290: } else { ! 291: #if MEM_STATS ! 292: hash_table_stats.find_or_alloc_calls[allocate].overflow++; ! 293: #endif /* MEM_STATS */ ! 294: /* Both PTEGs are full - we need to upcall ! 295: * to pmap to free up an entry, it will ! 296: * return the entry that has been freed up ! 297: */ ! 298: #if DEBUG ! 299: /* DPRINTF(("find_or_allocate : BOTH PTEGS ARE FULL\n")); */ ! 300: #endif /* DEBUG */ ! 301: pte = pmap_pteg_overflow( ! 302: (pte_t *)primary_hash, ! 303: primary_match, ! 304: (pte_t *)secondary_hash, ! 305: secondary_match); ! 306: assert (pte != PTE_NULL); ! 307: } ! 308: } ! 309: /* Set up the new entry - pmap code assumes: ! 310: * pte0 contains good translation but valid bit is reset ! 311: * pte1 has been initialised to zero ! 312: */ ! 313: assert(pte->pte0.word != PTE_EMPTY); ! 314: pte->pte1.word = 0; ! 315: ! 316: } ! 317: ! 318: return pte; /* Either the address or PTE_NULL */ ! 319: } ! 320:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.