|
|
1.1.1.2 ! root 1: /* $Id: sun2-mmu.c,v 1.9 2003/10/16 02:48:24 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.2 ! root 37: _TME_RCSID("$Id: sun2-mmu.c,v 1.9 2003/10/16 02:48:24 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: */ 295: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0); 296: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, -1); 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: */ ! 417: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 418: tlb_bus.tme_bus_tlb_addr_first, ! 419: 0); ! 420: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 421: tlb_bus.tme_bus_tlb_addr_last, ! 422: size - 1); ! 423: tlb_bus.tme_bus_tlb_cycles_ok ! 424: = (TME_BUS_CYCLE_READ ! 425: | TME_BUS_CYCLE_WRITE); ! 426: ! 427: /* map the filled TLB entry: */ ! 428: tme_bus_tlb_map(tlb, address | base, &tlb_bus, address); ! 429: 1.1 root 430: return (TME_OK); 431: } 432: 433: /* our post-MMU TLB filler: */ 434: static int 435: _tme_sun2_tlb_fill_mmu(void *_sun2, struct tme_bus_tlb *tlb, 436: struct tme_sun_mmu_pte *pte, 437: tme_uint32_t *_address, 438: unsigned int cycles) 439: { 440: struct tme_sun2 *sun2; 441: tme_uint32_t address; 442: unsigned int bus_type; 443: struct tme_bus_connection *conn_bus; 444: tme_bus_fault_handler bus_fault_handler; 445: int rc; 446: 447: /* recover our sun2: */ 448: sun2 = (struct tme_sun2 *) _sun2; 449: 450: /* get the physical page frame and bus type: */ 451: address = ((pte->tme_sun_mmu_pte_raw & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2); 452: bus_type = (pte->tme_sun_mmu_pte_raw & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK); 453: 454: /* any mapping of the *first* page of obio space means the PROM. 455: the virtual page frame is actually used to form the physical 456: address: */ 457: if (address == 0 458: && bus_type == TME_SUN2_PGTYPE_OBIO) { 459: address = TME_SUN2_PROM_BASE | (*_address & ((TME_SUN2_PROM_SIZE - 1) & ~(TME_SUN2_PAGE_SIZE - 1))); 460: bus_type = TME_SUN2_PGTYPE_OBMEM; 461: } 462: 463: /* add in the page offset to finish the address: */ 464: address |= *_address & (TME_SUN2_PAGE_SIZE - 1); 465: *_address = address; 466: 467: /* if this is obio: */ 468: if (bus_type == TME_SUN2_PGTYPE_OBIO) { 469: conn_bus = sun2->tme_sun2_obio; 470: bus_fault_handler = _tme_sun2_obio_fault_handler; 471: } 472: 473: /* if this is obmem: */ 474: else if (bus_type == TME_SUN2_PGTYPE_OBMEM) { 475: conn_bus = sun2->tme_sun2_obmem; 476: bus_fault_handler = _tme_sun2_obmem_fault_handler; 477: } 478: 479: /* if this is the VME bus: */ 480: else if (sun2->tme_sun2_has_vme) { 481: 482: if (bus_type == TME_SUN2_PGTYPE_VME8) { 483: address |= 0x800000; 484: } 485: else { 486: assert(bus_type == TME_SUN2_PGTYPE_VME0); 487: } 488: 489: bus_fault_handler = _tme_sun2_vmebus_fault_handler; 490: 491: /* TBD: */ 492: abort(); 493: } 494: 495: /* if this is mbmem: */ 496: else if (bus_type == TME_SUN2_PGTYPE_MBMEM) { 497: conn_bus = sun2->tme_sun2_mbmem; 498: bus_fault_handler = _tme_sun2_multibus_fault_handler; 499: } 500: 501: /* otherwise, this is mbio: */ 502: else { 503: assert(bus_type == TME_SUN2_PGTYPE_MBIO); 504: conn_bus = sun2->tme_sun2_mbio; 505: bus_fault_handler = _tme_sun2_multibus_fault_handler; 506: } 507: 508: /* call the bus TLB filler: */ 509: rc = ((*conn_bus->tme_bus_tlb_fill) 510: (conn_bus, tlb, address, cycles)); 511: 512: /* if the bus TLB filler succeeded, add our bus fault handler: */ 513: if (rc == TME_OK) { 514: TME_BUS_TLB_FAULT_HANDLER(tlb, bus_fault_handler, sun2); 515: } 516: 517: return (rc); 518: } 519: 520: /* this gets a PTE from the MMU: */ 521: int 522: _tme_sun2_mmu_pte_get(struct tme_sun2 *sun2, tme_uint32_t address, tme_uint32_t *_pte_sun2) 523: { 524: struct tme_sun_mmu_pte pte; 525: tme_uint32_t pte_sun2; 526: unsigned int pte_flags; 527: int rc; 528: 529: /* get the PTE from the MMU: */ 530: rc = tme_sun_mmu_pte_get(sun2->tme_sun2_mmu, 531: sun2->tme_sun2_context_user, 532: address, 533: &pte); 534: assert(rc == TME_OK); 535: 536: /* form the Sun-2 PTE: */ 537: pte_sun2 = pte.tme_sun_mmu_pte_raw; 538: pte_flags = pte.tme_sun_mmu_pte_flags; 539: if (pte_flags & TME_SUN_MMU_PTE_REF) { 540: pte_sun2 |= TME_SUN2_PTE_REF; 541: } 542: if (pte_flags & TME_SUN_MMU_PTE_MOD) { 543: pte_sun2 |= TME_SUN2_PTE_MOD; 544: } 545: 546: /* done: */ 547: *_pte_sun2 = pte_sun2; 548: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 549: (TME_SUN2_LOG_HANDLE(sun2), 550: _("pte_get: PGMAP[%d:0x%08x] -> 0x%08x"), 551: sun2->tme_sun2_context_user, 552: address, 553: pte_sun2)); 554: return (TME_OK); 555: } 556: 557: /* this sets a PTE into the MMU: */ 558: int 559: _tme_sun2_mmu_pte_set(struct tme_sun2 *sun2, tme_uint32_t address, tme_uint32_t pte_sun2) 560: { 561: struct tme_sun_mmu_pte pte; 562: unsigned int pte_flags; 563: #ifndef TME_NO_LOG 564: const char *bus_name; 565: tme_bus_addr_t physical_address; 566: 1.1.1.2 ! root 567: /* this silences gcc -Wuninitialized: */ ! 568: bus_name = NULL; ! 569: 1.1 root 570: /* log this setting: */ 571: physical_address = ((pte_sun2 & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2); 572: switch ((pte_sun2 & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK)) { 573: case TME_SUN2_PGTYPE_OBMEM: bus_name = "obmem"; break; 574: case TME_SUN2_PGTYPE_OBIO: bus_name = "obio"; break; 575: case TME_SUN2_PGTYPE_MBMEM: 576: if (sun2->tme_sun2_has_vme) { 577: bus_name = "VME"; 578: } 579: else { 580: bus_name = "mbmem"; 581: } 582: break; 583: case TME_SUN2_PGTYPE_MBIO: 584: if (sun2->tme_sun2_has_vme) { 585: bus_name = "VME"; 586: physical_address |= 0x800000; 587: } 588: else { 589: bus_name = "mbio"; 590: } 591: break; 592: } 593: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 594: (TME_SUN2_LOG_HANDLE(sun2), 595: _("pte_set: PGMAP[%d:0x%08x] <- 0x%08x (%s 0x%08x)"), 596: sun2->tme_sun2_context_user, 597: address, 598: pte_sun2, 599: bus_name, 600: physical_address)); 601: #endif /* !TME_NO_LOG */ 602: 603: pte.tme_sun_mmu_pte_raw = pte_sun2; 604: 605: pte_flags = 0; 606: if (pte_sun2 & TME_SUN2_PTE_MOD) { 607: pte_flags |= TME_SUN_MMU_PTE_MOD; 608: } 609: if (pte_sun2 & TME_SUN2_PTE_REF) { 610: pte_flags |= TME_SUN_MMU_PTE_REF; 611: } 612: switch (pte_sun2 & TME_SUN2_PTE_PROT) { 613: 614: /* with this protection, the system can read and write, 615: and the user gets a protection error: */ 616: case 0x70000000: 617: case 0x74000000: 618: case 0x60000000: 619: pte_flags |= 620: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) 621: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR)); 622: break; 623: 624: /* with this protection, the system gets a protection error, 625: and the user gets a protection error: */ 626: case 0x30000000: 627: case 0x20000000: 628: case 0x10000000: 629: case 0x00000000: 630: case 0x04000000: 631: pte_flags |= 632: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR) 633: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR)); 634: break; 635: 636: /* with this protection, the system can read and write, 637: and the user can read and write: */ 638: case 0x7C000000: 639: case 0x6C000000: 640: pte_flags |= 641: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) 642: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)); 643: break; 644: 645: /* with this protection, the system can read and write, 646: and the user can read: */ 647: case 0x78000000: 648: pte_flags |= 649: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) 650: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)); 651: break; 652: 653: /* with this protection, the system can read, 654: and the user can read: */ 655: case 0x58000000: 656: pte_flags |= 657: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO) 658: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)); 659: break; 660: 661: /* with this protection, the system can read, 662: and the user can read and write: */ 663: case 0x5C000000: 664: case 0x4C000000: 665: pte_flags |= 666: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO) 667: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)); 668: break; 669: 670: /* with this protection, the system can read, 671: and the user gets a protection error: */ 672: case 0x50000000: 673: case 0x40000000: 674: pte_flags |= 675: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO) 676: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR)); 677: break; 678: 679: /* with this protection, the system gets a protection error, 680: and the user can read and write: */ 681: case 0x3c000000: 1.1.1.2 ! root 682: case 0x0c000000: 1.1 root 683: pte_flags |= 684: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR) 685: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)); 686: break; 687: 688: /* with this protection, the system gets a protection error, 689: and the user can read: */ 690: case 0x08000000: 691: pte_flags |= 692: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR) 693: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)); 694: break; 695: 696: default: abort(); 697: } 698: if (pte_sun2 & TME_SUN2_PTE_VALID) { 699: pte_flags |= TME_SUN_MMU_PTE_VALID; 700: } 701: pte.tme_sun_mmu_pte_flags = pte_flags; 702: 703: return (tme_sun_mmu_pte_set(sun2->tme_sun2_mmu, 704: sun2->tme_sun2_context_user, 705: address, 706: &pte)); 707: } 708: 709: /* this is called when the system context register is set: */ 710: void 711: _tme_sun2_mmu_context_system_set(struct tme_sun2 *sun2) 712: { 713: /* system context register changes are assumed to be rare. if they 714: were frequent, we'd have to allocate 64 TLB sets for each TLB 715: user - one for each possible combination of user context and 716: system context. instead, when the system context register 717: changes, we simply invalidate all TLB entries everywhere: */ 718: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 719: (TME_SUN2_LOG_HANDLE(sun2), 720: _("system context now #%d"), 721: sun2->tme_sun2_context_system)); 722: tme_sun_mmu_tlbs_invalidate(sun2->tme_sun2_mmu); 723: } 724: 725: /* this is called when the user context register is set: */ 726: void 727: _tme_sun2_mmu_context_user_set(struct tme_sun2 *sun2) 728: { 729: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 730: (TME_SUN2_LOG_HANDLE(sun2), 731: _("user context now #%d"), 732: sun2->tme_sun2_context_user)); 733: tme_sun_mmu_tlbs_context_set(sun2->tme_sun2_mmu, sun2->tme_sun2_context_user); 734: } 735: 736: /* this allocates a new TLB set: */ 737: int 738: _tme_sun2_mmu_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker, 739: unsigned int count, unsigned int sizeof_one, 740: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb **) _tlbs) 741: { 742: struct tme_sun2 *sun2; 743: int rc; 744: 745: /* recover our sun2: */ 746: sun2 = (struct tme_sun2 *) conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private; 747: 748: /* get the MMU to allocate the TLB set: */ 749: rc = tme_sun_mmu_tlb_set_allocate(sun2->tme_sun2_mmu, count, sizeof_one, _tlbs); 750: 751: /* if this is the TLB set for our CPU, remember where the context 752: zero TLBs are, and try to reset the MMU now: */ 753: /* FIXME - this assumes that the *first* TLB set allocated by 754: the CPU is for its data: */ 755: if (rc == TME_OK 756: && conn_bus_asker->tme_bus_connection.tme_connection_type == TME_CONNECTION_BUS_M68K 757: && sun2->tme_sun2_reset_tlbs == NULL) { 758: assert(sizeof_one == sizeof(struct tme_m68k_tlb)); 759: sun2->tme_sun2_reset_tlbs = (struct tme_m68k_tlb *) TME_ATOMIC_READ(struct tme_bus_tlb *, *_tlbs); 760: sun2->tme_sun2_reset_tlb_count = count; 761: _tme_sun2_mmu_reset(sun2); 762: } 763: 764: return (rc); 765: } 766: 767: /* the first four 16-bit read cycles that the m68010 does after it comes 768: out of reset are to fetch the reset vector (one 32-bit word for the 769: initial SSP, one 32-bit word for the initial PC). 770: 771: apparently the Sun-2 reset circuitry has some special logic that 772: is able to direct these read cycles to the PROM, where the reset 773: vector is located. we simulate this logic by forcing the CPU's 774: context zero TLB entries to all point to ROM for addresses 0-7, 775: but only for the first four cycles, after which we invalidate 776: all of the CPU TLB entries. */ 777: 778: /* this is a special bus cycle handling function used at reset time. 779: it is used only for the first four m68010 read cycles: */ 780: static int 781: _tme_sun2_reset_cycle(void *_sun2, struct tme_bus_cycle *cycle) 782: { 783: struct tme_sun2 *sun2; 784: int rc; 785: 786: /* recover our sun2: */ 787: sun2 = (struct tme_sun2 *) _sun2; 788: 789: /* this must be a 16-bit read: */ 790: assert(cycle->tme_bus_cycle_size == sizeof(tme_uint16_t)); 791: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 792: (TME_SUN2_LOG_HANDLE(sun2), 793: _("reset cycle #%d"), 794: sun2->tme_sun2_reset_cycles)); 795: 796: /* run the real cycle: */ 797: rc = ((*sun2->tme_sun2_reset_cycle) 798: (sun2->tme_sun2_reset_cycle_private, 799: cycle)); 800: 801: /* after the fourth read cycle, invalidate all of the TLBs 802: that the CPU holds, ending these abnormal reset reads: */ 803: if (rc == TME_OK) { 804: sun2->tme_sun2_reset_cycles++; 805: if (sun2->tme_sun2_reset_cycles == 4) { 806: tme_sun_mmu_tlbs_invalidate(sun2->tme_sun2_mmu); 807: } 808: } 809: 810: return (rc); 811: } 812: 1.1.1.2 ! root 813: /* this initializes the context zero part of the CPU's TLB set to 1.1 root 814: support four slow 16-bit reads from ROM at addresses 0, 2, 4, 6, 815: respectively. this emulates how the Sun-2 behaves as it comes out 816: of reset: */ 817: int 818: _tme_sun2_mmu_reset(struct tme_sun2 *sun2) 819: { 820: struct tme_m68k_tlb *tlb_m68k; 821: struct tme_bus_tlb *tlb, tlb_virtual; 822: unsigned long tlb_i; 823: 824: /* we can only do this initialization once we have both 825: the obmem bus and the CPU's TLBs: */ 826: tlb_m68k = sun2->tme_sun2_reset_tlbs; 827: if (tlb_m68k == NULL 828: || sun2->tme_sun2_obmem == NULL) { 829: return (TME_OK); 830: } 831: sun2->tme_sun2_reset_tlbs = NULL; 832: tlb = &tlb_m68k->tme_m68k_tlb_bus_tlb; 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: */ 842: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_virtual.tme_bus_tlb_addr_first, 0); 843: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_virtual.tme_bus_tlb_addr_last, 7); 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) 850: || TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first) != 0 851: || TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last) != 7) { 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: 882: mmu_info.tme_sun_mmu_info_element = sun2->tme_sun2_element; 883: mmu_info.tme_sun_mmu_info_address_bits = 24; 884: mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN2_PAGE_SIZE_LOG2; 885: mmu_info.tme_sun_mmu_info_pteindex_bits = 4; 886: mmu_info.tme_sun_mmu_info_contexts = 8; 887: mmu_info.tme_sun_mmu_info_pmegs = 256; 888: mmu_info.tme_sun_mmu_info_seginv = 255; 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.