|
|
1.1 ! root 1: /* $Id: sun3-mmu.c,v 1.3 2005/04/30 15:09:44 fredette Exp $ */ ! 2: ! 3: /* machine/sun3/sun3-mmu.c - implementation of Sun 3 MMU emulation: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2003, 2004 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: sun3-mmu.c,v 1.3 2005/04/30 15:09:44 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include "sun3-impl.h" ! 41: ! 42: /* macros: */ ! 43: ! 44: /* real PTE entry bits: */ ! 45: #define TME_SUN3_PTE_VALID (0x80000000) ! 46: #define TME_SUN3_PTE_WRITE (0x40000000) ! 47: #define TME_SUN3_PTE_SYSTEM (0x20000000) ! 48: #define TME_SUN3_PTE_NC (0x10000000) ! 49: #define TME_SUN3_PTE_PGTYPE (0x0C000000) ! 50: #define TME_SUN3_PTE_REF (0x02000000) ! 51: #define TME_SUN3_PTE_MOD (0x01000000) ! 52: #define TME_SUN3_PTE_PGFRAME (0x0007FFFF) ! 53: ! 54: /* real PTE page types: */ ! 55: #define TME_SUN3_PGTYPE_OBMEM (0) ! 56: #define TME_SUN3_PGTYPE_OBIO (1) ! 57: #define TME_SUN3_PGTYPE_VME_D16 (2) ! 58: #define TME_SUN3_PGTYPE_VME_D32 (3) ! 59: ! 60: /* real bus error register bits: */ ! 61: #define TME_SUN3_BUSERR_WATCHDOG TME_BIT(0) /* watchdog or user reset */ ! 62: /* bit 1 unused */ ! 63: #define TME_SUN3_BUSERR_FPAENERR TME_BIT(2) /* FPA enable error */ ! 64: #define TME_SUN3_BUSERR_FPABERR TME_BIT(3) /* FPA bus error */ ! 65: #define TME_SUN3_BUSERR_VMEBUSERR TME_BIT(4) /* VME bus error */ ! 66: #define TME_SUN3_BUSERR_TIMEOUT TME_BIT(5) /* timeout error */ ! 67: #define TME_SUN3_BUSERR_PROTERR TME_BIT(6) /* MMU protection error */ ! 68: #define TME_SUN3_BUSERR_INVALID TME_BIT(7) /* MMU page invalid error */ ! 69: ! 70: /* this logs a bus error: */ ! 71: #ifndef TME_NO_LOG ! 72: static void ! 73: _tme_sun3_bus_fault_log(struct tme_sun3 *sun3, 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_sun3; ! 78: const char *bus_name; ! 79: tme_bus_addr_t physical_address; ! 80: int rc; ! 81: ! 82: /* this silences gcc -Wuninitialized: */ ! 83: bus_name = NULL; ! 84: ! 85: /* recover the virtual address used: */ ! 86: virtual_address = cycle->tme_bus_cycle_address - tlb->tme_bus_tlb_addr_offset; ! 87: ! 88: /* look up the PTE involved: */ ! 89: rc = tme_sun_mmu_pte_get(sun3->tme_sun3_mmu, ! 90: sun3->tme_sun3_context, ! 91: virtual_address, ! 92: &pte); ! 93: assert(rc == TME_OK); ! 94: pte_sun3 = pte.tme_sun_mmu_pte_raw; ! 95: ! 96: /* form the physical address and get the bus name: */ ! 97: physical_address = (((pte_sun3 & TME_SUN3_PTE_PGFRAME) << TME_SUN3_PAGE_SIZE_LOG2) ! 98: | (virtual_address & (TME_SUN3_PAGE_SIZE - 1))); ! 99: switch (TME_FIELD_MASK_EXTRACTU(pte_sun3, TME_SUN3_PTE_PGTYPE)) { ! 100: case TME_SUN3_PGTYPE_OBMEM: bus_name = "obmem"; break; ! 101: case TME_SUN3_PGTYPE_OBIO: bus_name = "obio"; break; ! 102: case TME_SUN3_PGTYPE_VME_D16: ! 103: bus_name = "VME_D16"; ! 104: break; ! 105: case TME_SUN3_PGTYPE_VME_D32: ! 106: bus_name = "VME_D32"; ! 107: break; ! 108: } ! 109: ! 110: /* log this bus error: */ ! 111: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, ! 112: (TME_SUN3_LOG_HANDLE(sun3), ! 113: _("%s bus error, physical 0x%08x, virtual 0x%08x, buserr = 0x%02x"), ! 114: bus_name, ! 115: physical_address, ! 116: virtual_address, ! 117: sun3->tme_sun3_buserr)); ! 118: } ! 119: #else /* TME_NO_LOG */ ! 120: #define _tme_sun3_bus_fault_log(a, b, c) do { } while (/* CONSTCOND */ 0) ! 121: #endif /* TME_NO_LOG */ ! 122: ! 123: /* our general bus fault handler: */ ! 124: static int ! 125: _tme_sun3_bus_fault_handler(struct tme_sun3 *sun3, ! 126: struct tme_bus_tlb *tlb, ! 127: struct tme_bus_cycle *cycle, ! 128: int rc) ! 129: { ! 130: tme_uint8_t buserr; ! 131: ! 132: /* dispatch on our fault code: */ ! 133: switch (rc) { ! 134: ! 135: /* bus address nonexistent: */ ! 136: case ENOENT: ! 137: buserr = TME_SUN3_BUSERR_TIMEOUT; ! 138: break; ! 139: ! 140: /* anything else is just a fault: */ ! 141: default: ! 142: buserr = 0; ! 143: break; ! 144: } ! 145: ! 146: /* set the bus error register: */ ! 147: sun3->tme_sun3_buserr = buserr; ! 148: ! 149: /* log the fault: */ ! 150: _tme_sun3_bus_fault_log(sun3, tlb, cycle); ! 151: ! 152: return (rc); ! 153: } ! 154: ! 155: /* our obio bus fault handler: */ ! 156: static int ! 157: _tme_sun3_obio_fault_handler(void *_sun3, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) ! 158: { ! 159: ! 160: /* call the common bus fault handler: */ ! 161: return (_tme_sun3_bus_fault_handler((struct tme_sun3 *) _sun3, tlb, cycle, rc)); ! 162: } ! 163: ! 164: /* our obmem bus fault handler: */ ! 165: static int ! 166: _tme_sun3_obmem_fault_handler(void *_sun3, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) ! 167: { ! 168: ! 169: /* call the common bus fault handler: */ ! 170: return (_tme_sun3_bus_fault_handler((struct tme_sun3 *) _sun3, tlb, cycle, rc)); ! 171: } ! 172: ! 173: /* our VMEbus fault handler: */ ! 174: static int ! 175: _tme_sun3_vmebus_fault_handler(void *_sun3, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) ! 176: { ! 177: struct tme_sun3 *sun3; ! 178: ! 179: /* recover our sun3: */ ! 180: sun3 = (struct tme_sun3 *) _sun3; ! 181: ! 182: /* call the common bus fault handler: */ ! 183: rc = _tme_sun3_bus_fault_handler((struct tme_sun3 *) _sun3, tlb, cycle, rc); ! 184: ! 185: /* this bus fault happened on the VMEbus: */ ! 186: sun3->tme_sun3_buserr |= TME_SUN3_BUSERR_VMEBUSERR; ! 187: ! 188: /* return the fault: */ ! 189: return (rc); ! 190: } ! 191: ! 192: /* our dummy cycle handler: */ ! 193: static int ! 194: _tme_sun3_cycle_dummy(void *_sun3, struct tme_bus_cycle *cycle) ! 195: { ! 196: return (TME_OK); ! 197: } ! 198: ! 199: /* our page-invalid cycle handler: */ ! 200: static int ! 201: _tme_sun3_mmu_invalid(void *_sun3, struct tme_bus_cycle *cycle) ! 202: { ! 203: struct tme_sun3 *sun3; ! 204: ! 205: /* recover our sun3: */ ! 206: sun3 = (struct tme_sun3 *) _sun3; ! 207: ! 208: /* log this bus error: */ ! 209: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, ! 210: (TME_SUN3_LOG_HANDLE(sun3), ! 211: _("page invalid bus error"))); ! 212: ! 213: /* set the bus error register: */ ! 214: sun3->tme_sun3_buserr = TME_SUN3_BUSERR_INVALID; ! 215: ! 216: /* return the fault: */ ! 217: return (EFAULT); ! 218: } ! 219: ! 220: /* our protection error cycle handler: */ ! 221: static int ! 222: _tme_sun3_mmu_proterr(void *_sun3, struct tme_bus_cycle *cycle) ! 223: { ! 224: struct tme_sun3 *sun3; ! 225: ! 226: /* recover our sun3: */ ! 227: sun3 = (struct tme_sun3 *) _sun3; ! 228: ! 229: /* log this bus error: */ ! 230: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, ! 231: (TME_SUN3_LOG_HANDLE(sun3), ! 232: _("page protection bus error"))); ! 233: ! 234: /* set the bus error register: */ ! 235: sun3->tme_sun3_buserr = TME_SUN3_BUSERR_PROTERR; ! 236: ! 237: /* return the fault: */ ! 238: return (EFAULT); ! 239: } ! 240: ! 241: /* our SDVMA disabled cycle handler: */ ! 242: static int ! 243: _tme_sun3_sdvma_disabled(void *_sun3, struct tme_bus_cycle *cycle) ! 244: { ! 245: return (ENOENT); ! 246: } ! 247: ! 248: /* our internal TLB filler: */ ! 249: static int ! 250: _tme_sun3_tlb_fill(struct tme_sun3 *sun3, struct tme_bus_tlb *tlb, tme_uint8_t context, ! 251: unsigned int *_function_code_or_codes, tme_uint32_t address, unsigned int cycles) ! 252: { ! 253: unsigned int function_code; ! 254: unsigned int function_code_sp; ! 255: unsigned short access; ! 256: struct tme_bus_tlb tlb_bus; ! 257: unsigned int tlb_i; ! 258: unsigned short tlb_flags; ! 259: ! 260: /* recover the function code: */ ! 261: function_code = *_function_code_or_codes; ! 262: ! 263: /* this must be a user or supervisor program or data function code: */ ! 264: assert(function_code == TME_M68K_FC_UD ! 265: || function_code == TME_M68K_FC_UP ! 266: || function_code == TME_M68K_FC_SD ! 267: || function_code == TME_M68K_FC_SP); ! 268: ! 269: /* assume that if this TLB entry ends up good for the supervisor, ! 270: it's good for the supervisor program function code: */ ! 271: function_code_sp = TME_BIT(TME_M68K_FC_SP); ! 272: ! 273: /* if we're in the boot state: */ ! 274: if (__tme_predict_false((sun3->tme_sun3_enable & TME_SUN3_ENA_NOTBOOT) == 0)) { ! 275: ! 276: /* if this is the supervisor program function code: */ ! 277: if (function_code == TME_M68K_FC_SP) { ! 278: ! 279: /* fill this TLB entry directly from the obmem bus: */ ! 280: (*sun3->tme_sun3_obmem->tme_bus_tlb_fill) ! 281: (sun3->tme_sun3_obmem, ! 282: tlb, ! 283: TME_SUN3_PROM_BASE | (address & (TME_SUN3_PROM_SIZE - 1)), ! 284: cycles); ! 285: ! 286: /* create the mapping TLB entry: */ ! 287: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 288: tlb_bus.tme_bus_tlb_addr_first, ! 289: address & (((tme_bus_addr_t) 0) - TME_SUN3_PROM_SIZE)); ! 290: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 291: tlb_bus.tme_bus_tlb_addr_last, ! 292: address | (TME_SUN3_PROM_SIZE - 1)); ! 293: tlb_bus.tme_bus_tlb_cycles_ok ! 294: = TME_BUS_CYCLE_READ; ! 295: ! 296: /* map the filled TLB entry: */ ! 297: tme_bus_tlb_map(tlb, TME_SUN3_PROM_BASE | (address & (TME_SUN3_PROM_SIZE - 1)), &tlb_bus, address); ! 298: ! 299: /* this is good for the supervisor program function code only: */ ! 300: *_function_code_or_codes = TME_BIT(TME_M68K_FC_SP); ! 301: ! 302: /* done: */ ! 303: return(TME_OK); ! 304: } ! 305: ! 306: /* update the head pointer for the active boot state TLB entry ! 307: list: */ ! 308: tlb_i = sun3->tme_sun3_boot_state_tlb_next ! 309: = ((sun3->tme_sun3_boot_state_tlb_next ! 310: + 1) ! 311: & (TME_SUN3_BOOT_STATE_TLBS - 1)); ! 312: ! 313: /* if the new head pointer already has a TLB entry, and it doesn't ! 314: happen to be the same as this TLB entry, invalidate it: */ ! 315: if (sun3->tme_sun3_boot_state_tlbs[tlb_i] != NULL ! 316: && (sun3->tme_sun3_boot_state_tlbs[tlb_i] ! 317: != TME_ATOMIC_READ(struct tme_bus_tlb *, ! 318: tlb->tme_bus_tlb_backing_reservation))) { ! 319: tme_bus_tlb_invalidate(sun3->tme_sun3_boot_state_tlbs[tlb_i]); ! 320: } ! 321: ! 322: /* add this TLB entry to the active list: */ ! 323: sun3->tme_sun3_boot_state_tlbs[tlb_i] = ! 324: TME_ATOMIC_READ(struct tme_bus_tlb *, ! 325: tlb->tme_bus_tlb_backing_reservation); ! 326: ! 327: /* if this TLB entry ends up good for the supervisor, it's not ! 328: good for the supervisor program function code: */ ! 329: function_code_sp = 0; ! 330: } ! 331: ! 332: /* fill this TLB entry from the MMU: */ ! 333: access ! 334: = ((cycles & TME_BUS_CYCLE_WRITE) ! 335: ? TME_SUN_MMU_PTE_PROT_RW ! 336: : TME_SUN_MMU_PTE_PROT_RO); ! 337: access ! 338: = ((function_code == TME_M68K_FC_UD ! 339: || function_code == TME_M68K_FC_UP) ! 340: ? TME_SUN_MMU_PTE_PROT_USER(access) ! 341: : TME_SUN_MMU_PTE_PROT_SYSTEM(access)); ! 342: tlb_flags = tme_sun_mmu_tlb_fill(sun3->tme_sun3_mmu, ! 343: tlb, ! 344: context, ! 345: address, ! 346: access); ! 347: ! 348: /* this TLB entry is good for the program and data function codes ! 349: for the user and/or the supervisor: */ ! 350: *_function_code_or_codes ! 351: = (((tlb_flags & TME_SUN_MMU_TLB_USER) ! 352: ? (TME_BIT(TME_M68K_FC_UD) ! 353: | TME_BIT(TME_M68K_FC_UP)) ! 354: : 0) ! 355: | ((tlb_flags & TME_SUN_MMU_TLB_SYSTEM) ! 356: ? (TME_BIT(TME_M68K_FC_SD) ! 357: | function_code_sp) ! 358: : 0)); ! 359: ! 360: /* if the memory error register is being tested: */ ! 361: if (__tme_predict_false(sun3->tme_sun3_memerr_csr & TME_SUN3_MEMERR_PAR_TEST)) { ! 362: ! 363: /* this must be a supervisor data access: */ ! 364: if (function_code != TME_M68K_FC_SD) { ! 365: abort(); ! 366: } ! 367: ! 368: /* if this TLB's bus cycle handler isn't for the memory error ! 369: register itself: */ ! 370: if (tlb->tme_bus_tlb_cycle != _tme_sun3_memerr_cycle_handler) { ! 371: ! 372: /* there must be no other TLB entry already involved in the test: */ ! 373: if (sun3->tme_sun3_memerr_tlb != NULL) { ! 374: abort(); ! 375: } ! 376: ! 377: /* remember this TLB entry pointer, and its original bus cycle ! 378: handler: */ ! 379: sun3->tme_sun3_memerr_tlb = TME_ATOMIC_READ(struct tme_bus_tlb *, ! 380: tlb->tme_bus_tlb_backing_reservation); ! 381: assert (sun3->tme_sun3_memerr_tlb != NULL); ! 382: sun3->tme_sun3_memerr_cycle_private = tlb->tme_bus_tlb_cycle_private; ! 383: sun3->tme_sun3_memerr_cycle = tlb->tme_bus_tlb_cycle; ! 384: ! 385: /* this TLB entry does not allow fast reading and writing, and ! 386: it now uses the memory error test cycle handler: */ ! 387: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; ! 388: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; ! 389: tlb->tme_bus_tlb_rwlock = NULL; ! 390: tlb->tme_bus_tlb_cycle_private = sun3; ! 391: tlb->tme_bus_tlb_cycle = _tme_sun3_memerr_test_cycle_handler; ! 392: ! 393: /* reset other memory error test values: */ ! 394: sun3->tme_sun3_memerr_pending_csr = 0; ! 395: } ! 396: } ! 397: ! 398: return (TME_OK); ! 399: } ! 400: ! 401: /* our m68k TLB filler: */ ! 402: int ! 403: _tme_sun3_m68k_tlb_fill(struct tme_m68k_bus_connection *conn_m68k, struct tme_m68k_tlb *tlb_m68k, ! 404: unsigned int function_code, tme_uint32_t address, unsigned int cycles) ! 405: { ! 406: struct tme_sun3 *sun3; ! 407: struct tme_bus_tlb *tlb; ! 408: struct tme_bus_tlb tlb_bus; ! 409: ! 410: /* recover our sun3: */ ! 411: sun3 = (struct tme_sun3 *) conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private; ! 412: ! 413: /* get the generic bus TLB: */ ! 414: tlb = &tlb_m68k->tme_m68k_tlb_bus_tlb; ! 415: ! 416: /* if this is function code three: */ ! 417: if (function_code == TME_M68K_FC_3) { ! 418: ! 419: /* if this address is within the UART bypass: */ ! 420: if (address >= TME_SUN3_CONTROL_UART_BYPASS ! 421: && address < TME_SUN3_CONTROL_UART_BYPASS + TME_SUN_Z8530_SIZE) { ! 422: ! 423: /* fill this TLB entry directly from the obio bus: */ ! 424: (*sun3->tme_sun3_obio->tme_bus_tlb_fill) ! 425: (sun3->tme_sun3_obio, ! 426: tlb, ! 427: (address - TME_SUN3_CONTROL_UART_BYPASS) + TME_SUN3_OBIO_ZS0, ! 428: cycles); ! 429: ! 430: /* create the mapping TLB entry: */ ! 431: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 432: tlb_bus.tme_bus_tlb_addr_first, ! 433: TME_SUN3_CONTROL_UART_BYPASS); ! 434: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 435: tlb_bus.tme_bus_tlb_addr_last, ! 436: TME_SUN3_CONTROL_UART_BYPASS + TME_SUN_Z8530_SIZE - 1); ! 437: tlb_bus.tme_bus_tlb_cycles_ok ! 438: = (TME_BUS_CYCLE_READ ! 439: | TME_BUS_CYCLE_WRITE); ! 440: ! 441: /* map the filled TLB entry: */ ! 442: tme_bus_tlb_map(tlb, (address - TME_SUN3_CONTROL_UART_BYPASS) + TME_SUN3_OBIO_ZS0, &tlb_bus, address); ! 443: } ! 444: ! 445: /* otherwise, this is something else in control space: */ ! 446: else { ! 447: ! 448: /* initialize the TLB entry: */ ! 449: tme_bus_tlb_initialize(tlb); ! 450: ! 451: /* we cover the entire address space up to the UART bypass: */ ! 452: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0); ! 453: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_SUN3_CONTROL_UART_BYPASS - 1); ! 454: ! 455: /* we allow reading and writing: */ ! 456: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 457: ! 458: /* our bus cycle handler: */ ! 459: tlb->tme_bus_tlb_cycle_private = sun3; ! 460: tlb->tme_bus_tlb_cycle = _tme_sun3_control_cycle_handler; ! 461: } ! 462: ! 463: /* this is good for function code three only: */ ! 464: tlb_m68k->tme_m68k_tlb_function_codes_mask = TME_BIT(TME_M68K_FC_3); ! 465: ! 466: /* done: */ ! 467: return (TME_OK); ! 468: } ! 469: ! 470: /* this is a normal function code: */ ! 471: tlb_m68k->tme_m68k_tlb_function_codes_mask = function_code; ! 472: return (_tme_sun3_tlb_fill(sun3, tlb, sun3->tme_sun3_context, ! 473: &tlb_m68k->tme_m68k_tlb_function_codes_mask, ! 474: address, cycles)); ! 475: } ! 476: ! 477: /* our bus TLB filler: */ ! 478: int ! 479: _tme_sun3_bus_tlb_fill(struct tme_bus_connection *conn_bus, struct tme_bus_tlb *tlb, ! 480: tme_uint32_t address, unsigned int cycles) ! 481: { ! 482: struct tme_sun3 *sun3; ! 483: struct tme_sun3_bus_connection *conn_sun3; ! 484: tme_uint32_t base, size; ! 485: struct tme_bus_tlb tlb_bus; ! 486: tme_uint8_t context; ! 487: unsigned int function_code_or_codes; ! 488: unsigned int tlb_i; ! 489: ! 490: /* recover our sun3: */ ! 491: sun3 = (struct tme_sun3 *) conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 492: ! 493: /* recover the sun3 internal mainbus connection: */ ! 494: conn_sun3 = (struct tme_sun3_bus_connection *) conn_bus; ! 495: ! 496: /* dispatch on the internal connection. the bus address into a DVMA ! 497: address, context, and function code, except for the memory error ! 498: register and interrupt register connections, which are handled ! 499: specially: */ ! 500: switch (conn_sun3->tme_sun3_bus_connection_which) { ! 501: ! 502: case TME_SUN3_CONN_OBIO_MASTER: ! 503: base = 0x0f000000; ! 504: size = TME_SUN3_DVMA_SIZE_OBIO; ! 505: context = sun3->tme_sun3_context; ! 506: function_code_or_codes = TME_M68K_FC_SD; ! 507: break; ! 508: ! 509: case TME_SUN3_CONN_BUS_VME: ! 510: base = 0x0ff00000; ! 511: size = TME_SUN3_DVMA_SIZE_VME; ! 512: context = sun3->tme_sun3_context; ! 513: function_code_or_codes = TME_M68K_FC_SD; ! 514: break; ! 515: ! 516: case TME_SUN3_CONN_REG_MEMERR: ! 517: case TME_SUN3_CONN_REG_INTREG: ! 518: ! 519: /* initialize the TLB entry: */ ! 520: tme_bus_tlb_initialize(tlb); ! 521: ! 522: /* the address range: */ ! 523: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0); ! 524: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, ! 525: ((conn_sun3->tme_sun3_bus_connection_which == TME_SUN3_CONN_REG_MEMERR ! 526: ? TME_SUN3_MEMERR_SIZ_REG ! 527: : sizeof(sun3->tme_sun3_ints)) ! 528: - 1)); ! 529: ! 530: /* we allow reading and writing: */ ! 531: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 532: ! 533: /* our bus cycle handler: */ ! 534: tlb->tme_bus_tlb_cycle_private = sun3; ! 535: tlb->tme_bus_tlb_cycle ! 536: = (conn_sun3->tme_sun3_bus_connection_which == TME_SUN3_CONN_REG_MEMERR ! 537: ? _tme_sun3_memerr_cycle_handler ! 538: : _tme_sun3_intreg_cycle_handler); ! 539: ! 540: /* done: */ ! 541: return (TME_OK); ! 542: ! 543: default: abort(); ! 544: } ! 545: ! 546: /* update the head pointer for the active SDVMA TLB entry list: */ ! 547: tlb_i = sun3->tme_sun3_sdvma_tlb_next ! 548: = ((sun3->tme_sun3_sdvma_tlb_next ! 549: + 1) ! 550: & (TME_SUN3_SDVMA_TLBS - 1)); ! 551: ! 552: /* if the new head pointer already has a TLB entry, and it doesn't ! 553: happen to be the same as this TLB entry, invalidate it: */ ! 554: if (sun3->tme_sun3_sdvma_tlbs[tlb_i] != NULL ! 555: && (sun3->tme_sun3_sdvma_tlbs[tlb_i] ! 556: != TME_ATOMIC_READ(struct tme_bus_tlb *, ! 557: tlb->tme_bus_tlb_backing_reservation))) { ! 558: tme_bus_tlb_invalidate(sun3->tme_sun3_sdvma_tlbs[tlb_i]); ! 559: } ! 560: ! 561: /* add this TLB entry to the active list: */ ! 562: sun3->tme_sun3_sdvma_tlbs[tlb_i] = ! 563: TME_ATOMIC_READ(struct tme_bus_tlb *, ! 564: tlb->tme_bus_tlb_backing_reservation); ! 565: ! 566: /* if system DVMA is disabled: */ ! 567: if (__tme_predict_false(!(sun3->tme_sun3_enable & TME_SUN3_ENA_SDVMA))) { ! 568: ! 569: /* return a TLB entry that will generate a VME bus fault: */ ! 570: tme_bus_tlb_initialize(tlb); ! 571: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0); ! 572: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, size - 1); ! 573: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 574: tlb->tme_bus_tlb_cycle_private = sun3; ! 575: tlb->tme_bus_tlb_cycle = _tme_sun3_sdvma_disabled; ! 576: TME_BUS_TLB_FAULT_HANDLER(tlb, _tme_sun3_vmebus_fault_handler, sun3); ! 577: return (TME_OK); ! 578: } ! 579: ! 580: assert (!(address & base) ! 581: && (address < size)); ! 582: ! 583: /* fill this TLB entry from the MMU: */ ! 584: _tme_sun3_tlb_fill(sun3, tlb, context, ! 585: &function_code_or_codes, ! 586: address | base, cycles); ! 587: ! 588: /* create the mapping TLB entry. we do this even if base == 0, ! 589: because the TLB entry as currently filled may cover more address ! 590: space than DVMA space on this machine is supposed to cover: */ ! 591: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 592: tlb_bus.tme_bus_tlb_addr_first, ! 593: 0); ! 594: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 595: tlb_bus.tme_bus_tlb_addr_last, ! 596: size - 1); ! 597: tlb_bus.tme_bus_tlb_cycles_ok ! 598: = (TME_BUS_CYCLE_READ ! 599: | TME_BUS_CYCLE_WRITE); ! 600: ! 601: /* map the filled TLB entry: */ ! 602: tme_bus_tlb_map(tlb, address | base, &tlb_bus, address); ! 603: ! 604: /* XXX FIXME - what happens to a bus cycle to an unmapped DVMA ! 605: address? is the answer different for obio masters and the VME ! 606: bus? for now, these bus cycles get ignored in both cases: */ ! 607: if (tlb->tme_bus_tlb_cycle == _tme_sun3_mmu_invalid) { ! 608: tlb->tme_bus_tlb_cycle = _tme_sun3_cycle_dummy; ! 609: } ! 610: ! 611: return (TME_OK); ! 612: } ! 613: ! 614: /* our post-MMU TLB filler: */ ! 615: static int ! 616: _tme_sun3_tlb_fill_mmu(void *_sun3, struct tme_bus_tlb *tlb, ! 617: struct tme_sun_mmu_pte *pte, ! 618: tme_uint32_t *_address, ! 619: unsigned int cycles) ! 620: { ! 621: struct tme_sun3 *sun3; ! 622: tme_uint32_t address; ! 623: unsigned int bus_type; ! 624: struct tme_bus_connection *conn_bus; ! 625: tme_bus_fault_handler bus_fault_handler; ! 626: int rc; ! 627: ! 628: /* recover our sun3: */ ! 629: sun3 = (struct tme_sun3 *) _sun3; ! 630: ! 631: /* get the physical page frame and bus type: */ ! 632: address = ((pte->tme_sun_mmu_pte_raw & TME_SUN3_PTE_PGFRAME) << TME_SUN3_PAGE_SIZE_LOG2); ! 633: bus_type = TME_FIELD_MASK_EXTRACTU(pte->tme_sun_mmu_pte_raw, TME_SUN3_PTE_PGTYPE); ! 634: ! 635: /* any mapping of any address in a PROM-sized region starting at ! 636: 0x100000 in obio space means the PROM. the virtual page frame is ! 637: actually used to form the physical address: */ ! 638: if ((address & -TME_SUN3_PROM_SIZE) == TME_SUN3_OBIO_PROM ! 639: && bus_type == TME_SUN3_PGTYPE_OBIO) { ! 640: address = TME_SUN3_PROM_BASE | (*_address & ((TME_SUN3_PROM_SIZE - 1) & ~(TME_SUN3_PAGE_SIZE - 1))); ! 641: bus_type = TME_SUN3_PGTYPE_OBMEM; ! 642: } ! 643: ! 644: #if 1 /* NetBSD/sun3 cgtwo bug */ ! 645: /* XXX FIXME - this hack works around a bug in NetBSD/sun3, present ! 646: since revision 1.49 of src/sys/arch/sun3/conf/GENERIC (when the ! 647: sun3x port was merged into the sun3 port). in this revision, the ! 648: declaration for cgtwo0 changed: ! 649: ! 650: -cgtwo0 at vmes0 addr 0xff400000 level 4 vect 0xA8 ! 651: +cgtwo0 at vme2 addr 0x400000 ipl 4 vect 0xA8 ! 652: ! 653: because the cg2mmap() function in src/sys/arch/sun3/dev/cg2.c ! 654: doesn't add the 0xff000000 mask to the configured physical ! 655: address (needed because the cgtwo is an A24 device), when Xsun ! 656: mmap()s the cgtwo it gets a mapping of physical address 0x400000 ! 657: in VME space instead of the correct 0xff400000. the sparc cgtwo ! 658: driver gets this right. ! 659: ! 660: so for now we force all accesses to VME D16 address 0x400000 to ! 661: 0xff400000. once the NetBSD bug has been fixed this code should ! 662: be removed: */ ! 663: if (bus_type == TME_SUN3_PGTYPE_VME_D16 ! 664: && ((address & 0xff400000) == 0x400000)) { ! 665: address |= 0xff000000; ! 666: } ! 667: #endif /* NetBSD/sun3 cgtwo bug */ ! 668: ! 669: /* add in the page offset to finish the address: */ ! 670: address |= *_address & (TME_SUN3_PAGE_SIZE - 1); ! 671: *_address = address; ! 672: ! 673: /* if this is obio: */ ! 674: if (bus_type == TME_SUN3_PGTYPE_OBIO) { ! 675: conn_bus = sun3->tme_sun3_obio; ! 676: bus_fault_handler = _tme_sun3_obio_fault_handler; ! 677: } ! 678: ! 679: /* if this is obmem: */ ! 680: else if (bus_type == TME_SUN3_PGTYPE_OBMEM) { ! 681: conn_bus = sun3->tme_sun3_obmem; ! 682: bus_fault_handler = _tme_sun3_obmem_fault_handler; ! 683: } ! 684: ! 685: /* if this is the VME bus: */ ! 686: else { ! 687: assert(bus_type == TME_SUN3_PGTYPE_VME_D16 ! 688: || bus_type == TME_SUN3_PGTYPE_VME_D32); ! 689: conn_bus = sun3->tme_sun3_vmebus; ! 690: bus_fault_handler = _tme_sun3_vmebus_fault_handler; ! 691: } ! 692: ! 693: /* call the bus TLB filler: */ ! 694: rc = ((*conn_bus->tme_bus_tlb_fill) ! 695: (conn_bus, tlb, address, cycles)); ! 696: ! 697: /* if the bus TLB filler succeeded, add our bus fault handler: */ ! 698: if (rc == TME_OK) { ! 699: TME_BUS_TLB_FAULT_HANDLER(tlb, bus_fault_handler, sun3); ! 700: } ! 701: ! 702: return (rc); ! 703: } ! 704: ! 705: /* this gets a PTE from the MMU: */ ! 706: int ! 707: _tme_sun3_mmu_pte_get(struct tme_sun3 *sun3, tme_uint32_t address, tme_uint32_t *_pte_sun3) ! 708: { ! 709: struct tme_sun_mmu_pte pte; ! 710: tme_uint32_t pte_sun3; ! 711: unsigned int pte_flags; ! 712: int rc; ! 713: ! 714: /* get the PTE from the MMU: */ ! 715: rc = tme_sun_mmu_pte_get(sun3->tme_sun3_mmu, ! 716: sun3->tme_sun3_context, ! 717: address, ! 718: &pte); ! 719: assert(rc == TME_OK); ! 720: ! 721: /* form the Sun-3 PTE: */ ! 722: pte_sun3 = pte.tme_sun_mmu_pte_raw; ! 723: pte_flags = pte.tme_sun_mmu_pte_flags; ! 724: if (pte_flags & TME_SUN_MMU_PTE_REF) { ! 725: pte_sun3 |= TME_SUN3_PTE_REF; ! 726: } ! 727: if (pte_flags & TME_SUN_MMU_PTE_MOD) { ! 728: pte_sun3 |= TME_SUN3_PTE_MOD; ! 729: } ! 730: ! 731: /* done: */ ! 732: *_pte_sun3 = pte_sun3; ! 733: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, ! 734: (TME_SUN3_LOG_HANDLE(sun3), ! 735: _("pte_get: PGMAP[%d:0x%08x] -> 0x%08x"), ! 736: sun3->tme_sun3_context, ! 737: address, ! 738: pte_sun3)); ! 739: return (TME_OK); ! 740: } ! 741: ! 742: /* this sets a PTE into the MMU: */ ! 743: int ! 744: _tme_sun3_mmu_pte_set(struct tme_sun3 *sun3, tme_uint32_t address, tme_uint32_t pte_sun3) ! 745: { ! 746: struct tme_sun_mmu_pte pte; ! 747: unsigned int pte_flags; ! 748: #ifndef TME_NO_LOG ! 749: const char *bus_name; ! 750: tme_bus_addr_t physical_address; ! 751: ! 752: /* this silences gcc -Wuninitialized: */ ! 753: bus_name = NULL; ! 754: ! 755: /* log this setting: */ ! 756: physical_address = ((pte_sun3 & TME_SUN3_PTE_PGFRAME) << TME_SUN3_PAGE_SIZE_LOG2); ! 757: switch (TME_FIELD_MASK_EXTRACTU(pte_sun3, TME_SUN3_PTE_PGTYPE)) { ! 758: case TME_SUN3_PGTYPE_OBMEM: bus_name = "obmem"; break; ! 759: case TME_SUN3_PGTYPE_OBIO: bus_name = "obio"; break; ! 760: case TME_SUN3_PGTYPE_VME_D16: bus_name = "VME_D16"; break; ! 761: case TME_SUN3_PGTYPE_VME_D32: bus_name = "VME_D32"; break; ! 762: } ! 763: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, ! 764: (TME_SUN3_LOG_HANDLE(sun3), ! 765: _("pte_set: PGMAP[%d:0x%08x] <- 0x%08x (%s 0x%08x)"), ! 766: sun3->tme_sun3_context, ! 767: address, ! 768: pte_sun3, ! 769: bus_name, ! 770: physical_address)); ! 771: #endif /* !TME_NO_LOG */ ! 772: ! 773: pte.tme_sun_mmu_pte_raw = pte_sun3; ! 774: ! 775: pte_flags = (pte_sun3 & TME_SUN3_PTE_WRITE ! 776: ? TME_SUN_MMU_PTE_PROT_RW ! 777: : TME_SUN_MMU_PTE_PROT_RO); ! 778: pte_flags = (TME_SUN_MMU_PTE_PROT_SYSTEM(pte_flags) ! 779: | TME_SUN_MMU_PTE_PROT_USER(pte_sun3 & TME_SUN3_PTE_SYSTEM ! 780: ? TME_SUN_MMU_PTE_PROT_ERROR ! 781: : pte_flags)); ! 782: if (pte_sun3 & TME_SUN3_PTE_MOD) { ! 783: pte_flags |= TME_SUN_MMU_PTE_MOD; ! 784: } ! 785: if (pte_sun3 & TME_SUN3_PTE_REF) { ! 786: pte_flags |= TME_SUN_MMU_PTE_REF; ! 787: } ! 788: if (pte_sun3 & TME_SUN3_PTE_VALID) { ! 789: pte_flags |= TME_SUN_MMU_PTE_VALID; ! 790: } ! 791: pte.tme_sun_mmu_pte_flags = pte_flags; ! 792: ! 793: return (tme_sun_mmu_pte_set(sun3->tme_sun3_mmu, ! 794: sun3->tme_sun3_context, ! 795: address, ! 796: &pte)); ! 797: } ! 798: ! 799: /* this is called when the SDVMA bit is changed in the enable register: */ ! 800: void ! 801: _tme_sun3_mmu_sdvma_change(struct tme_sun3 *sun3) ! 802: { ! 803: unsigned int tlb_i; ! 804: ! 805: /* whenever the SDVMA bit changes, we have to invalidate all SDVMA ! 806: TLB entries: */ ! 807: for (tlb_i = 0; tlb_i < TME_SUN3_SDVMA_TLBS; tlb_i++) { ! 808: if (sun3->tme_sun3_sdvma_tlbs[tlb_i] != NULL) { ! 809: tme_bus_tlb_invalidate(sun3->tme_sun3_sdvma_tlbs[tlb_i]); ! 810: sun3->tme_sun3_sdvma_tlbs[tlb_i] = NULL; ! 811: } ! 812: } ! 813: } ! 814: ! 815: /* this is called when the context register is set: */ ! 816: void ! 817: _tme_sun3_mmu_context_set(struct tme_sun3 *sun3) ! 818: { ! 819: unsigned int tlb_i; ! 820: ! 821: /* every TLB set has nine contexts' worth of TLB entries. context ! 822: zero is used for the "boot state", and the remaining contexts ! 823: correspond to the eight possible MMU contexts. ! 824: ! 825: context zero is used for the boot state because at TLB set ! 826: allocation time, TLB sets are initialized pointing to the context ! 827: zero TLBs (by tme_sun_mmu_tlb_set_allocate), and TLBs must be ! 828: initialized to the boot state TLBs. ! 829: ! 830: in the boot state, TLB fills for supervisor program references ! 831: bypass the MMU and are filled to reference the PROM, and data ! 832: fills are filled as normal using the current context. since context ! 833: register changes can happen while in the boot state, but we only ! 834: have one boot state context in the TLB sets, we have to track ! 835: the data TLBs we fill in the boot state. ! 836: ! 837: we don't bother to track the supervisor program TLB fills, since ! 838: they never change. */ ! 839: ! 840: /* in the not-boot (i.e., normal, state): */ ! 841: if (__tme_predict_true(sun3->tme_sun3_enable & TME_SUN3_ENA_NOTBOOT)) { ! 842: ! 843: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, ! 844: (TME_SUN3_LOG_HANDLE(sun3), ! 845: _("context now #%d"), ! 846: sun3->tme_sun3_context)); ! 847: ! 848: /* update all TLB sets to reflect the context change: */ ! 849: tme_sun_mmu_tlbs_context_set(sun3->tme_sun3_mmu, sun3->tme_sun3_context + 1); ! 850: } ! 851: ! 852: /* in the boot state: */ ! 853: else { ! 854: ! 855: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, ! 856: (TME_SUN3_LOG_HANDLE(sun3), ! 857: _("context now #%d (boot state)"), ! 858: sun3->tme_sun3_context)); ! 859: ! 860: /* update all TLB sets to reflect the pseudo-context change: */ ! 861: tme_sun_mmu_tlbs_context_set(sun3->tme_sun3_mmu, 0); ! 862: ! 863: /* invalidate all of the boot-state data TLBs: */ ! 864: for (tlb_i = 0; tlb_i < TME_SUN3_BOOT_STATE_TLBS; tlb_i++) { ! 865: if (sun3->tme_sun3_boot_state_tlbs[tlb_i] != NULL) { ! 866: tme_bus_tlb_invalidate(sun3->tme_sun3_boot_state_tlbs[tlb_i]); ! 867: sun3->tme_sun3_boot_state_tlbs[tlb_i] = NULL; ! 868: } ! 869: } ! 870: } ! 871: } ! 872: ! 873: /* this allocates a new TLB set: */ ! 874: int ! 875: _tme_sun3_mmu_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker, ! 876: unsigned int count, unsigned int sizeof_one, ! 877: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb *) _tlbs) ! 878: { ! 879: struct tme_sun3 *sun3; ! 880: int rc; ! 881: ! 882: /* recover our sun3: */ ! 883: sun3 = (struct tme_sun3 *) conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private; ! 884: ! 885: /* get the MMU to allocate the TLB set: */ ! 886: rc = tme_sun_mmu_tlb_set_allocate(sun3->tme_sun3_mmu, count, sizeof_one, _tlbs); ! 887: ! 888: return (rc); ! 889: } ! 890: ! 891: /* this creates a Sun-3 MMU: */ ! 892: void ! 893: _tme_sun3_mmu_new(struct tme_sun3 *sun3) ! 894: { ! 895: struct tme_sun_mmu_info mmu_info; ! 896: ! 897: mmu_info.tme_sun_mmu_info_element = sun3->tme_sun3_element; ! 898: mmu_info.tme_sun_mmu_info_address_bits = 28; ! 899: mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN3_PAGE_SIZE_LOG2; ! 900: mmu_info.tme_sun_mmu_info_pteindex_bits = 4; ! 901: mmu_info.tme_sun_mmu_info_contexts = 1 + 8; /* internal context zero is for the boot state */ ! 902: mmu_info.tme_sun_mmu_info_pmegs = TME_SUN3_PMEGS; ! 903: mmu_info.tme_sun_mmu_info_seginv = 255; ! 904: mmu_info.tme_sun_mmu_info_tlb_fill_private = sun3; ! 905: mmu_info.tme_sun_mmu_info_tlb_fill = _tme_sun3_tlb_fill_mmu; ! 906: mmu_info.tme_sun_mmu_info_proterr_private = sun3; ! 907: mmu_info.tme_sun_mmu_info_proterr = _tme_sun3_mmu_proterr; ! 908: mmu_info.tme_sun_mmu_info_invalid_private = sun3; ! 909: mmu_info.tme_sun_mmu_info_invalid = _tme_sun3_mmu_invalid; ! 910: sun3->tme_sun3_mmu = tme_sun_mmu_new(&mmu_info); ! 911: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.