|
|
1.1 ! root 1: /* $Id: sun2-mmu.c,v 1.7 2003/05/16 21:48:13 fredette Exp $ */ ! 2: ! 3: /* machine/sun2/sun2-mmu.c - implementation of Sun 2 MMU emulation: */ ! 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: sun2-mmu.c,v 1.7 2003/05/16 21:48:13 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include "sun2-impl.h" ! 41: ! 42: /* macros: */ ! 43: ! 44: /* real PTE entry bits: */ ! 45: #define TME_SUN2_PTE_VALID 0x80000000 ! 46: #define TME_SUN2_PTE_PROT 0x7C000000 ! 47: #define TME_SUN2_PTE_FOD 0x02000000 ! 48: #define TME_SUN2_PTE_PGTYPE 0x00C00000 ! 49: #define TME_SUN2_PTE_PGTYPE_MASK 0x00000003 ! 50: #define TME_SUN2_PTE_REF 0x00200000 ! 51: #define TME_SUN2_PTE_MOD 0x00100000 ! 52: #define TME_SUN2_PTE_PGFRAME 0x00000FFF ! 53: ! 54: /* real PTE page types: */ ! 55: #define TME_SUN2_PGTYPE_OBMEM (0) ! 56: #define TME_SUN2_PGTYPE_OBIO (1) ! 57: #define TME_SUN2_PGTYPE_MBMEM (2) ! 58: #define TME_SUN2_PGTYPE_VME0 (2) ! 59: #define TME_SUN2_PGTYPE_MBIO (3) ! 60: #define TME_SUN2_PGTYPE_VME8 (3) ! 61: ! 62: /* real bus error register bits: */ ! 63: #define TME_SUN2_BUSERR_PARERR_L TME_BIT(0) /* parity error, lower byte */ ! 64: #define TME_SUN2_BUSERR_PARERR_U TME_BIT(1) /* parity error, upper byte */ ! 65: #define TME_SUN2_BUSERR_TIMEOUT TME_BIT(2) /* bus access timed out */ ! 66: #define TME_SUN2_BUSERR_PROTERR TME_BIT(3) /* protection error */ ! 67: #define TME_SUN2_BUSERR_VMEBUSERR TME_BIT(6) /* bus error signaled on VMEbus */ ! 68: #define TME_SUN2_BUSERR_VALID TME_BIT(7) /* page map was valid */ ! 69: ! 70: /* this logs a bus error: */ ! 71: #ifndef TME_NO_LOG ! 72: static void ! 73: _tme_sun2_bus_fault_log(struct tme_sun2 *sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle) ! 74: { ! 75: tme_bus_addr_t virtual_address; ! 76: struct tme_sun_mmu_pte pte; ! 77: tme_uint32_t pte_sun2; ! 78: const char *bus_name; ! 79: tme_bus_addr_t physical_address; ! 80: int rc; ! 81: ! 82: /* recover the virtual address used: */ ! 83: virtual_address = cycle->tme_bus_cycle_address - tlb->tme_bus_tlb_addr_offset; ! 84: ! 85: /* look up the PTE involved. since this is a real bus error, and ! 86: not a protection violation or page not present bus error, we ! 87: assume the system context: */ ! 88: rc = tme_sun_mmu_pte_get(sun2->tme_sun2_mmu, ! 89: sun2->tme_sun2_context_system, ! 90: virtual_address, ! 91: &pte); ! 92: assert(rc == TME_OK); ! 93: pte_sun2 = pte.tme_sun_mmu_pte_raw; ! 94: ! 95: /* form the physical address and get the bus name: */ ! 96: physical_address = (((pte_sun2 & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2) ! 97: | (virtual_address & (TME_SUN2_PAGE_SIZE - 1))); ! 98: switch ((pte_sun2 & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK)) { ! 99: case TME_SUN2_PGTYPE_OBMEM: bus_name = "obmem"; break; ! 100: case TME_SUN2_PGTYPE_OBIO: bus_name = "obio"; break; ! 101: case TME_SUN2_PGTYPE_MBMEM: ! 102: if (sun2->tme_sun2_has_vme) { ! 103: bus_name = "VME"; ! 104: } ! 105: else { ! 106: bus_name = "mbmem"; ! 107: } ! 108: break; ! 109: case TME_SUN2_PGTYPE_MBIO: ! 110: if (sun2->tme_sun2_has_vme) { ! 111: bus_name = "VME"; ! 112: physical_address |= 0x800000; ! 113: } ! 114: else { ! 115: bus_name = "mbio"; ! 116: } ! 117: break; ! 118: } ! 119: ! 120: /* log this bus error: */ ! 121: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, ! 122: (TME_SUN2_LOG_HANDLE(sun2), ! 123: _("%s bus error, physical 0x%08x, virtual 0x%08x, buserr = 0x%02x"), ! 124: bus_name, ! 125: physical_address, ! 126: virtual_address, ! 127: sun2->tme_sun2_buserr)); ! 128: } ! 129: #else /* TME_NO_LOG */ ! 130: #define _tme_sun2_bus_fault_log(a, b, c) do { } while (/* CONSTCOND */ 0) ! 131: #endif /* TME_NO_LOG */ ! 132: ! 133: /* our general bus fault handler: */ ! 134: static int ! 135: _tme_sun2_bus_fault_handler(struct tme_sun2 *sun2, ! 136: struct tme_bus_tlb *tlb, ! 137: struct tme_bus_cycle *cycle, ! 138: int rc) ! 139: { ! 140: tme_uint16_t buserr; ! 141: ! 142: /* dispatch on our fault code: */ ! 143: switch (rc) { ! 144: ! 145: /* bus address nonexistent: */ ! 146: case ENOENT: ! 147: buserr = TME_SUN2_BUSERR_VALID | TME_SUN2_BUSERR_TIMEOUT; ! 148: break; ! 149: ! 150: /* anything else is just a fault: */ ! 151: default: ! 152: buserr = TME_SUN2_BUSERR_VALID; ! 153: break; ! 154: } ! 155: ! 156: /* set the bus error register: */ ! 157: sun2->tme_sun2_buserr = buserr; ! 158: ! 159: /* log the fault: */ ! 160: _tme_sun2_bus_fault_log(sun2, tlb, cycle); ! 161: ! 162: return (rc); ! 163: } ! 164: ! 165: /* our obio bus fault handler: */ ! 166: static int ! 167: _tme_sun2_obio_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) ! 168: { ! 169: tme_uint8_t all_bits_one[sizeof(tme_uint16_t)]; ! 170: ! 171: /* the sun2 obio bus doesn't generate bus errors, it just reads ! 172: all-bits-one: */ ! 173: memset(all_bits_one, 0xff, sizeof(all_bits_one)); ! 174: tme_bus_cycle_xfer_memory(cycle, ! 175: &all_bits_one[0] - cycle->tme_bus_cycle_address, ! 176: cycle->tme_bus_cycle_address + sizeof(all_bits_one)); ! 177: return (TME_OK); ! 178: } ! 179: ! 180: /* our obmem bus fault handler: */ ! 181: static int ! 182: _tme_sun2_obmem_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) ! 183: { ! 184: tme_uint8_t all_bits_one[sizeof(tme_uint16_t)]; ! 185: ! 186: /* the sun2 obmem bus apparently doesn't generate bus errors below ! 187: 0x700000, and instead just reads all-bits-one: */ ! 188: if (cycle->tme_bus_cycle_address < 0x700000) { ! 189: memset(all_bits_one, 0xff, sizeof(all_bits_one)); ! 190: tme_bus_cycle_xfer_memory(cycle, ! 191: &all_bits_one[0] - cycle->tme_bus_cycle_address, ! 192: cycle->tme_bus_cycle_address + sizeof(all_bits_one)); ! 193: return (TME_OK); ! 194: } ! 195: ! 196: /* call the common bus fault handler: */ ! 197: return (_tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc)); ! 198: } ! 199: ! 200: /* our Multibus fault handler: */ ! 201: static int ! 202: _tme_sun2_multibus_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) ! 203: { ! 204: ! 205: /* call the common bus fault handler: */ ! 206: return (_tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc)); ! 207: } ! 208: ! 209: /* our VMEbus fault handler: */ ! 210: static int ! 211: _tme_sun2_vmebus_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) ! 212: { ! 213: struct tme_sun2 *sun2; ! 214: ! 215: /* recover our sun2: */ ! 216: sun2 = (struct tme_sun2 *) _sun2; ! 217: ! 218: /* call the common bus fault handler: */ ! 219: rc = _tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc); ! 220: ! 221: /* this bus fault happened on the VMEbus: */ ! 222: sun2->tme_sun2_buserr |= TME_SUN2_BUSERR_VMEBUSERR; ! 223: ! 224: /* return the fault: */ ! 225: return (rc); ! 226: } ! 227: ! 228: /* our page-invalid cycle handler: */ ! 229: static int ! 230: _tme_sun2_mmu_invalid(void *_sun2, struct tme_bus_cycle *cycle) ! 231: { ! 232: struct tme_sun2 *sun2; ! 233: ! 234: /* recover our sun2: */ ! 235: sun2 = (struct tme_sun2 *) _sun2; ! 236: ! 237: /* log this bus error: */ ! 238: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, ! 239: (TME_SUN2_LOG_HANDLE(sun2), ! 240: _("page invalid bus error"))); ! 241: ! 242: /* set the bus error register: */ ! 243: sun2->tme_sun2_buserr = TME_SUN2_BUSERR_PROTERR; ! 244: ! 245: /* return the fault: */ ! 246: return (EFAULT); ! 247: } ! 248: ! 249: /* our protection error cycle handler: */ ! 250: static int ! 251: _tme_sun2_mmu_proterr(void *_sun2, struct tme_bus_cycle *cycle) ! 252: { ! 253: struct tme_sun2 *sun2; ! 254: ! 255: /* recover our sun2: */ ! 256: sun2 = (struct tme_sun2 *) _sun2; ! 257: ! 258: /* log this bus error: */ ! 259: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, ! 260: (TME_SUN2_LOG_HANDLE(sun2), ! 261: _("page protection bus error"))); ! 262: ! 263: /* set the bus error register: */ ! 264: sun2->tme_sun2_buserr = TME_SUN2_BUSERR_VALID | TME_SUN2_BUSERR_PROTERR; ! 265: ! 266: /* return the fault: */ ! 267: return (EFAULT); ! 268: } ! 269: ! 270: /* our m68k TLB filler: */ ! 271: int ! 272: _tme_sun2_m68k_tlb_fill(struct tme_m68k_bus_connection *conn_m68k, struct tme_m68k_tlb *tlb_m68k, ! 273: unsigned int function_code, tme_uint32_t address, unsigned int cycles) ! 274: { ! 275: struct tme_sun2 *sun2; ! 276: struct tme_bus_tlb *tlb; ! 277: unsigned short tlb_flags; ! 278: ! 279: /* recover our sun2: */ ! 280: sun2 = (struct tme_sun2 *) conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private; ! 281: ! 282: /* get the generic bus TLB: */ ! 283: tlb = &tlb_m68k->tme_m68k_tlb_bus_tlb; ! 284: ! 285: /* if this is function code three, we handle this ourselves: */ ! 286: if (function_code == TME_M68K_FC_3) { ! 287: ! 288: /* initialize the TLB entry: */ ! 289: tme_bus_tlb_initialize(tlb); ! 290: ! 291: /* we cover the entire address space: */ ! 292: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0); ! 293: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, -1); ! 294: ! 295: /* we allow reading and writing: */ ! 296: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 297: ! 298: /* our bus cycle handler: */ ! 299: tlb->tme_bus_tlb_cycle_private = sun2; ! 300: tlb->tme_bus_tlb_cycle = _tme_sun2_control_cycle_handler; ! 301: ! 302: /* this is good for function code three only: */ ! 303: tlb_m68k->tme_m68k_tlb_function_codes_mask = TME_BIT(TME_M68K_FC_3); ! 304: } ! 305: ! 306: /* if this is a supervisor function code and we're in the PROM ! 307: address range, we handle this ourselves: */ ! 308: else if ((function_code == TME_M68K_FC_SD ! 309: || function_code == TME_M68K_FC_SP) ! 310: && address >= TME_SUN2_PROM_BASE ! 311: && address < (TME_SUN2_PROM_BASE + TME_SUN2_PROM_SIZE)) { ! 312: ! 313: /* fill this TLB entry directly from the obmem bus: */ ! 314: (*sun2->tme_sun2_obmem->tme_bus_tlb_fill) ! 315: (sun2->tme_sun2_obmem, ! 316: tlb, ! 317: address, ! 318: cycles); ! 319: ! 320: /* this is good for supervisor data and supervisor program function codes: */ ! 321: tlb_m68k->tme_m68k_tlb_function_codes_mask = (TME_BIT(TME_M68K_FC_SD) ! 322: | TME_BIT(TME_M68K_FC_SP)); ! 323: } ! 324: ! 325: /* this is a normal function code: */ ! 326: else { ! 327: ! 328: /* fill this TLB entry from the MMU: */ ! 329: tlb_flags = ((function_code == TME_M68K_FC_UD ! 330: || function_code == TME_M68K_FC_UP) ! 331: ? tme_sun_mmu_tlb_fill(sun2->tme_sun2_mmu, ! 332: tlb, ! 333: sun2->tme_sun2_context_user, ! 334: address, ! 335: ((cycles & TME_BUS_CYCLE_WRITE) ! 336: ? TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW) ! 337: : TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO))) ! 338: : tme_sun_mmu_tlb_fill(sun2->tme_sun2_mmu, ! 339: tlb, ! 340: sun2->tme_sun2_context_system, ! 341: address, ! 342: ((cycles & TME_BUS_CYCLE_WRITE) ! 343: ? TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) ! 344: : TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)))); ! 345: ! 346: /* TLB entries are good only for the program and data function ! 347: codes for the user or supervisor, but never both, because ! 348: the two types of accesses go through different contexts: */ ! 349: tlb_m68k->tme_m68k_tlb_function_codes_mask = ! 350: ((function_code == TME_M68K_FC_UD ! 351: || function_code == TME_M68K_FC_UP) ! 352: ? (TME_BIT(TME_M68K_FC_UD) ! 353: | TME_BIT(TME_M68K_FC_UP)) ! 354: : (TME_BIT(TME_M68K_FC_SD) ! 355: | TME_BIT(TME_M68K_FC_SP))); ! 356: } ! 357: ! 358: return (TME_OK); ! 359: } ! 360: ! 361: /* our bus TLB filler: */ ! 362: int ! 363: _tme_sun2_bus_tlb_fill(struct tme_bus_connection *conn_bus, struct tme_bus_tlb *tlb, ! 364: tme_uint32_t address, unsigned int cycles) ! 365: { ! 366: struct tme_sun2 *sun2; ! 367: ! 368: /* recover our sun2: */ ! 369: sun2 = (struct tme_sun2 *) conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 370: ! 371: /* fill this TLB entry from the MMU: */ ! 372: tme_sun_mmu_tlb_fill(sun2->tme_sun2_mmu, ! 373: tlb, ! 374: sun2->tme_sun2_context_system, ! 375: address, ! 376: ((cycles & TME_BUS_CYCLE_WRITE) ! 377: ? TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) ! 378: : TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO))); ! 379: return (TME_OK); ! 380: } ! 381: ! 382: /* our post-MMU TLB filler: */ ! 383: static int ! 384: _tme_sun2_tlb_fill_mmu(void *_sun2, struct tme_bus_tlb *tlb, ! 385: struct tme_sun_mmu_pte *pte, ! 386: tme_uint32_t *_address, ! 387: unsigned int cycles) ! 388: { ! 389: struct tme_sun2 *sun2; ! 390: tme_uint32_t address; ! 391: unsigned int bus_type; ! 392: struct tme_bus_connection *conn_bus; ! 393: tme_bus_fault_handler bus_fault_handler; ! 394: int rc; ! 395: ! 396: /* recover our sun2: */ ! 397: sun2 = (struct tme_sun2 *) _sun2; ! 398: ! 399: /* get the physical page frame and bus type: */ ! 400: address = ((pte->tme_sun_mmu_pte_raw & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2); ! 401: bus_type = (pte->tme_sun_mmu_pte_raw & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK); ! 402: ! 403: /* any mapping of the *first* page of obio space means the PROM. ! 404: the virtual page frame is actually used to form the physical ! 405: address: */ ! 406: if (address == 0 ! 407: && bus_type == TME_SUN2_PGTYPE_OBIO) { ! 408: address = TME_SUN2_PROM_BASE | (*_address & ((TME_SUN2_PROM_SIZE - 1) & ~(TME_SUN2_PAGE_SIZE - 1))); ! 409: bus_type = TME_SUN2_PGTYPE_OBMEM; ! 410: } ! 411: ! 412: /* add in the page offset to finish the address: */ ! 413: address |= *_address & (TME_SUN2_PAGE_SIZE - 1); ! 414: *_address = address; ! 415: ! 416: /* if this is obio: */ ! 417: if (bus_type == TME_SUN2_PGTYPE_OBIO) { ! 418: conn_bus = sun2->tme_sun2_obio; ! 419: bus_fault_handler = _tme_sun2_obio_fault_handler; ! 420: } ! 421: ! 422: /* if this is obmem: */ ! 423: else if (bus_type == TME_SUN2_PGTYPE_OBMEM) { ! 424: conn_bus = sun2->tme_sun2_obmem; ! 425: bus_fault_handler = _tme_sun2_obmem_fault_handler; ! 426: } ! 427: ! 428: /* if this is the VME bus: */ ! 429: else if (sun2->tme_sun2_has_vme) { ! 430: ! 431: if (bus_type == TME_SUN2_PGTYPE_VME8) { ! 432: address |= 0x800000; ! 433: } ! 434: else { ! 435: assert(bus_type == TME_SUN2_PGTYPE_VME0); ! 436: } ! 437: ! 438: bus_fault_handler = _tme_sun2_vmebus_fault_handler; ! 439: ! 440: /* TBD: */ ! 441: abort(); ! 442: } ! 443: ! 444: /* if this is mbmem: */ ! 445: else if (bus_type == TME_SUN2_PGTYPE_MBMEM) { ! 446: conn_bus = sun2->tme_sun2_mbmem; ! 447: bus_fault_handler = _tme_sun2_multibus_fault_handler; ! 448: } ! 449: ! 450: /* otherwise, this is mbio: */ ! 451: else { ! 452: assert(bus_type == TME_SUN2_PGTYPE_MBIO); ! 453: conn_bus = sun2->tme_sun2_mbio; ! 454: bus_fault_handler = _tme_sun2_multibus_fault_handler; ! 455: } ! 456: ! 457: /* call the bus TLB filler: */ ! 458: rc = ((*conn_bus->tme_bus_tlb_fill) ! 459: (conn_bus, tlb, address, cycles)); ! 460: ! 461: /* if the bus TLB filler succeeded, add our bus fault handler: */ ! 462: if (rc == TME_OK) { ! 463: TME_BUS_TLB_FAULT_HANDLER(tlb, bus_fault_handler, sun2); ! 464: } ! 465: ! 466: return (rc); ! 467: } ! 468: ! 469: /* this gets a PTE from the MMU: */ ! 470: int ! 471: _tme_sun2_mmu_pte_get(struct tme_sun2 *sun2, tme_uint32_t address, tme_uint32_t *_pte_sun2) ! 472: { ! 473: struct tme_sun_mmu_pte pte; ! 474: tme_uint32_t pte_sun2; ! 475: unsigned int pte_flags; ! 476: int rc; ! 477: ! 478: /* get the PTE from the MMU: */ ! 479: rc = tme_sun_mmu_pte_get(sun2->tme_sun2_mmu, ! 480: sun2->tme_sun2_context_user, ! 481: address, ! 482: &pte); ! 483: assert(rc == TME_OK); ! 484: ! 485: /* form the Sun-2 PTE: */ ! 486: pte_sun2 = pte.tme_sun_mmu_pte_raw; ! 487: pte_flags = pte.tme_sun_mmu_pte_flags; ! 488: if (pte_flags & TME_SUN_MMU_PTE_REF) { ! 489: pte_sun2 |= TME_SUN2_PTE_REF; ! 490: } ! 491: if (pte_flags & TME_SUN_MMU_PTE_MOD) { ! 492: pte_sun2 |= TME_SUN2_PTE_MOD; ! 493: } ! 494: ! 495: /* done: */ ! 496: *_pte_sun2 = pte_sun2; ! 497: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, ! 498: (TME_SUN2_LOG_HANDLE(sun2), ! 499: _("pte_get: PGMAP[%d:0x%08x] -> 0x%08x"), ! 500: sun2->tme_sun2_context_user, ! 501: address, ! 502: pte_sun2)); ! 503: return (TME_OK); ! 504: } ! 505: ! 506: /* this sets a PTE into the MMU: */ ! 507: int ! 508: _tme_sun2_mmu_pte_set(struct tme_sun2 *sun2, tme_uint32_t address, tme_uint32_t pte_sun2) ! 509: { ! 510: struct tme_sun_mmu_pte pte; ! 511: unsigned int pte_flags; ! 512: #ifndef TME_NO_LOG ! 513: const char *bus_name; ! 514: tme_bus_addr_t physical_address; ! 515: ! 516: /* log this setting: */ ! 517: physical_address = ((pte_sun2 & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2); ! 518: switch ((pte_sun2 & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK)) { ! 519: case TME_SUN2_PGTYPE_OBMEM: bus_name = "obmem"; break; ! 520: case TME_SUN2_PGTYPE_OBIO: bus_name = "obio"; break; ! 521: case TME_SUN2_PGTYPE_MBMEM: ! 522: if (sun2->tme_sun2_has_vme) { ! 523: bus_name = "VME"; ! 524: } ! 525: else { ! 526: bus_name = "mbmem"; ! 527: } ! 528: break; ! 529: case TME_SUN2_PGTYPE_MBIO: ! 530: if (sun2->tme_sun2_has_vme) { ! 531: bus_name = "VME"; ! 532: physical_address |= 0x800000; ! 533: } ! 534: else { ! 535: bus_name = "mbio"; ! 536: } ! 537: break; ! 538: } ! 539: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, ! 540: (TME_SUN2_LOG_HANDLE(sun2), ! 541: _("pte_set: PGMAP[%d:0x%08x] <- 0x%08x (%s 0x%08x)"), ! 542: sun2->tme_sun2_context_user, ! 543: address, ! 544: pte_sun2, ! 545: bus_name, ! 546: physical_address)); ! 547: #endif /* !TME_NO_LOG */ ! 548: ! 549: pte.tme_sun_mmu_pte_raw = pte_sun2; ! 550: ! 551: pte_flags = 0; ! 552: if (pte_sun2 & TME_SUN2_PTE_MOD) { ! 553: pte_flags |= TME_SUN_MMU_PTE_MOD; ! 554: } ! 555: if (pte_sun2 & TME_SUN2_PTE_REF) { ! 556: pte_flags |= TME_SUN_MMU_PTE_REF; ! 557: } ! 558: switch (pte_sun2 & TME_SUN2_PTE_PROT) { ! 559: ! 560: /* with this protection, the system can read and write, ! 561: and the user gets a protection error: */ ! 562: case 0x70000000: ! 563: case 0x74000000: ! 564: case 0x60000000: ! 565: pte_flags |= ! 566: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) ! 567: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR)); ! 568: break; ! 569: ! 570: /* with this protection, the system gets a protection error, ! 571: and the user gets a protection error: */ ! 572: case 0x30000000: ! 573: case 0x20000000: ! 574: case 0x10000000: ! 575: case 0x00000000: ! 576: case 0x04000000: ! 577: pte_flags |= ! 578: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR) ! 579: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR)); ! 580: break; ! 581: ! 582: /* with this protection, the system can read and write, ! 583: and the user can read and write: */ ! 584: case 0x7C000000: ! 585: case 0x6C000000: ! 586: pte_flags |= ! 587: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) ! 588: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)); ! 589: break; ! 590: ! 591: /* with this protection, the system can read and write, ! 592: and the user can read: */ ! 593: case 0x78000000: ! 594: pte_flags |= ! 595: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) ! 596: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)); ! 597: break; ! 598: ! 599: /* with this protection, the system can read, ! 600: and the user can read: */ ! 601: case 0x58000000: ! 602: pte_flags |= ! 603: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO) ! 604: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)); ! 605: break; ! 606: ! 607: /* with this protection, the system can read, ! 608: and the user can read and write: */ ! 609: case 0x5C000000: ! 610: case 0x4C000000: ! 611: pte_flags |= ! 612: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO) ! 613: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)); ! 614: break; ! 615: ! 616: /* with this protection, the system can read, ! 617: and the user gets a protection error: */ ! 618: case 0x50000000: ! 619: case 0x40000000: ! 620: pte_flags |= ! 621: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO) ! 622: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR)); ! 623: break; ! 624: ! 625: /* with this protection, the system gets a protection error, ! 626: and the user can read and write: */ ! 627: case 0x3c000000: ! 628: pte_flags |= ! 629: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR) ! 630: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)); ! 631: break; ! 632: ! 633: /* with this protection, the system gets a protection error, ! 634: and the user can read: */ ! 635: case 0x08000000: ! 636: pte_flags |= ! 637: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR) ! 638: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)); ! 639: break; ! 640: ! 641: default: abort(); ! 642: } ! 643: if (pte_sun2 & TME_SUN2_PTE_VALID) { ! 644: pte_flags |= TME_SUN_MMU_PTE_VALID; ! 645: } ! 646: pte.tme_sun_mmu_pte_flags = pte_flags; ! 647: ! 648: return (tme_sun_mmu_pte_set(sun2->tme_sun2_mmu, ! 649: sun2->tme_sun2_context_user, ! 650: address, ! 651: &pte)); ! 652: } ! 653: ! 654: /* this is called when the system context register is set: */ ! 655: void ! 656: _tme_sun2_mmu_context_system_set(struct tme_sun2 *sun2) ! 657: { ! 658: /* system context register changes are assumed to be rare. if they ! 659: were frequent, we'd have to allocate 64 TLB sets for each TLB ! 660: user - one for each possible combination of user context and ! 661: system context. instead, when the system context register ! 662: changes, we simply invalidate all TLB entries everywhere: */ ! 663: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, ! 664: (TME_SUN2_LOG_HANDLE(sun2), ! 665: _("system context now #%d"), ! 666: sun2->tme_sun2_context_system)); ! 667: tme_sun_mmu_tlbs_invalidate(sun2->tme_sun2_mmu); ! 668: } ! 669: ! 670: /* this is called when the user context register is set: */ ! 671: void ! 672: _tme_sun2_mmu_context_user_set(struct tme_sun2 *sun2) ! 673: { ! 674: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, ! 675: (TME_SUN2_LOG_HANDLE(sun2), ! 676: _("user context now #%d"), ! 677: sun2->tme_sun2_context_user)); ! 678: tme_sun_mmu_tlbs_context_set(sun2->tme_sun2_mmu, sun2->tme_sun2_context_user); ! 679: } ! 680: ! 681: /* this allocates a new TLB set: */ ! 682: int ! 683: _tme_sun2_mmu_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker, ! 684: unsigned int count, unsigned int sizeof_one, ! 685: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb **) _tlbs) ! 686: { ! 687: struct tme_sun2 *sun2; ! 688: int rc; ! 689: ! 690: /* recover our sun2: */ ! 691: sun2 = (struct tme_sun2 *) conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private; ! 692: ! 693: /* get the MMU to allocate the TLB set: */ ! 694: rc = tme_sun_mmu_tlb_set_allocate(sun2->tme_sun2_mmu, count, sizeof_one, _tlbs); ! 695: ! 696: /* if this is the TLB set for our CPU, remember where the context ! 697: zero TLBs are, and try to reset the MMU now: */ ! 698: /* FIXME - this assumes that the *first* TLB set allocated by ! 699: the CPU is for its data: */ ! 700: if (rc == TME_OK ! 701: && conn_bus_asker->tme_bus_connection.tme_connection_type == TME_CONNECTION_BUS_M68K ! 702: && sun2->tme_sun2_reset_tlbs == NULL) { ! 703: assert(sizeof_one == sizeof(struct tme_m68k_tlb)); ! 704: sun2->tme_sun2_reset_tlbs = (struct tme_m68k_tlb *) TME_ATOMIC_READ(struct tme_bus_tlb *, *_tlbs); ! 705: sun2->tme_sun2_reset_tlb_count = count; ! 706: _tme_sun2_mmu_reset(sun2); ! 707: } ! 708: ! 709: return (rc); ! 710: } ! 711: ! 712: /* the first four 16-bit read cycles that the m68010 does after it comes ! 713: out of reset are to fetch the reset vector (one 32-bit word for the ! 714: initial SSP, one 32-bit word for the initial PC). ! 715: ! 716: apparently the Sun-2 reset circuitry has some special logic that ! 717: is able to direct these read cycles to the PROM, where the reset ! 718: vector is located. we simulate this logic by forcing the CPU's ! 719: context zero TLB entries to all point to ROM for addresses 0-7, ! 720: but only for the first four cycles, after which we invalidate ! 721: all of the CPU TLB entries. */ ! 722: ! 723: /* this is a special bus cycle handling function used at reset time. ! 724: it is used only for the first four m68010 read cycles: */ ! 725: static int ! 726: _tme_sun2_reset_cycle(void *_sun2, struct tme_bus_cycle *cycle) ! 727: { ! 728: struct tme_sun2 *sun2; ! 729: int rc; ! 730: ! 731: /* recover our sun2: */ ! 732: sun2 = (struct tme_sun2 *) _sun2; ! 733: ! 734: /* this must be a 16-bit read: */ ! 735: assert(cycle->tme_bus_cycle_size == sizeof(tme_uint16_t)); ! 736: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, ! 737: (TME_SUN2_LOG_HANDLE(sun2), ! 738: _("reset cycle #%d"), ! 739: sun2->tme_sun2_reset_cycles)); ! 740: ! 741: /* run the real cycle: */ ! 742: rc = ((*sun2->tme_sun2_reset_cycle) ! 743: (sun2->tme_sun2_reset_cycle_private, ! 744: cycle)); ! 745: ! 746: /* after the fourth read cycle, invalidate all of the TLBs ! 747: that the CPU holds, ending these abnormal reset reads: */ ! 748: if (rc == TME_OK) { ! 749: sun2->tme_sun2_reset_cycles++; ! 750: if (sun2->tme_sun2_reset_cycles == 4) { ! 751: tme_sun_mmu_tlbs_invalidate(sun2->tme_sun2_mmu); ! 752: } ! 753: } ! 754: ! 755: return (rc); ! 756: } ! 757: ! 758: /* this initialize the context zero part of the CPU's TLB set to ! 759: support four slow 16-bit reads from ROM at addresses 0, 2, 4, 6, ! 760: respectively. this emulates how the Sun-2 behaves as it comes out ! 761: of reset: */ ! 762: int ! 763: _tme_sun2_mmu_reset(struct tme_sun2 *sun2) ! 764: { ! 765: struct tme_m68k_tlb *tlb_m68k; ! 766: struct tme_bus_tlb *tlb, tlb_virtual; ! 767: unsigned long tlb_i; ! 768: ! 769: /* we can only do this initialization once we have both ! 770: the obmem bus and the CPU's TLBs: */ ! 771: tlb_m68k = sun2->tme_sun2_reset_tlbs; ! 772: if (tlb_m68k == NULL ! 773: || sun2->tme_sun2_obmem == NULL) { ! 774: return (TME_OK); ! 775: } ! 776: sun2->tme_sun2_reset_tlbs = NULL; ! 777: tlb = &tlb_m68k->tme_m68k_tlb_bus_tlb; ! 778: ! 779: /* fill the TLB entry: */ ! 780: (*sun2->tme_sun2_obmem->tme_bus_tlb_fill) ! 781: (sun2->tme_sun2_obmem, ! 782: tlb, ! 783: TME_SUN2_PROM_BASE, ! 784: TME_BUS_CYCLE_READ); ! 785: ! 786: /* map the TLB entry: */ ! 787: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_virtual.tme_bus_tlb_addr_first, 0); ! 788: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_virtual.tme_bus_tlb_addr_last, 7); ! 789: tlb_virtual.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ; ! 790: tme_bus_tlb_map(tlb, TME_SUN2_PROM_BASE, &tlb_virtual, 0); ! 791: ! 792: /* this TLB entry must allow slow reads from exactly the reset ! 793: range: */ ! 794: if (!(tlb->tme_bus_tlb_cycles_ok & TME_BUS_CYCLE_READ) ! 795: || TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first) != 0 ! 796: || TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last) != 7) { ! 797: abort(); ! 798: } ! 799: ! 800: /* take over this TLB entry: */ ! 801: sun2->tme_sun2_reset_cycles = 0; ! 802: sun2->tme_sun2_reset_cycle_private = tlb->tme_bus_tlb_cycle_private; ! 803: sun2->tme_sun2_reset_cycle = tlb->tme_bus_tlb_cycle; ! 804: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; ! 805: tlb->tme_bus_tlb_cycle_private = sun2; ! 806: tlb->tme_bus_tlb_cycle = _tme_sun2_reset_cycle; ! 807: ! 808: /* this TLB entry is usable by the supervisor: */ ! 809: tlb_m68k->tme_m68k_tlb_function_codes_mask = (TME_BIT(TME_M68K_FC_SD) ! 810: | TME_BIT(TME_M68K_FC_SP)); ! 811: ! 812: /* now copy this TLB entry into all of the others: */ ! 813: for (tlb_i = sun2->tme_sun2_reset_tlb_count - 1; tlb_i-- > 0; ) { ! 814: tlb_m68k[1] = tlb_m68k[0]; ! 815: tlb_m68k++; ! 816: } ! 817: ! 818: return (TME_OK); ! 819: } ! 820: ! 821: /* this creates a Sun-2 MMU: */ ! 822: void ! 823: _tme_sun2_mmu_new(struct tme_sun2 *sun2) ! 824: { ! 825: struct tme_sun_mmu_info mmu_info; ! 826: ! 827: mmu_info.tme_sun_mmu_info_element = sun2->tme_sun2_element; ! 828: mmu_info.tme_sun_mmu_info_address_bits = 24; ! 829: mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN2_PAGE_SIZE_LOG2; ! 830: mmu_info.tme_sun_mmu_info_pteindex_bits = 4; ! 831: mmu_info.tme_sun_mmu_info_contexts = 8; ! 832: mmu_info.tme_sun_mmu_info_pmegs = 256; ! 833: mmu_info.tme_sun_mmu_info_seginv = 255; ! 834: mmu_info.tme_sun_mmu_info_tlb_fill_private = sun2; ! 835: mmu_info.tme_sun_mmu_info_tlb_fill = _tme_sun2_tlb_fill_mmu; ! 836: mmu_info.tme_sun_mmu_info_proterr_private = sun2; ! 837: mmu_info.tme_sun_mmu_info_proterr = _tme_sun2_mmu_proterr; ! 838: mmu_info.tme_sun_mmu_info_invalid_private = sun2; ! 839: mmu_info.tme_sun_mmu_info_invalid = _tme_sun2_mmu_invalid; ! 840: sun2->tme_sun2_mmu = tme_sun_mmu_new(&mmu_info); ! 841: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.