|
|
1.1.1.2 ! root 1: /* $Id: sun3-mmu.c,v 1.5 2006/09/30 12:43:39 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.2 ! root 37: _TME_RCSID("$Id: sun3-mmu.c,v 1.5 2006/09/30 12:43:39 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: 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: */ 1.1.1.2 ! root 287: tlb_bus.tme_bus_tlb_addr_first = address & (((tme_bus_addr_t) 0) - TME_SUN3_PROM_SIZE); ! 288: tlb_bus.tme_bus_tlb_addr_last = address | (TME_SUN3_PROM_SIZE - 1); 1.1 root 289: tlb_bus.tme_bus_tlb_cycles_ok 290: = TME_BUS_CYCLE_READ; 291: 292: /* map the filled TLB entry: */ 293: tme_bus_tlb_map(tlb, TME_SUN3_PROM_BASE | (address & (TME_SUN3_PROM_SIZE - 1)), &tlb_bus, address); 294: 295: /* this is good for the supervisor program function code only: */ 296: *_function_code_or_codes = TME_BIT(TME_M68K_FC_SP); 297: 298: /* done: */ 299: return(TME_OK); 300: } 301: 302: /* update the head pointer for the active boot state TLB entry 303: list: */ 304: tlb_i = sun3->tme_sun3_boot_state_tlb_next 305: = ((sun3->tme_sun3_boot_state_tlb_next 306: + 1) 307: & (TME_SUN3_BOOT_STATE_TLBS - 1)); 308: 309: /* if the new head pointer already has a TLB entry, and it doesn't 310: happen to be the same as this TLB entry, invalidate it: */ 311: if (sun3->tme_sun3_boot_state_tlbs[tlb_i] != NULL 312: && (sun3->tme_sun3_boot_state_tlbs[tlb_i] 1.1.1.2 ! root 313: != tlb->tme_bus_tlb_global)) { 1.1 root 314: tme_bus_tlb_invalidate(sun3->tme_sun3_boot_state_tlbs[tlb_i]); 315: } 316: 317: /* add this TLB entry to the active list: */ 318: sun3->tme_sun3_boot_state_tlbs[tlb_i] = 1.1.1.2 ! root 319: tlb->tme_bus_tlb_global; 1.1 root 320: 321: /* if this TLB entry ends up good for the supervisor, it's not 322: good for the supervisor program function code: */ 323: function_code_sp = 0; 324: } 325: 326: /* fill this TLB entry from the MMU: */ 327: access 328: = ((cycles & TME_BUS_CYCLE_WRITE) 329: ? TME_SUN_MMU_PTE_PROT_RW 330: : TME_SUN_MMU_PTE_PROT_RO); 331: access 332: = ((function_code == TME_M68K_FC_UD 333: || function_code == TME_M68K_FC_UP) 334: ? TME_SUN_MMU_PTE_PROT_USER(access) 335: : TME_SUN_MMU_PTE_PROT_SYSTEM(access)); 336: tlb_flags = tme_sun_mmu_tlb_fill(sun3->tme_sun3_mmu, 337: tlb, 338: context, 339: address, 340: access); 341: 342: /* this TLB entry is good for the program and data function codes 343: for the user and/or the supervisor: */ 344: *_function_code_or_codes 345: = (((tlb_flags & TME_SUN_MMU_TLB_USER) 346: ? (TME_BIT(TME_M68K_FC_UD) 347: | TME_BIT(TME_M68K_FC_UP)) 348: : 0) 349: | ((tlb_flags & TME_SUN_MMU_TLB_SYSTEM) 350: ? (TME_BIT(TME_M68K_FC_SD) 351: | function_code_sp) 352: : 0)); 353: 354: /* if the memory error register is being tested: */ 355: if (__tme_predict_false(sun3->tme_sun3_memerr_csr & TME_SUN3_MEMERR_PAR_TEST)) { 356: 357: /* this must be a supervisor data access: */ 358: if (function_code != TME_M68K_FC_SD) { 359: abort(); 360: } 361: 362: /* if this TLB's bus cycle handler isn't for the memory error 363: register itself: */ 364: if (tlb->tme_bus_tlb_cycle != _tme_sun3_memerr_cycle_handler) { 365: 366: /* there must be no other TLB entry already involved in the test: */ 367: if (sun3->tme_sun3_memerr_tlb != NULL) { 368: abort(); 369: } 370: 371: /* remember this TLB entry pointer, and its original bus cycle 372: handler: */ 1.1.1.2 ! root 373: sun3->tme_sun3_memerr_tlb = tlb->tme_bus_tlb_global; 1.1 root 374: assert (sun3->tme_sun3_memerr_tlb != NULL); 375: sun3->tme_sun3_memerr_cycle_private = tlb->tme_bus_tlb_cycle_private; 376: sun3->tme_sun3_memerr_cycle = tlb->tme_bus_tlb_cycle; 377: 378: /* this TLB entry does not allow fast reading and writing, and 379: it now uses the memory error test cycle handler: */ 380: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; 381: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; 382: tlb->tme_bus_tlb_rwlock = NULL; 383: tlb->tme_bus_tlb_cycle_private = sun3; 384: tlb->tme_bus_tlb_cycle = _tme_sun3_memerr_test_cycle_handler; 385: 386: /* reset other memory error test values: */ 387: sun3->tme_sun3_memerr_pending_csr = 0; 388: } 389: } 390: 391: return (TME_OK); 392: } 393: 394: /* our m68k TLB filler: */ 395: int 396: _tme_sun3_m68k_tlb_fill(struct tme_m68k_bus_connection *conn_m68k, struct tme_m68k_tlb *tlb_m68k, 397: unsigned int function_code, tme_uint32_t address, unsigned int cycles) 398: { 399: struct tme_sun3 *sun3; 400: struct tme_bus_tlb *tlb; 401: struct tme_bus_tlb tlb_bus; 402: 403: /* recover our sun3: */ 404: sun3 = (struct tme_sun3 *) conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private; 405: 406: /* get the generic bus TLB: */ 407: tlb = &tlb_m68k->tme_m68k_tlb_bus_tlb; 408: 409: /* if this is function code three: */ 410: if (function_code == TME_M68K_FC_3) { 411: 412: /* if this address is within the UART bypass: */ 413: if (address >= TME_SUN3_CONTROL_UART_BYPASS 414: && address < TME_SUN3_CONTROL_UART_BYPASS + TME_SUN_Z8530_SIZE) { 415: 416: /* fill this TLB entry directly from the obio bus: */ 417: (*sun3->tme_sun3_obio->tme_bus_tlb_fill) 418: (sun3->tme_sun3_obio, 419: tlb, 420: (address - TME_SUN3_CONTROL_UART_BYPASS) + TME_SUN3_OBIO_ZS0, 421: cycles); 422: 423: /* create the mapping TLB entry: */ 1.1.1.2 ! root 424: tlb_bus.tme_bus_tlb_addr_first = TME_SUN3_CONTROL_UART_BYPASS; ! 425: tlb_bus.tme_bus_tlb_addr_last = TME_SUN3_CONTROL_UART_BYPASS + TME_SUN_Z8530_SIZE - 1; 1.1 root 426: tlb_bus.tme_bus_tlb_cycles_ok 427: = (TME_BUS_CYCLE_READ 428: | TME_BUS_CYCLE_WRITE); 429: 430: /* map the filled TLB entry: */ 431: tme_bus_tlb_map(tlb, (address - TME_SUN3_CONTROL_UART_BYPASS) + TME_SUN3_OBIO_ZS0, &tlb_bus, address); 432: } 433: 434: /* otherwise, this is something else in control space: */ 435: else { 436: 437: /* initialize the TLB entry: */ 438: tme_bus_tlb_initialize(tlb); 439: 440: /* we cover the entire address space up to the UART bypass: */ 1.1.1.2 ! root 441: tlb->tme_bus_tlb_addr_first = 0; ! 442: tlb->tme_bus_tlb_addr_last = TME_SUN3_CONTROL_UART_BYPASS - 1; 1.1 root 443: 444: /* we allow reading and writing: */ 445: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 446: 447: /* our bus cycle handler: */ 448: tlb->tme_bus_tlb_cycle_private = sun3; 449: tlb->tme_bus_tlb_cycle = _tme_sun3_control_cycle_handler; 450: } 451: 452: /* this is good for function code three only: */ 453: tlb_m68k->tme_m68k_tlb_function_codes_mask = TME_BIT(TME_M68K_FC_3); 454: 455: /* done: */ 456: return (TME_OK); 457: } 458: 459: /* this is a normal function code: */ 460: tlb_m68k->tme_m68k_tlb_function_codes_mask = function_code; 461: return (_tme_sun3_tlb_fill(sun3, tlb, sun3->tme_sun3_context, 462: &tlb_m68k->tme_m68k_tlb_function_codes_mask, 463: address, cycles)); 464: } 465: 466: /* our bus TLB filler: */ 467: int 468: _tme_sun3_bus_tlb_fill(struct tme_bus_connection *conn_bus, struct tme_bus_tlb *tlb, 469: tme_uint32_t address, unsigned int cycles) 470: { 471: struct tme_sun3 *sun3; 472: struct tme_sun3_bus_connection *conn_sun3; 473: tme_uint32_t base, size; 474: struct tme_bus_tlb tlb_bus; 475: tme_uint8_t context; 476: unsigned int function_code_or_codes; 477: unsigned int tlb_i; 478: 479: /* recover our sun3: */ 480: sun3 = (struct tme_sun3 *) conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; 481: 482: /* recover the sun3 internal mainbus connection: */ 483: conn_sun3 = (struct tme_sun3_bus_connection *) conn_bus; 484: 485: /* dispatch on the internal connection. the bus address into a DVMA 486: address, context, and function code, except for the memory error 487: register and interrupt register connections, which are handled 488: specially: */ 489: switch (conn_sun3->tme_sun3_bus_connection_which) { 490: 491: case TME_SUN3_CONN_OBIO_MASTER: 492: base = 0x0f000000; 493: size = TME_SUN3_DVMA_SIZE_OBIO; 494: context = sun3->tme_sun3_context; 495: function_code_or_codes = TME_M68K_FC_SD; 496: break; 497: 498: case TME_SUN3_CONN_BUS_VME: 499: base = 0x0ff00000; 500: size = TME_SUN3_DVMA_SIZE_VME; 501: context = sun3->tme_sun3_context; 502: function_code_or_codes = TME_M68K_FC_SD; 503: break; 504: 505: case TME_SUN3_CONN_REG_MEMERR: 506: case TME_SUN3_CONN_REG_INTREG: 507: 508: /* initialize the TLB entry: */ 509: tme_bus_tlb_initialize(tlb); 510: 511: /* the address range: */ 1.1.1.2 ! root 512: tlb->tme_bus_tlb_addr_first = 0; ! 513: tlb->tme_bus_tlb_addr_last ! 514: = ((conn_sun3->tme_sun3_bus_connection_which == TME_SUN3_CONN_REG_MEMERR ! 515: ? TME_SUN3_MEMERR_SIZ_REG ! 516: : sizeof(sun3->tme_sun3_ints)) ! 517: - 1); 1.1 root 518: 519: /* we allow reading and writing: */ 520: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 521: 522: /* our bus cycle handler: */ 523: tlb->tme_bus_tlb_cycle_private = sun3; 524: tlb->tme_bus_tlb_cycle 525: = (conn_sun3->tme_sun3_bus_connection_which == TME_SUN3_CONN_REG_MEMERR 526: ? _tme_sun3_memerr_cycle_handler 527: : _tme_sun3_intreg_cycle_handler); 528: 529: /* done: */ 530: return (TME_OK); 531: 532: default: abort(); 533: } 534: 535: /* update the head pointer for the active SDVMA TLB entry list: */ 536: tlb_i = sun3->tme_sun3_sdvma_tlb_next 537: = ((sun3->tme_sun3_sdvma_tlb_next 538: + 1) 539: & (TME_SUN3_SDVMA_TLBS - 1)); 540: 541: /* if the new head pointer already has a TLB entry, and it doesn't 542: happen to be the same as this TLB entry, invalidate it: */ 543: if (sun3->tme_sun3_sdvma_tlbs[tlb_i] != NULL 544: && (sun3->tme_sun3_sdvma_tlbs[tlb_i] 1.1.1.2 ! root 545: != tlb->tme_bus_tlb_global)) { 1.1 root 546: tme_bus_tlb_invalidate(sun3->tme_sun3_sdvma_tlbs[tlb_i]); 547: } 548: 549: /* add this TLB entry to the active list: */ 550: sun3->tme_sun3_sdvma_tlbs[tlb_i] = 1.1.1.2 ! root 551: tlb->tme_bus_tlb_global; 1.1 root 552: 553: /* if system DVMA is disabled: */ 554: if (__tme_predict_false(!(sun3->tme_sun3_enable & TME_SUN3_ENA_SDVMA))) { 555: 556: /* return a TLB entry that will generate a VME bus fault: */ 557: tme_bus_tlb_initialize(tlb); 1.1.1.2 ! root 558: tlb->tme_bus_tlb_addr_first = 0; ! 559: tlb->tme_bus_tlb_addr_last = size - 1; 1.1 root 560: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 561: tlb->tme_bus_tlb_cycle_private = sun3; 562: tlb->tme_bus_tlb_cycle = _tme_sun3_sdvma_disabled; 563: TME_BUS_TLB_FAULT_HANDLER(tlb, _tme_sun3_vmebus_fault_handler, sun3); 564: return (TME_OK); 565: } 566: 567: assert (!(address & base) 568: && (address < size)); 569: 570: /* fill this TLB entry from the MMU: */ 571: _tme_sun3_tlb_fill(sun3, tlb, context, 572: &function_code_or_codes, 573: address | base, cycles); 574: 575: /* create the mapping TLB entry. we do this even if base == 0, 576: because the TLB entry as currently filled may cover more address 577: space than DVMA space on this machine is supposed to cover: */ 1.1.1.2 ! root 578: tlb_bus.tme_bus_tlb_addr_first = 0; ! 579: tlb_bus.tme_bus_tlb_addr_last = size - 1; 1.1 root 580: tlb_bus.tme_bus_tlb_cycles_ok 581: = (TME_BUS_CYCLE_READ 582: | TME_BUS_CYCLE_WRITE); 583: 584: /* map the filled TLB entry: */ 585: tme_bus_tlb_map(tlb, address | base, &tlb_bus, address); 586: 587: /* XXX FIXME - what happens to a bus cycle to an unmapped DVMA 588: address? is the answer different for obio masters and the VME 589: bus? for now, these bus cycles get ignored in both cases: */ 590: if (tlb->tme_bus_tlb_cycle == _tme_sun3_mmu_invalid) { 591: tlb->tme_bus_tlb_cycle = _tme_sun3_cycle_dummy; 592: } 593: 594: return (TME_OK); 595: } 596: 597: /* our post-MMU TLB filler: */ 598: static int 599: _tme_sun3_tlb_fill_mmu(void *_sun3, struct tme_bus_tlb *tlb, 600: struct tme_sun_mmu_pte *pte, 601: tme_uint32_t *_address, 602: unsigned int cycles) 603: { 604: struct tme_sun3 *sun3; 605: tme_uint32_t address; 606: unsigned int bus_type; 607: struct tme_bus_connection *conn_bus; 608: tme_bus_fault_handler bus_fault_handler; 609: int rc; 610: 611: /* recover our sun3: */ 612: sun3 = (struct tme_sun3 *) _sun3; 613: 614: /* get the physical page frame and bus type: */ 615: address = ((pte->tme_sun_mmu_pte_raw & TME_SUN3_PTE_PGFRAME) << TME_SUN3_PAGE_SIZE_LOG2); 616: bus_type = TME_FIELD_MASK_EXTRACTU(pte->tme_sun_mmu_pte_raw, TME_SUN3_PTE_PGTYPE); 617: 618: /* any mapping of any address in a PROM-sized region starting at 619: 0x100000 in obio space means the PROM. the virtual page frame is 620: actually used to form the physical address: */ 621: if ((address & -TME_SUN3_PROM_SIZE) == TME_SUN3_OBIO_PROM 622: && bus_type == TME_SUN3_PGTYPE_OBIO) { 623: address = TME_SUN3_PROM_BASE | (*_address & ((TME_SUN3_PROM_SIZE - 1) & ~(TME_SUN3_PAGE_SIZE - 1))); 624: bus_type = TME_SUN3_PGTYPE_OBMEM; 625: } 626: 627: #if 1 /* NetBSD/sun3 cgtwo bug */ 628: /* XXX FIXME - this hack works around a bug in NetBSD/sun3, present 629: since revision 1.49 of src/sys/arch/sun3/conf/GENERIC (when the 630: sun3x port was merged into the sun3 port). in this revision, the 631: declaration for cgtwo0 changed: 632: 633: -cgtwo0 at vmes0 addr 0xff400000 level 4 vect 0xA8 634: +cgtwo0 at vme2 addr 0x400000 ipl 4 vect 0xA8 635: 636: because the cg2mmap() function in src/sys/arch/sun3/dev/cg2.c 637: doesn't add the 0xff000000 mask to the configured physical 638: address (needed because the cgtwo is an A24 device), when Xsun 639: mmap()s the cgtwo it gets a mapping of physical address 0x400000 640: in VME space instead of the correct 0xff400000. the sparc cgtwo 641: driver gets this right. 642: 643: so for now we force all accesses to VME D16 address 0x400000 to 644: 0xff400000. once the NetBSD bug has been fixed this code should 645: be removed: */ 646: if (bus_type == TME_SUN3_PGTYPE_VME_D16 647: && ((address & 0xff400000) == 0x400000)) { 648: address |= 0xff000000; 649: } 650: #endif /* NetBSD/sun3 cgtwo bug */ 651: 652: /* add in the page offset to finish the address: */ 653: address |= *_address & (TME_SUN3_PAGE_SIZE - 1); 654: *_address = address; 655: 656: /* if this is obio: */ 657: if (bus_type == TME_SUN3_PGTYPE_OBIO) { 658: conn_bus = sun3->tme_sun3_obio; 659: bus_fault_handler = _tme_sun3_obio_fault_handler; 660: } 661: 662: /* if this is obmem: */ 663: else if (bus_type == TME_SUN3_PGTYPE_OBMEM) { 664: conn_bus = sun3->tme_sun3_obmem; 665: bus_fault_handler = _tme_sun3_obmem_fault_handler; 666: } 667: 668: /* if this is the VME bus: */ 669: else { 670: assert(bus_type == TME_SUN3_PGTYPE_VME_D16 671: || bus_type == TME_SUN3_PGTYPE_VME_D32); 672: conn_bus = sun3->tme_sun3_vmebus; 673: bus_fault_handler = _tme_sun3_vmebus_fault_handler; 674: } 675: 676: /* call the bus TLB filler: */ 677: rc = ((*conn_bus->tme_bus_tlb_fill) 678: (conn_bus, tlb, address, cycles)); 679: 680: /* if the bus TLB filler succeeded, add our bus fault handler: */ 681: if (rc == TME_OK) { 682: TME_BUS_TLB_FAULT_HANDLER(tlb, bus_fault_handler, sun3); 683: } 684: 685: return (rc); 686: } 687: 688: /* this gets a PTE from the MMU: */ 689: int 690: _tme_sun3_mmu_pte_get(struct tme_sun3 *sun3, tme_uint32_t address, tme_uint32_t *_pte_sun3) 691: { 692: struct tme_sun_mmu_pte pte; 693: tme_uint32_t pte_sun3; 694: unsigned int pte_flags; 695: int rc; 696: 697: /* get the PTE from the MMU: */ 698: rc = tme_sun_mmu_pte_get(sun3->tme_sun3_mmu, 699: sun3->tme_sun3_context, 700: address, 701: &pte); 702: assert(rc == TME_OK); 703: 704: /* form the Sun-3 PTE: */ 705: pte_sun3 = pte.tme_sun_mmu_pte_raw; 706: pte_flags = pte.tme_sun_mmu_pte_flags; 707: if (pte_flags & TME_SUN_MMU_PTE_REF) { 708: pte_sun3 |= TME_SUN3_PTE_REF; 709: } 710: if (pte_flags & TME_SUN_MMU_PTE_MOD) { 711: pte_sun3 |= TME_SUN3_PTE_MOD; 712: } 713: 714: /* done: */ 715: *_pte_sun3 = pte_sun3; 716: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, 717: (TME_SUN3_LOG_HANDLE(sun3), 718: _("pte_get: PGMAP[%d:0x%08x] -> 0x%08x"), 719: sun3->tme_sun3_context, 720: address, 721: pte_sun3)); 722: return (TME_OK); 723: } 724: 725: /* this sets a PTE into the MMU: */ 726: int 727: _tme_sun3_mmu_pte_set(struct tme_sun3 *sun3, tme_uint32_t address, tme_uint32_t pte_sun3) 728: { 729: struct tme_sun_mmu_pte pte; 730: unsigned int pte_flags; 731: #ifndef TME_NO_LOG 732: const char *bus_name; 733: tme_bus_addr_t physical_address; 734: 735: /* this silences gcc -Wuninitialized: */ 736: bus_name = NULL; 737: 738: /* log this setting: */ 739: physical_address = ((pte_sun3 & TME_SUN3_PTE_PGFRAME) << TME_SUN3_PAGE_SIZE_LOG2); 740: switch (TME_FIELD_MASK_EXTRACTU(pte_sun3, TME_SUN3_PTE_PGTYPE)) { 741: case TME_SUN3_PGTYPE_OBMEM: bus_name = "obmem"; break; 742: case TME_SUN3_PGTYPE_OBIO: bus_name = "obio"; break; 743: case TME_SUN3_PGTYPE_VME_D16: bus_name = "VME_D16"; break; 744: case TME_SUN3_PGTYPE_VME_D32: bus_name = "VME_D32"; break; 745: } 746: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, 747: (TME_SUN3_LOG_HANDLE(sun3), 748: _("pte_set: PGMAP[%d:0x%08x] <- 0x%08x (%s 0x%08x)"), 749: sun3->tme_sun3_context, 750: address, 751: pte_sun3, 752: bus_name, 753: physical_address)); 754: #endif /* !TME_NO_LOG */ 755: 756: pte.tme_sun_mmu_pte_raw = pte_sun3; 757: 758: pte_flags = (pte_sun3 & TME_SUN3_PTE_WRITE 759: ? TME_SUN_MMU_PTE_PROT_RW 760: : TME_SUN_MMU_PTE_PROT_RO); 761: pte_flags = (TME_SUN_MMU_PTE_PROT_SYSTEM(pte_flags) 762: | TME_SUN_MMU_PTE_PROT_USER(pte_sun3 & TME_SUN3_PTE_SYSTEM 763: ? TME_SUN_MMU_PTE_PROT_ERROR 764: : pte_flags)); 765: if (pte_sun3 & TME_SUN3_PTE_MOD) { 766: pte_flags |= TME_SUN_MMU_PTE_MOD; 767: } 768: if (pte_sun3 & TME_SUN3_PTE_REF) { 769: pte_flags |= TME_SUN_MMU_PTE_REF; 770: } 771: if (pte_sun3 & TME_SUN3_PTE_VALID) { 772: pte_flags |= TME_SUN_MMU_PTE_VALID; 773: } 774: pte.tme_sun_mmu_pte_flags = pte_flags; 775: 776: return (tme_sun_mmu_pte_set(sun3->tme_sun3_mmu, 777: sun3->tme_sun3_context, 778: address, 779: &pte)); 780: } 781: 782: /* this is called when the SDVMA bit is changed in the enable register: */ 783: void 784: _tme_sun3_mmu_sdvma_change(struct tme_sun3 *sun3) 785: { 786: unsigned int tlb_i; 787: 788: /* whenever the SDVMA bit changes, we have to invalidate all SDVMA 789: TLB entries: */ 790: for (tlb_i = 0; tlb_i < TME_SUN3_SDVMA_TLBS; tlb_i++) { 791: if (sun3->tme_sun3_sdvma_tlbs[tlb_i] != NULL) { 792: tme_bus_tlb_invalidate(sun3->tme_sun3_sdvma_tlbs[tlb_i]); 793: sun3->tme_sun3_sdvma_tlbs[tlb_i] = NULL; 794: } 795: } 796: } 797: 798: /* this is called when the context register is set: */ 799: void 800: _tme_sun3_mmu_context_set(struct tme_sun3 *sun3) 801: { 802: unsigned int tlb_i; 803: 804: /* every TLB set has nine contexts' worth of TLB entries. context 805: zero is used for the "boot state", and the remaining contexts 806: correspond to the eight possible MMU contexts. 807: 808: context zero is used for the boot state because at TLB set 809: allocation time, TLB sets are initialized pointing to the context 810: zero TLBs (by tme_sun_mmu_tlb_set_allocate), and TLBs must be 811: initialized to the boot state TLBs. 812: 813: in the boot state, TLB fills for supervisor program references 814: bypass the MMU and are filled to reference the PROM, and data 815: fills are filled as normal using the current context. since context 816: register changes can happen while in the boot state, but we only 817: have one boot state context in the TLB sets, we have to track 818: the data TLBs we fill in the boot state. 819: 820: we don't bother to track the supervisor program TLB fills, since 821: they never change. */ 822: 823: /* in the not-boot (i.e., normal, state): */ 824: if (__tme_predict_true(sun3->tme_sun3_enable & TME_SUN3_ENA_NOTBOOT)) { 825: 826: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, 827: (TME_SUN3_LOG_HANDLE(sun3), 828: _("context now #%d"), 829: sun3->tme_sun3_context)); 830: 831: /* update all TLB sets to reflect the context change: */ 832: tme_sun_mmu_tlbs_context_set(sun3->tme_sun3_mmu, sun3->tme_sun3_context + 1); 833: } 834: 835: /* in the boot state: */ 836: else { 837: 838: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK, 839: (TME_SUN3_LOG_HANDLE(sun3), 840: _("context now #%d (boot state)"), 841: sun3->tme_sun3_context)); 842: 843: /* update all TLB sets to reflect the pseudo-context change: */ 844: tme_sun_mmu_tlbs_context_set(sun3->tme_sun3_mmu, 0); 845: 846: /* invalidate all of the boot-state data TLBs: */ 847: for (tlb_i = 0; tlb_i < TME_SUN3_BOOT_STATE_TLBS; tlb_i++) { 848: if (sun3->tme_sun3_boot_state_tlbs[tlb_i] != NULL) { 849: tme_bus_tlb_invalidate(sun3->tme_sun3_boot_state_tlbs[tlb_i]); 850: sun3->tme_sun3_boot_state_tlbs[tlb_i] = NULL; 851: } 852: } 853: } 854: } 855: 856: /* this allocates a new TLB set: */ 857: int 858: _tme_sun3_mmu_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker, 859: unsigned int count, unsigned int sizeof_one, 1.1.1.2 ! root 860: struct tme_bus_tlb * tme_shared *_tlbs, ! 861: tme_rwlock_t *_tlbs_rwlock) 1.1 root 862: { 863: struct tme_sun3 *sun3; 864: int rc; 865: 866: /* recover our sun3: */ 867: sun3 = (struct tme_sun3 *) conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private; 868: 869: /* get the MMU to allocate the TLB set: */ 1.1.1.2 ! root 870: rc = tme_sun_mmu_tlb_set_allocate(sun3->tme_sun3_mmu, count, sizeof_one, _tlbs, _tlbs_rwlock); 1.1 root 871: 872: return (rc); 873: } 874: 875: /* this creates a Sun-3 MMU: */ 876: void 877: _tme_sun3_mmu_new(struct tme_sun3 *sun3) 878: { 879: struct tme_sun_mmu_info mmu_info; 880: 1.1.1.2 ! root 881: memset(&mmu_info, 0, sizeof(mmu_info)); 1.1 root 882: mmu_info.tme_sun_mmu_info_element = sun3->tme_sun3_element; 883: mmu_info.tme_sun_mmu_info_address_bits = 28; 884: mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN3_PAGE_SIZE_LOG2; 885: mmu_info.tme_sun_mmu_info_pteindex_bits = 4; 886: mmu_info.tme_sun_mmu_info_contexts = 1 + 8; /* internal context zero is for the boot state */ 887: mmu_info.tme_sun_mmu_info_pmegs = TME_SUN3_PMEGS; 888: mmu_info.tme_sun_mmu_info_tlb_fill_private = sun3; 889: mmu_info.tme_sun_mmu_info_tlb_fill = _tme_sun3_tlb_fill_mmu; 890: mmu_info.tme_sun_mmu_info_proterr_private = sun3; 891: mmu_info.tme_sun_mmu_info_proterr = _tme_sun3_mmu_proterr; 892: mmu_info.tme_sun_mmu_info_invalid_private = sun3; 893: mmu_info.tme_sun_mmu_info_invalid = _tme_sun3_mmu_invalid; 894: sun3->tme_sun3_mmu = tme_sun_mmu_new(&mmu_info); 895: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.