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