|
|
1.1 ! root 1: /* $Id: sun-mmu.c,v 1.4 2003/05/16 21:48:13 fredette Exp $ */ ! 2: ! 3: /* machine/sun/sun-mmu.c - classic Sun MMU emulation implementation: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2003 Matt Fredette ! 7: * All rights reserved. ! 8: * ! 9: * Redistribution and use in source and binary forms, with or without ! 10: * modification, are permitted provided that the following conditions ! 11: * are met: ! 12: * 1. Redistributions of source code must retain the above copyright ! 13: * notice, this list of conditions and the following disclaimer. ! 14: * 2. Redistributions in binary form must reproduce the above copyright ! 15: * notice, this list of conditions and the following disclaimer in the ! 16: * documentation and/or other materials provided with the distribution. ! 17: * 3. All advertising materials mentioning features or use of this software ! 18: * must display the following acknowledgement: ! 19: * This product includes software developed by Matt Fredette. ! 20: * 4. The name of the author may not be used to endorse or promote products ! 21: * derived from this software without specific prior written permission. ! 22: * ! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 33: * POSSIBILITY OF SUCH DAMAGE. ! 34: */ ! 35: ! 36: #include <tme/common.h> ! 37: _TME_RCSID("$Id: sun-mmu.c,v 1.4 2003/05/16 21:48:13 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include <tme/machine/sun.h> ! 41: ! 42: /* macros: */ ! 43: #define TME_SUN_MMU_PMEG_TLBS (16) ! 44: ! 45: /* structures: */ ! 46: ! 47: /* an allocated TLB set in a classic two-level Sun MMU: */ ! 48: struct tme_sun_mmu_tlb_set { ! 49: ! 50: /* the next allocated TLB set: */ ! 51: struct tme_sun_mmu_tlb_set *tme_sun_mmu_tlb_set_next; ! 52: ! 53: /* the user's pointer into the TLB set: */ ! 54: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb **) tme_sun_mmu_tlb_set_pointer; ! 55: ! 56: /* the base of this TLB set: */ ! 57: struct tme_bus_tlb *tme_sun_mmu_tlb_set_base; ! 58: ! 59: /* the size of one TLB entry: */ ! 60: unsigned int tme_sun_mmu_tlb_set_sizeof_one; ! 61: ! 62: /* the number of TLB entries per context in the set: */ ! 63: unsigned int tme_sun_mmu_tlb_set_count; ! 64: }; ! 65: ! 66: /* one PMEG in a classic two-level Sun MMU: */ ! 67: struct tme_sun_mmu_pmeg { ! 68: ! 69: /* the current list of TLBs using a page table entry in this PMEG, and ! 70: the head within that list: */ ! 71: struct tme_bus_tlb *tme_sun_mmu_pmeg_tlbs[TME_SUN_MMU_PMEG_TLBS]; ! 72: unsigned int tme_sun_mmu_pmeg_tlbs_head; ! 73: }; ! 74: ! 75: /* the private structure for a classic two-level Sun MMU: */ ! 76: struct tme_sun_mmu { ! 77: ! 78: /* the information provided by the user: */ ! 79: struct tme_sun_mmu_info tme_sun_mmu_info; ! 80: #define tme_sun_mmu_element tme_sun_mmu_info.tme_sun_mmu_info_element ! 81: #define tme_sun_mmu_address_bits tme_sun_mmu_info.tme_sun_mmu_info_address_bits ! 82: #define tme_sun_mmu_pgoffset_bits tme_sun_mmu_info.tme_sun_mmu_info_pgoffset_bits ! 83: #define tme_sun_mmu_pteindex_bits tme_sun_mmu_info.tme_sun_mmu_info_pteindex_bits ! 84: #define tme_sun_mmu_contexts tme_sun_mmu_info.tme_sun_mmu_info_contexts ! 85: #define tme_sun_mmu_pmegs_count tme_sun_mmu_info.tme_sun_mmu_info_pmegs ! 86: #define tme_sun_mmu_seginv tme_sun_mmu_info.tme_sun_mmu_info_seginv ! 87: #define _tme_sun_mmu_tlb_fill_private tme_sun_mmu_info.tme_sun_mmu_info_tlb_fill_private ! 88: #define _tme_sun_mmu_tlb_fill tme_sun_mmu_info.tme_sun_mmu_info_tlb_fill ! 89: ! 90: /* the number of bits in a segment map index: */ ! 91: tme_uint8_t tme_sun_mmu_segment_bits; ! 92: ! 93: /* the segment map: */ ! 94: unsigned short *tme_sun_mmu_segment_map; ! 95: ! 96: /* the PMEGs: */ ! 97: struct tme_sun_mmu_pmeg *tme_sun_mmu_pmegs; ! 98: ! 99: /* the PTEs: */ ! 100: struct tme_sun_mmu_pte *tme_sun_mmu_ptes; ! 101: ! 102: /* the allocated TLB sets: */ ! 103: struct tme_sun_mmu_tlb_set *tme_sun_mmu_tlb_sets; ! 104: }; ! 105: ! 106: /* this creates a classic two-level Sun MMU: */ ! 107: void * ! 108: tme_sun_mmu_new(struct tme_sun_mmu_info *info) ! 109: { ! 110: struct tme_sun_mmu *mmu; ! 111: unsigned int segmap_count; ! 112: unsigned int segmap_i; ! 113: ! 114: /* allocate the new private structure: */ ! 115: mmu = tme_new0(struct tme_sun_mmu, 1); ! 116: ! 117: /* copy the user-provided information: */ ! 118: mmu->tme_sun_mmu_info = *info; ! 119: ! 120: /* allocate the segment map and initialize it to all invalid: */ ! 121: mmu->tme_sun_mmu_segment_bits = (mmu->tme_sun_mmu_address_bits ! 122: - (mmu->tme_sun_mmu_pteindex_bits ! 123: + mmu->tme_sun_mmu_pgoffset_bits)); ! 124: segmap_count = (mmu->tme_sun_mmu_contexts ! 125: * (1 << mmu->tme_sun_mmu_segment_bits)); ! 126: mmu->tme_sun_mmu_segment_map = tme_new(unsigned short, segmap_count); ! 127: for (segmap_i = 0; segmap_i < segmap_count; segmap_i++) { ! 128: mmu->tme_sun_mmu_segment_map[segmap_i] = mmu->tme_sun_mmu_seginv; ! 129: } ! 130: ! 131: /* allocate the PMEGs: */ ! 132: mmu->tme_sun_mmu_pmegs = tme_new0(struct tme_sun_mmu_pmeg, mmu->tme_sun_mmu_pmegs_count); ! 133: ! 134: /* allocate the PTEs: */ ! 135: mmu->tme_sun_mmu_ptes = ! 136: tme_new0(struct tme_sun_mmu_pte, ! 137: mmu->tme_sun_mmu_pmegs_count ! 138: * (1 << mmu->tme_sun_mmu_pteindex_bits)); ! 139: ! 140: /* done: */ ! 141: return (mmu); ! 142: } ! 143: ! 144: /* given a context and an address, returns the segment map index and ! 145: PTE: */ ! 146: static unsigned short ! 147: _tme_sun_mmu_lookup(struct tme_sun_mmu *mmu, tme_uint8_t context, tme_uint32_t address, ! 148: struct tme_sun_mmu_pte **_pte) ! 149: { ! 150: unsigned short pteindex; ! 151: unsigned short segment; ! 152: unsigned short segment_map_index; ! 153: unsigned short pmeg; ! 154: ! 155: /* lose the page offset bits: */ ! 156: address >>= mmu->tme_sun_mmu_pgoffset_bits; ! 157: ! 158: /* get the PTE index: */ ! 159: pteindex = (address ! 160: & (TME_BIT(mmu->tme_sun_mmu_pteindex_bits) - 1)); ! 161: address >>= mmu->tme_sun_mmu_pteindex_bits; ! 162: ! 163: /* get the segment number: */ ! 164: segment = (address ! 165: & (TME_BIT(mmu->tme_sun_mmu_segment_bits) - 1)); ! 166: ! 167: /* get the segment map index: */ ! 168: segment_map_index = ((context << mmu->tme_sun_mmu_segment_bits) ! 169: | segment); ! 170: ! 171: /* get the PMEG: */ ! 172: pmeg = mmu->tme_sun_mmu_segment_map[segment_map_index]; ! 173: ! 174: /* return the segment map index and the PTE: */ ! 175: *_pte = (mmu->tme_sun_mmu_ptes + (pmeg << mmu->tme_sun_mmu_pteindex_bits) + pteindex); ! 176: return (segment_map_index); ! 177: } ! 178: ! 179: /* this invalidates all TLB entries that may be affected by changes to ! 180: a PMEG: */ ! 181: static void ! 182: _tme_sun_mmu_pmeg_invalidate(struct tme_sun_mmu *mmu, unsigned short segment_map_index) ! 183: { ! 184: struct tme_sun_mmu_pmeg *pmeg; ! 185: int tlb_i; ! 186: struct tme_bus_tlb *tlb; ! 187: ! 188: /* get the PMEG: */ ! 189: pmeg = mmu->tme_sun_mmu_pmegs + mmu->tme_sun_mmu_segment_map[segment_map_index]; ! 190: ! 191: /* invalidate all of the TLBs: */ ! 192: for (tlb_i = 0; tlb_i < TME_SUN_MMU_PMEG_TLBS; tlb_i++) { ! 193: tlb = pmeg->tme_sun_mmu_pmeg_tlbs[tlb_i]; ! 194: pmeg->tme_sun_mmu_pmeg_tlbs[tlb_i] = NULL; ! 195: if (tlb != NULL) { ! 196: tme_bus_tlb_invalidate(tlb); ! 197: } ! 198: } ! 199: } ! 200: ! 201: /* this gets a PTE: */ ! 202: int ! 203: tme_sun_mmu_pte_get(void *_mmu, tme_uint8_t context, tme_uint32_t address, ! 204: struct tme_sun_mmu_pte *_pte) ! 205: { ! 206: struct tme_sun_mmu *mmu; ! 207: unsigned short segment_map_index; ! 208: struct tme_sun_mmu_pte *pte; ! 209: ! 210: /* lookup this address: */ ! 211: mmu = (struct tme_sun_mmu *) _mmu; ! 212: segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte); ! 213: ! 214: #if 0 ! 215: /* if this segment is invalid, return failure: */ ! 216: if (mmu->tme_sun_mmu_segment_map[segment_map_index] ! 217: == mmu->tme_sun_mmu_seginv) { ! 218: return (ENOENT); ! 219: } ! 220: #endif ! 221: ! 222: /* otherwise, copy the PTE: */ ! 223: *_pte = *pte; ! 224: return (TME_OK); ! 225: } ! 226: ! 227: /* this sets a PTE: */ ! 228: int ! 229: tme_sun_mmu_pte_set(void *_mmu, tme_uint8_t context, tme_uint32_t address, ! 230: struct tme_sun_mmu_pte *_pte) ! 231: { ! 232: struct tme_sun_mmu *mmu; ! 233: unsigned short segment_map_index; ! 234: struct tme_sun_mmu_pte *pte; ! 235: ! 236: /* lookup this address: */ ! 237: mmu = (struct tme_sun_mmu *) _mmu; ! 238: segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte); ! 239: ! 240: #if 0 ! 241: /* if this segment is invalid, return failure: */ ! 242: if (mmu->tme_sun_mmu_segment_map[segment_map_index] ! 243: == mmu->tme_sun_mmu_seginv) { ! 244: return (ENOENT); ! 245: } ! 246: #endif ! 247: ! 248: /* invalidate all TLB entries that are affected by changes to this PMEG: */ ! 249: _tme_sun_mmu_pmeg_invalidate(mmu, segment_map_index); ! 250: ! 251: /* otherwise, copy the PTE: */ ! 252: *pte = *_pte; ! 253: return (TME_OK); ! 254: } ! 255: ! 256: /* this gets a segment map entry: */ ! 257: unsigned short ! 258: tme_sun_mmu_segmap_get(void *_mmu, tme_uint8_t context, tme_uint32_t address) ! 259: { ! 260: struct tme_sun_mmu *mmu; ! 261: struct tme_sun_mmu_pte *pte; ! 262: unsigned short segment_map_index, pmeg; ! 263: ! 264: /* lookup this address: */ ! 265: mmu = (struct tme_sun_mmu *) _mmu; ! 266: segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte); ! 267: pmeg = mmu->tme_sun_mmu_segment_map[segment_map_index]; ! 268: tme_log(&mmu->tme_sun_mmu_element->tme_element_log_handle, 1000, TME_OK, ! 269: (&mmu->tme_sun_mmu_element->tme_element_log_handle, ! 270: "segmap_get: SEGMAP[%d:0x%08x] -> 0x%04x", ! 271: context, ! 272: address, ! 273: pmeg)); ! 274: return (pmeg); ! 275: } ! 276: ! 277: /* this sets a segment map entry: */ ! 278: void ! 279: tme_sun_mmu_segmap_set(void *_mmu, tme_uint8_t context, tme_uint32_t address, unsigned short pmeg) ! 280: { ! 281: struct tme_sun_mmu *mmu; ! 282: unsigned short segment_map_index; ! 283: struct tme_sun_mmu_pte *pte; ! 284: ! 285: /* lookup this address: */ ! 286: mmu = (struct tme_sun_mmu *) _mmu; ! 287: segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte); ! 288: ! 289: /* if the old segment is valid, invalidate all TLB entries that ! 290: are affected by changes to this PMEG - losing a spot in the ! 291: segment map counts as such a change: */ ! 292: if ( ! 293: #if 0 ! 294: mmu->tme_sun_mmu_segment_map[segment_map_index] ! 295: != mmu->tme_sun_mmu_seginv ! 296: #else ! 297: TRUE ! 298: #endif ! 299: ) { ! 300: _tme_sun_mmu_pmeg_invalidate(mmu, segment_map_index); ! 301: } ! 302: ! 303: /* set the new segment: */ ! 304: mmu->tme_sun_mmu_segment_map[segment_map_index] = pmeg; ! 305: tme_log(&mmu->tme_sun_mmu_element->tme_element_log_handle, 1000, TME_OK, ! 306: (&mmu->tme_sun_mmu_element->tme_element_log_handle, ! 307: "segmap_set: SEGMAP[%d:0x%08x] <- 0x%04x", ! 308: context, ! 309: address, ! 310: pmeg)); ! 311: } ! 312: ! 313: /* this fills a TLB entry: */ ! 314: unsigned short ! 315: tme_sun_mmu_tlb_fill(void *_mmu, struct tme_bus_tlb *tlb, ! 316: tme_uint8_t context, tme_uint32_t address, unsigned short access) ! 317: { ! 318: struct tme_sun_mmu *mmu; ! 319: unsigned short segment_map_index; ! 320: struct tme_sun_mmu_pte *pte; ! 321: tme_bus_addr_t addr_first, addr_last; ! 322: unsigned short protection, protection_other, tlb_valid_for; ! 323: tme_uint32_t physical_address; ! 324: struct tme_sun_mmu_pmeg *pmeg; ! 325: struct tme_bus_tlb tlb_virtual, *tlb_old; ! 326: int tlb_i; ! 327: ! 328: /* the access must be a read or write by the system or user: */ ! 329: assert(access != 0 ! 330: && (access == TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO) ! 331: || access == TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) ! 332: || access == TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO) ! 333: || access == TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW))); ! 334: ! 335: /* lookup this address: */ ! 336: mmu = (struct tme_sun_mmu *) _mmu; ! 337: segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte); ! 338: addr_first = (address & ~(TME_BIT(mmu->tme_sun_mmu_pgoffset_bits) - 1)); ! 339: addr_last = (address | (TME_BIT(mmu->tme_sun_mmu_pgoffset_bits) - 1)); ! 340: ! 341: /* remember this TLB entry in the PMEG: */ ! 342: pmeg = mmu->tme_sun_mmu_pmegs + mmu->tme_sun_mmu_segment_map[segment_map_index]; ! 343: tlb_i = pmeg->tme_sun_mmu_pmeg_tlbs_head; ! 344: tlb_old = pmeg->tme_sun_mmu_pmeg_tlbs[tlb_i]; ! 345: if (tlb_old != NULL) { ! 346: tme_bus_tlb_invalidate(tlb_old); ! 347: } ! 348: pmeg->tme_sun_mmu_pmeg_tlbs[tlb_i] = tlb; ! 349: pmeg->tme_sun_mmu_pmeg_tlbs_head = (tlb_i + 1) & (TME_SUN_MMU_PMEG_TLBS - 1); ! 350: ! 351: /* if this page is invalid, return the page-invalid cycle handler, ! 352: which is valid for reading and writing for the user and system: */ ! 353: if (!(pte->tme_sun_mmu_pte_flags & TME_SUN_MMU_PTE_VALID)) { ! 354: tme_bus_tlb_initialize(tlb); ! 355: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, addr_first); ! 356: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, addr_last); ! 357: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 358: tlb->tme_bus_tlb_cycle_private = mmu->tme_sun_mmu_info.tme_sun_mmu_info_invalid_private; ! 359: tlb->tme_bus_tlb_cycle = mmu->tme_sun_mmu_info.tme_sun_mmu_info_invalid; ! 360: return (TME_SUN_MMU_TLB_SYSTEM | TME_SUN_MMU_TLB_USER); ! 361: } ! 362: ! 363: /* otherwise, this page is valid. get the relevant part of the ! 364: protection for this accessor (system or user), the part of the ! 365: protection covering the other accessor (system or user), adjust ! 366: "access" to be an unshifted TME_SUN_MMU_PTE_PROT_ value, and get ! 367: the accessor (user or system) that this TLB entry will definitely ! 368: be valid for: */ ! 369: protection = pte->tme_sun_mmu_pte_flags; ! 370: if (access & TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_MASK)) { ! 371: protection_other = protection / TME_SUN_MMU_PTE_PROT_USER(1); ! 372: access /= TME_SUN_MMU_PTE_PROT_SYSTEM(1); ! 373: protection /= TME_SUN_MMU_PTE_PROT_SYSTEM(1); ! 374: tlb_valid_for = TME_SUN_MMU_TLB_SYSTEM; ! 375: } ! 376: else { ! 377: protection_other = protection / TME_SUN_MMU_PTE_PROT_SYSTEM(1); ! 378: access /= TME_SUN_MMU_PTE_PROT_USER(1); ! 379: protection /= TME_SUN_MMU_PTE_PROT_USER(1); ! 380: tlb_valid_for = TME_SUN_MMU_TLB_USER; ! 381: } ! 382: ! 383: /* NB that the following code assumes a particular ordering of ! 384: TME_SUN_MMU_PTE_PROT_ values. specifically, it assumes that ! 385: ABORT < ERROR < RO < RW: */ ! 386: ! 387: /* if the part of the protection covering the other accessor (system ! 388: or user) allows at least as much access as the relevant part of ! 389: the protection, this TLB entry will be valid for that other ! 390: successor as well. we rely on particular definitions of the ! 391: TME_SUN_MMU_TLB_ macros to make this fast: */ ! 392: #if (3 - TME_SUN_MMU_TLB_SYSTEM) != TME_SUN_MMU_TLB_USER ! 393: #error "TME_SUN_MMU_TLB_USER and TME_SUN_MMU_TLB_SYSTEM are incompatible" ! 394: #endif ! 395: protection &= TME_SUN_MMU_PTE_PROT_MASK; ! 396: protection_other &= TME_SUN_MMU_PTE_PROT_MASK; ! 397: if (protection_other >= protection) { ! 398: tlb_valid_for |= (3 - tlb_valid_for); ! 399: } ! 400: ! 401: /* if the access is protected, return the protection-error cycle ! 402: handler: */ ! 403: if (protection < access) { ! 404: if (protection == TME_SUN_MMU_PTE_PROT_ABORT) { ! 405: abort(); ! 406: } ! 407: tme_bus_tlb_initialize(tlb); ! 408: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, addr_first); ! 409: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, addr_last); ! 410: tlb->tme_bus_tlb_cycles_ok = (TME_BUS_CYCLE_WRITE ! 411: | (protection == TME_SUN_MMU_PTE_PROT_ERROR ! 412: ? TME_BUS_CYCLE_READ ! 413: : 0)); ! 414: tlb->tme_bus_tlb_cycle_private = mmu->tme_sun_mmu_info.tme_sun_mmu_info_proterr_private; ! 415: tlb->tme_bus_tlb_cycle = mmu->tme_sun_mmu_info.tme_sun_mmu_info_proterr; ! 416: return (tlb_valid_for); ! 417: } ! 418: ! 419: /* this access is OK. fill the TLB with physical bus information. ! 420: we pass in the virtual address as the initial physical address ! 421: because sometimes the virtual part of the address can influence ! 422: the physical address (as in the Sun-2 PROM mapping): */ ! 423: physical_address = address; ! 424: (*mmu->_tme_sun_mmu_tlb_fill) ! 425: (mmu->_tme_sun_mmu_tlb_fill_private, ! 426: tlb, ! 427: pte, ! 428: &physical_address, ! 429: ((access == TME_SUN_MMU_PTE_PROT_RW) ! 430: ? TME_BUS_CYCLE_WRITE ! 431: : TME_BUS_CYCLE_READ)); ! 432: ! 433: /* create the mapping TLB entry, and update the PTE flags: */ ! 434: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_virtual.tme_bus_tlb_addr_first, addr_first); ! 435: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_virtual.tme_bus_tlb_addr_last, addr_last); ! 436: pte->tme_sun_mmu_pte_flags |= TME_SUN_MMU_PTE_REF; ! 437: tlb_virtual.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ; ! 438: if (access == TME_SUN_MMU_PTE_PROT_RW) { ! 439: pte->tme_sun_mmu_pte_flags |= TME_SUN_MMU_PTE_MOD; ! 440: } ! 441: if (pte->tme_sun_mmu_pte_flags & TME_SUN_MMU_PTE_MOD) { ! 442: tlb_virtual.tme_bus_tlb_cycles_ok |= TME_BUS_CYCLE_WRITE; ! 443: } ! 444: ! 445: /* map the filled TLB entry: */ ! 446: tme_bus_tlb_map(tlb, physical_address, &tlb_virtual, address); ! 447: ! 448: /* return who this TLB entry is good for: */ ! 449: return (tlb_valid_for); ! 450: } ! 451: ! 452: /* this invalidates all TLB entries in all TLB sets: */ ! 453: void ! 454: tme_sun_mmu_tlbs_invalidate(void *_mmu) ! 455: { ! 456: struct tme_sun_mmu *mmu; ! 457: struct tme_sun_mmu_tlb_set *tlb_set; ! 458: struct tme_bus_tlb *tlb; ! 459: unsigned long tlb_i; ! 460: ! 461: /* recover our MMU: */ ! 462: mmu = (struct tme_sun_mmu *) _mmu; ! 463: ! 464: /* invalidate all TLB entries in all sets: */ ! 465: for (tlb_set = mmu->tme_sun_mmu_tlb_sets; ! 466: tlb_set != NULL; ! 467: tlb_set = tlb_set->tme_sun_mmu_tlb_set_next) { ! 468: tlb = tlb_set->tme_sun_mmu_tlb_set_base; ! 469: tlb_i = ((unsigned long) tlb_set->tme_sun_mmu_tlb_set_count) * mmu->tme_sun_mmu_contexts; ! 470: for (; tlb_i-- > 0; ) { ! 471: tme_bus_tlb_invalidate(tlb); ! 472: tlb = (struct tme_bus_tlb *) (((tme_uint8_t *) tlb) + tlb_set->tme_sun_mmu_tlb_set_sizeof_one); ! 473: } ! 474: } ! 475: } ! 476: ! 477: /* this sets the user context register: */ ! 478: void ! 479: tme_sun_mmu_tlbs_context_set(void *_mmu, tme_uint8_t context) ! 480: { ! 481: struct tme_sun_mmu *mmu; ! 482: struct tme_sun_mmu_tlb_set *tlb_set; ! 483: ! 484: /* recover our MMU: */ ! 485: mmu = (struct tme_sun_mmu *) _mmu; ! 486: ! 487: /* we have to update each TLB set to reflect the context change: */ ! 488: for (tlb_set = mmu->tme_sun_mmu_tlb_sets; ! 489: tlb_set != NULL; ! 490: tlb_set = tlb_set->tme_sun_mmu_tlb_set_next) { ! 491: TME_ATOMIC_WRITE(struct tme_bus_tlb *, ! 492: *tlb_set->tme_sun_mmu_tlb_set_pointer, ! 493: (struct tme_bus_tlb *) ! 494: (((tme_uint8_t *) tlb_set->tme_sun_mmu_tlb_set_base) ! 495: + (((unsigned long) tlb_set->tme_sun_mmu_tlb_set_count) ! 496: * tlb_set->tme_sun_mmu_tlb_set_sizeof_one ! 497: * context))); ! 498: } ! 499: } ! 500: ! 501: /* this allocates a new TLB set: */ ! 502: int ! 503: tme_sun_mmu_tlb_set_allocate(void *_mmu, ! 504: unsigned int count, unsigned int sizeof_one, ! 505: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb **) _tlbs) ! 506: { ! 507: struct tme_sun_mmu *mmu; ! 508: struct tme_bus_tlb *tlbs, *tlb; ! 509: unsigned long tlb_i; ! 510: struct tme_sun_mmu_tlb_set *tlb_set; ! 511: ! 512: /* recover our mmu: */ ! 513: mmu = (struct tme_sun_mmu *) _mmu; ! 514: ! 515: /* allocate and initialize a set of TLBs: */ ! 516: tlb_i = ((unsigned long) mmu->tme_sun_mmu_contexts) * count; ! 517: tlbs = (struct tme_bus_tlb *) tme_malloc(tlb_i * sizeof_one); ! 518: tlb = tlbs; ! 519: for (; tlb_i-- > 0; ) { ! 520: tme_bus_tlb_invalidate(tlb); ! 521: tlb = (struct tme_bus_tlb *) (((tme_uint8_t *) tlb) + sizeof_one); ! 522: } ! 523: ! 524: /* remember this set: */ ! 525: tlb_set = tme_new0(struct tme_sun_mmu_tlb_set, 1); ! 526: tlb_set->tme_sun_mmu_tlb_set_next = mmu->tme_sun_mmu_tlb_sets; ! 527: tlb_set->tme_sun_mmu_tlb_set_pointer = _tlbs; ! 528: tlb_set->tme_sun_mmu_tlb_set_base = tlbs; ! 529: tlb_set->tme_sun_mmu_tlb_set_sizeof_one = sizeof_one; ! 530: tlb_set->tme_sun_mmu_tlb_set_count = count; ! 531: mmu->tme_sun_mmu_tlb_sets = tlb_set; ! 532: ! 533: TME_ATOMIC_WRITE(struct tme_bus_tlb *, *_tlbs, tlbs); ! 534: return (TME_OK); ! 535: } ! 536:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.