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