|
|
1.1.1.5 ! root 1: /* $Id: sun2-mmu.c,v 1.14 2009/08/30 14:39:47 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.5 ! root 37: _TME_RCSID("$Id: sun2-mmu.c,v 1.14 2009/08/30 14:39:47 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: 1.1.1.5 ! root 70: /* real context count: */ ! 71: #define TME_SUN2_CONTEXT_COUNT (8) ! 72: 1.1 root 73: /* this logs a bus error: */ 74: #ifndef TME_NO_LOG 75: static void 76: _tme_sun2_bus_fault_log(struct tme_sun2 *sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle) 77: { 1.1.1.5 ! root 78: tme_bus_addr32_t virtual_address; 1.1 root 79: struct tme_sun_mmu_pte pte; 80: tme_uint32_t pte_sun2; 81: const char *bus_name; 1.1.1.5 ! root 82: tme_bus_addr32_t physical_address; 1.1 root 83: int rc; 84: 1.1.1.2 root 85: /* this silences gcc -Wuninitialized: */ 86: bus_name = NULL; 87: 1.1 root 88: /* recover the virtual address used: */ 89: virtual_address = cycle->tme_bus_cycle_address - tlb->tme_bus_tlb_addr_offset; 90: 91: /* look up the PTE involved. since this is a real bus error, and 92: not a protection violation or page not present bus error, we 93: assume the system context: */ 94: rc = tme_sun_mmu_pte_get(sun2->tme_sun2_mmu, 95: sun2->tme_sun2_context_system, 96: virtual_address, 97: &pte); 98: assert(rc == TME_OK); 99: pte_sun2 = pte.tme_sun_mmu_pte_raw; 100: 101: /* form the physical address and get the bus name: */ 102: physical_address = (((pte_sun2 & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2) 103: | (virtual_address & (TME_SUN2_PAGE_SIZE - 1))); 104: switch ((pte_sun2 & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK)) { 105: case TME_SUN2_PGTYPE_OBMEM: bus_name = "obmem"; break; 106: case TME_SUN2_PGTYPE_OBIO: bus_name = "obio"; break; 107: case TME_SUN2_PGTYPE_MBMEM: 108: if (sun2->tme_sun2_has_vme) { 109: bus_name = "VME"; 110: } 111: else { 112: bus_name = "mbmem"; 113: } 114: break; 115: case TME_SUN2_PGTYPE_MBIO: 116: if (sun2->tme_sun2_has_vme) { 117: bus_name = "VME"; 118: physical_address |= 0x800000; 119: } 120: else { 121: bus_name = "mbio"; 122: } 123: break; 124: } 125: 126: /* log this bus error: */ 127: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 128: (TME_SUN2_LOG_HANDLE(sun2), 129: _("%s bus error, physical 0x%08x, virtual 0x%08x, buserr = 0x%02x"), 130: bus_name, 131: physical_address, 132: virtual_address, 133: sun2->tme_sun2_buserr)); 134: } 135: #else /* TME_NO_LOG */ 136: #define _tme_sun2_bus_fault_log(a, b, c) do { } while (/* CONSTCOND */ 0) 137: #endif /* TME_NO_LOG */ 138: 139: /* our general bus fault handler: */ 140: static int 141: _tme_sun2_bus_fault_handler(struct tme_sun2 *sun2, 142: struct tme_bus_tlb *tlb, 143: struct tme_bus_cycle *cycle, 144: int rc) 145: { 146: tme_uint16_t buserr; 147: 148: /* dispatch on our fault code: */ 149: switch (rc) { 150: 151: /* bus address nonexistent: */ 152: case ENOENT: 153: buserr = TME_SUN2_BUSERR_VALID | TME_SUN2_BUSERR_TIMEOUT; 154: break; 155: 156: /* anything else is just a fault: */ 157: default: 158: buserr = TME_SUN2_BUSERR_VALID; 159: break; 160: } 161: 162: /* set the bus error register: */ 163: sun2->tme_sun2_buserr = buserr; 164: 165: /* log the fault: */ 166: _tme_sun2_bus_fault_log(sun2, tlb, cycle); 167: 168: return (rc); 169: } 170: 171: /* our obio bus fault handler: */ 172: static int 173: _tme_sun2_obio_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) 174: { 175: tme_uint8_t all_bits_one[sizeof(tme_uint16_t)]; 176: 177: /* the sun2 obio bus doesn't generate bus errors, it just reads 178: all-bits-one: */ 179: memset(all_bits_one, 0xff, sizeof(all_bits_one)); 180: tme_bus_cycle_xfer_memory(cycle, 181: &all_bits_one[0] - cycle->tme_bus_cycle_address, 182: cycle->tme_bus_cycle_address + sizeof(all_bits_one)); 183: return (TME_OK); 184: } 185: 186: /* our obmem bus fault handler: */ 187: static int 188: _tme_sun2_obmem_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) 189: { 190: tme_uint8_t all_bits_one[sizeof(tme_uint16_t)]; 191: 192: /* the sun2 obmem bus apparently doesn't generate bus errors below 193: 0x700000, and instead just reads all-bits-one: */ 194: if (cycle->tme_bus_cycle_address < 0x700000) { 195: memset(all_bits_one, 0xff, sizeof(all_bits_one)); 196: tme_bus_cycle_xfer_memory(cycle, 197: &all_bits_one[0] - cycle->tme_bus_cycle_address, 198: cycle->tme_bus_cycle_address + sizeof(all_bits_one)); 199: return (TME_OK); 200: } 201: 202: /* call the common bus fault handler: */ 203: return (_tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc)); 204: } 205: 206: /* our Multibus fault handler: */ 207: static int 208: _tme_sun2_multibus_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) 209: { 210: 211: /* call the common bus fault handler: */ 212: return (_tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc)); 213: } 214: 215: /* our VMEbus fault handler: */ 216: static int 217: _tme_sun2_vmebus_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) 218: { 219: struct tme_sun2 *sun2; 220: 221: /* recover our sun2: */ 222: sun2 = (struct tme_sun2 *) _sun2; 223: 224: /* call the common bus fault handler: */ 225: rc = _tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc); 226: 227: /* this bus fault happened on the VMEbus: */ 228: sun2->tme_sun2_buserr |= TME_SUN2_BUSERR_VMEBUSERR; 229: 230: /* return the fault: */ 231: return (rc); 232: } 233: 234: /* our page-invalid cycle handler: */ 235: static int 236: _tme_sun2_mmu_invalid(void *_sun2, struct tme_bus_cycle *cycle) 237: { 238: struct tme_sun2 *sun2; 239: 240: /* recover our sun2: */ 241: sun2 = (struct tme_sun2 *) _sun2; 242: 243: /* log this bus error: */ 244: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 245: (TME_SUN2_LOG_HANDLE(sun2), 246: _("page invalid bus error"))); 247: 248: /* set the bus error register: */ 249: sun2->tme_sun2_buserr = TME_SUN2_BUSERR_PROTERR; 250: 251: /* return the fault: */ 252: return (EFAULT); 253: } 254: 255: /* our protection error cycle handler: */ 256: static int 257: _tme_sun2_mmu_proterr(void *_sun2, struct tme_bus_cycle *cycle) 258: { 259: struct tme_sun2 *sun2; 260: 261: /* recover our sun2: */ 262: sun2 = (struct tme_sun2 *) _sun2; 263: 264: /* log this bus error: */ 265: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 266: (TME_SUN2_LOG_HANDLE(sun2), 267: _("page protection bus error"))); 268: 269: /* set the bus error register: */ 270: sun2->tme_sun2_buserr = TME_SUN2_BUSERR_VALID | TME_SUN2_BUSERR_PROTERR; 271: 272: /* return the fault: */ 273: return (EFAULT); 274: } 275: 276: /* our m68k TLB filler: */ 277: int 278: _tme_sun2_m68k_tlb_fill(struct tme_m68k_bus_connection *conn_m68k, struct tme_m68k_tlb *tlb_m68k, 279: unsigned int function_code, tme_uint32_t address, unsigned int cycles) 280: { 281: struct tme_sun2 *sun2; 282: struct tme_bus_tlb *tlb; 1.1.1.5 ! root 283: unsigned int function_codes_mask; ! 284: struct tme_bus_tlb tlb_mapping; ! 285: tme_uint32_t context; ! 286: tme_uint32_t access; 1.1 root 287: unsigned short tlb_flags; 288: 289: /* recover our sun2: */ 290: sun2 = (struct tme_sun2 *) conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private; 291: 292: /* get the generic bus TLB: */ 293: tlb = &tlb_m68k->tme_m68k_tlb_bus_tlb; 294: 295: /* if this is function code three, we handle this ourselves: */ 296: if (function_code == TME_M68K_FC_3) { 297: 298: /* initialize the TLB entry: */ 299: tme_bus_tlb_initialize(tlb); 300: 301: /* we cover the entire address space: */ 1.1.1.4 root 302: tlb->tme_bus_tlb_addr_first = 0; 1.1.1.5 ! root 303: tlb->tme_bus_tlb_addr_last = 0 - (tme_bus_addr32_t) 1; 1.1 root 304: 305: /* we allow reading and writing: */ 306: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 307: 308: /* our bus cycle handler: */ 309: tlb->tme_bus_tlb_cycle_private = sun2; 310: tlb->tme_bus_tlb_cycle = _tme_sun2_control_cycle_handler; 311: 312: /* this is good for function code three only: */ 313: tlb_m68k->tme_m68k_tlb_function_codes_mask = TME_BIT(TME_M68K_FC_3); 1.1.1.5 ! root 314: ! 315: /* done: */ ! 316: return (TME_OK); 1.1 root 317: } 318: 1.1.1.5 ! root 319: /* this must be or a user or supervisor program or data function ! 320: code: */ ! 321: assert(function_code == TME_M68K_FC_UD ! 322: || function_code == TME_M68K_FC_UP ! 323: || function_code == TME_M68K_FC_SD ! 324: || function_code == TME_M68K_FC_SP); ! 325: ! 326: /* assume that if this TLB entry ends up good for the supervisor, ! 327: it's good for the supervisor program function code: */ ! 328: function_codes_mask = TME_BIT(TME_M68K_FC_SP); ! 329: ! 330: /* if we're in the boot state: */ ! 331: if (__tme_predict_false((sun2->tme_sun2_enable & TME_SUN2_ENA_NOTBOOT) == 0)) { ! 332: ! 333: /* if this is the supervisor program function code: */ ! 334: if (function_code == TME_M68K_FC_SP) { ! 335: ! 336: /* fill this TLB entry directly from the obmem bus: */ ! 337: (*sun2->tme_sun2_obmem->tme_bus_tlb_fill) ! 338: (sun2->tme_sun2_obmem, ! 339: tlb, ! 340: TME_SUN2_PROM_BASE | (address & (TME_SUN2_PROM_SIZE - 1)), ! 341: cycles); ! 342: ! 343: /* create the mapping TLB entry: */ ! 344: tlb_mapping.tme_bus_tlb_addr_first = address & (((tme_bus_addr32_t) 0) - TME_SUN2_PROM_SIZE); ! 345: tlb_mapping.tme_bus_tlb_addr_last = address | (TME_SUN2_PROM_SIZE - 1); ! 346: tlb_mapping.tme_bus_tlb_cycles_ok ! 347: = TME_BUS_CYCLE_READ; ! 348: ! 349: /* map the filled TLB entry: */ ! 350: tme_bus_tlb_map(tlb, TME_SUN2_PROM_BASE | (address & (TME_SUN2_PROM_SIZE - 1)), &tlb_mapping, address); ! 351: ! 352: /* this is good for the supervisor program function code only: */ ! 353: tlb_m68k->tme_m68k_tlb_function_codes_mask ! 354: = TME_BIT(TME_M68K_FC_SP); ! 355: ! 356: /* done: */ ! 357: return(TME_OK); ! 358: } ! 359: ! 360: /* if this TLB entry ends up good for the supervisor, it's not ! 361: good for the supervisor program function code: */ ! 362: function_codes_mask = 0; 1.1 root 363: } 364: 1.1.1.5 ! root 365: /* start the access: */ ! 366: access ! 367: = ((cycles & TME_BUS_CYCLE_WRITE) ! 368: ? TME_SUN_MMU_PTE_PROT_RW ! 369: : TME_SUN_MMU_PTE_PROT_RO); 1.1 root 370: 1.1.1.5 ! root 371: /* if this is a user program or data function code: */ ! 372: if (function_code == TME_M68K_FC_UD ! 373: || function_code == TME_M68K_FC_UP) { ! 374: context = sun2->tme_sun2_context_user; ! 375: access = TME_SUN_MMU_PTE_PROT_USER(access); ! 376: function_codes_mask = (TME_BIT(TME_M68K_FC_UD) + TME_BIT(TME_M68K_FC_UP)); ! 377: } ! 378: ! 379: /* otherwise, this is a supervisor program or data function code: */ ! 380: else { ! 381: context = sun2->tme_sun2_context_system; ! 382: access = TME_SUN_MMU_PTE_PROT_SYSTEM(access); ! 383: function_codes_mask += TME_BIT(TME_M68K_FC_SD); 1.1 root 384: } 385: 1.1.1.5 ! root 386: /* fill this TLB entry from the MMU: */ ! 387: tlb_flags ! 388: = tme_sun_mmu_tlb_fill(sun2->tme_sun2_mmu, ! 389: tlb, ! 390: context, ! 391: address, ! 392: access); ! 393: ! 394: /* TLB entries are good only for the program and data function ! 395: codes for the user or supervisor, but never both, because ! 396: the two types of accesses go through different contexts: */ ! 397: tlb_m68k->tme_m68k_tlb_function_codes_mask = function_codes_mask; ! 398: 1.1 root 399: return (TME_OK); 400: } 401: 402: /* our bus TLB filler: */ 403: int 404: _tme_sun2_bus_tlb_fill(struct tme_bus_connection *conn_bus, struct tme_bus_tlb *tlb, 1.1.1.5 ! root 405: tme_bus_addr_t address_wider, unsigned int cycles) 1.1 root 406: { 407: struct tme_sun2 *sun2; 1.1.1.5 ! root 408: tme_bus_addr32_t address; 1.1.1.2 root 409: struct tme_sun2_bus_connection *conn_sun2; 410: tme_uint32_t base, size; 411: struct tme_bus_tlb tlb_bus; 1.1 root 412: 413: /* recover our sun2: */ 414: sun2 = (struct tme_sun2 *) conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; 415: 1.1.1.5 ! root 416: /* get the normal-width address: */ ! 417: address = address_wider; ! 418: assert (address == address_wider); ! 419: 1.1.1.2 root 420: /* recover the sun2 internal mainbus connection: */ 421: conn_sun2 = (struct tme_sun2_bus_connection *) conn_bus; 422: 423: /* turn the bus address into a DVMA address: */ 424: switch (conn_sun2->tme_sun2_bus_connection_which) { 425: 426: /* obio devices can actually see the whole address space: */ 427: case TME_SUN2_BUS_OBIO: 428: base = 0x000000; 429: size = 0x1000000; 430: break; 431: 432: case TME_SUN2_BUS_MBMEM: 433: base = 0xf00000; 434: size = TME_SUN2_DVMA_SIZE_MBMEM; 435: break; 436: 437: case TME_SUN2_BUS_VME: 438: base = 0xf00000; 439: size = TME_SUN2_DVMA_SIZE_VME; 440: break; 441: 442: default: abort(); 443: } 444: 445: assert (!(address & base) 446: && (address < size)); 447: 1.1 root 448: /* fill this TLB entry from the MMU: */ 449: tme_sun_mmu_tlb_fill(sun2->tme_sun2_mmu, 450: tlb, 451: sun2->tme_sun2_context_system, 1.1.1.2 root 452: address | base, 1.1 root 453: ((cycles & TME_BUS_CYCLE_WRITE) 454: ? TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) 455: : TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO))); 1.1.1.2 root 456: 457: /* create the mapping TLB entry. we do this even if base == 0, 458: because the TLB entry as currently filled may cover more address 459: space than DVMA space on this machine is supposed to cover: */ 1.1.1.4 root 460: tlb_bus.tme_bus_tlb_addr_first = 0; 461: tlb_bus.tme_bus_tlb_addr_last = size - 1; 1.1.1.2 root 462: tlb_bus.tme_bus_tlb_cycles_ok 463: = (TME_BUS_CYCLE_READ 464: | TME_BUS_CYCLE_WRITE); 465: 466: /* map the filled TLB entry: */ 467: tme_bus_tlb_map(tlb, address | base, &tlb_bus, address); 468: 1.1 root 469: return (TME_OK); 470: } 471: 472: /* our post-MMU TLB filler: */ 473: static int 474: _tme_sun2_tlb_fill_mmu(void *_sun2, struct tme_bus_tlb *tlb, 475: struct tme_sun_mmu_pte *pte, 476: tme_uint32_t *_address, 477: unsigned int cycles) 478: { 479: struct tme_sun2 *sun2; 480: tme_uint32_t address; 481: unsigned int bus_type; 482: struct tme_bus_connection *conn_bus; 483: tme_bus_fault_handler bus_fault_handler; 484: int rc; 485: 486: /* recover our sun2: */ 487: sun2 = (struct tme_sun2 *) _sun2; 488: 489: /* get the physical page frame and bus type: */ 490: address = ((pte->tme_sun_mmu_pte_raw & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2); 491: bus_type = (pte->tme_sun_mmu_pte_raw & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK); 492: 493: /* any mapping of the *first* page of obio space means the PROM. 494: the virtual page frame is actually used to form the physical 495: address: */ 496: if (address == 0 497: && bus_type == TME_SUN2_PGTYPE_OBIO) { 498: address = TME_SUN2_PROM_BASE | (*_address & ((TME_SUN2_PROM_SIZE - 1) & ~(TME_SUN2_PAGE_SIZE - 1))); 499: bus_type = TME_SUN2_PGTYPE_OBMEM; 500: } 501: 502: /* add in the page offset to finish the address: */ 503: address |= *_address & (TME_SUN2_PAGE_SIZE - 1); 504: *_address = address; 505: 506: /* if this is obio: */ 507: if (bus_type == TME_SUN2_PGTYPE_OBIO) { 508: conn_bus = sun2->tme_sun2_obio; 509: bus_fault_handler = _tme_sun2_obio_fault_handler; 510: } 511: 512: /* if this is obmem: */ 513: else if (bus_type == TME_SUN2_PGTYPE_OBMEM) { 514: conn_bus = sun2->tme_sun2_obmem; 515: bus_fault_handler = _tme_sun2_obmem_fault_handler; 516: } 517: 518: /* if this is the VME bus: */ 519: else if (sun2->tme_sun2_has_vme) { 520: 521: if (bus_type == TME_SUN2_PGTYPE_VME8) { 522: address |= 0x800000; 523: } 524: else { 525: assert(bus_type == TME_SUN2_PGTYPE_VME0); 526: } 527: 528: bus_fault_handler = _tme_sun2_vmebus_fault_handler; 529: 530: /* TBD: */ 531: abort(); 532: } 533: 534: /* if this is mbmem: */ 535: else if (bus_type == TME_SUN2_PGTYPE_MBMEM) { 536: conn_bus = sun2->tme_sun2_mbmem; 537: bus_fault_handler = _tme_sun2_multibus_fault_handler; 538: } 539: 540: /* otherwise, this is mbio: */ 541: else { 542: assert(bus_type == TME_SUN2_PGTYPE_MBIO); 543: conn_bus = sun2->tme_sun2_mbio; 544: bus_fault_handler = _tme_sun2_multibus_fault_handler; 545: } 546: 547: /* call the bus TLB filler: */ 548: rc = ((*conn_bus->tme_bus_tlb_fill) 549: (conn_bus, tlb, address, cycles)); 550: 551: /* if the bus TLB filler succeeded, add our bus fault handler: */ 552: if (rc == TME_OK) { 553: TME_BUS_TLB_FAULT_HANDLER(tlb, bus_fault_handler, sun2); 554: } 555: 556: return (rc); 557: } 558: 559: /* this gets a PTE from the MMU: */ 560: int 561: _tme_sun2_mmu_pte_get(struct tme_sun2 *sun2, tme_uint32_t address, tme_uint32_t *_pte_sun2) 562: { 563: struct tme_sun_mmu_pte pte; 564: tme_uint32_t pte_sun2; 565: unsigned int pte_flags; 566: int rc; 567: 568: /* get the PTE from the MMU: */ 569: rc = tme_sun_mmu_pte_get(sun2->tme_sun2_mmu, 570: sun2->tme_sun2_context_user, 571: address, 572: &pte); 573: assert(rc == TME_OK); 574: 575: /* form the Sun-2 PTE: */ 576: pte_sun2 = pte.tme_sun_mmu_pte_raw; 577: pte_flags = pte.tme_sun_mmu_pte_flags; 578: if (pte_flags & TME_SUN_MMU_PTE_REF) { 579: pte_sun2 |= TME_SUN2_PTE_REF; 580: } 581: if (pte_flags & TME_SUN_MMU_PTE_MOD) { 582: pte_sun2 |= TME_SUN2_PTE_MOD; 583: } 584: 585: /* done: */ 586: *_pte_sun2 = pte_sun2; 587: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 588: (TME_SUN2_LOG_HANDLE(sun2), 589: _("pte_get: PGMAP[%d:0x%08x] -> 0x%08x"), 590: sun2->tme_sun2_context_user, 591: address, 592: pte_sun2)); 593: return (TME_OK); 594: } 595: 596: /* this sets a PTE into the MMU: */ 597: int 598: _tme_sun2_mmu_pte_set(struct tme_sun2 *sun2, tme_uint32_t address, tme_uint32_t pte_sun2) 599: { 600: struct tme_sun_mmu_pte pte; 601: unsigned int pte_flags; 602: #ifndef TME_NO_LOG 603: const char *bus_name; 1.1.1.5 ! root 604: tme_bus_addr32_t physical_address; 1.1 root 605: 1.1.1.2 root 606: /* this silences gcc -Wuninitialized: */ 607: bus_name = NULL; 608: 1.1 root 609: /* log this setting: */ 610: physical_address = ((pte_sun2 & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2); 611: switch ((pte_sun2 & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK)) { 612: case TME_SUN2_PGTYPE_OBMEM: bus_name = "obmem"; break; 613: case TME_SUN2_PGTYPE_OBIO: bus_name = "obio"; break; 614: case TME_SUN2_PGTYPE_MBMEM: 615: if (sun2->tme_sun2_has_vme) { 616: bus_name = "VME"; 617: } 618: else { 619: bus_name = "mbmem"; 620: } 621: break; 622: case TME_SUN2_PGTYPE_MBIO: 623: if (sun2->tme_sun2_has_vme) { 624: bus_name = "VME"; 625: physical_address |= 0x800000; 626: } 627: else { 628: bus_name = "mbio"; 629: } 630: break; 631: } 632: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 633: (TME_SUN2_LOG_HANDLE(sun2), 634: _("pte_set: PGMAP[%d:0x%08x] <- 0x%08x (%s 0x%08x)"), 635: sun2->tme_sun2_context_user, 636: address, 637: pte_sun2, 638: bus_name, 639: physical_address)); 640: #endif /* !TME_NO_LOG */ 641: 642: pte.tme_sun_mmu_pte_raw = pte_sun2; 643: 644: pte_flags = 0; 645: if (pte_sun2 & TME_SUN2_PTE_MOD) { 646: pte_flags |= TME_SUN_MMU_PTE_MOD; 647: } 648: if (pte_sun2 & TME_SUN2_PTE_REF) { 649: pte_flags |= TME_SUN_MMU_PTE_REF; 650: } 651: switch (pte_sun2 & TME_SUN2_PTE_PROT) { 652: 653: /* with this protection, the system can read and write, 654: and the user gets a protection error: */ 655: case 0x70000000: 656: case 0x74000000: 657: case 0x60000000: 658: pte_flags |= 659: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) 660: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR)); 661: break; 662: 663: /* with this protection, the system gets a protection error, 664: and the user gets a protection error: */ 665: case 0x30000000: 666: case 0x20000000: 667: case 0x10000000: 668: case 0x00000000: 669: case 0x04000000: 670: pte_flags |= 671: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR) 672: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR)); 673: break; 674: 675: /* with this protection, the system can read and write, 676: and the user can read and write: */ 677: case 0x7C000000: 678: case 0x6C000000: 679: pte_flags |= 680: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) 681: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)); 682: break; 683: 684: /* with this protection, the system can read and write, 685: and the user can read: */ 686: case 0x78000000: 687: pte_flags |= 688: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW) 689: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)); 690: break; 691: 692: /* with this protection, the system can read, 693: and the user can read: */ 694: case 0x58000000: 695: pte_flags |= 696: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO) 697: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)); 698: break; 699: 700: /* with this protection, the system can read, 701: and the user can read and write: */ 702: case 0x5C000000: 703: case 0x4C000000: 704: pte_flags |= 705: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO) 706: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)); 707: break; 708: 709: /* with this protection, the system can read, 710: and the user gets a protection error: */ 711: case 0x50000000: 712: case 0x40000000: 713: pte_flags |= 714: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO) 715: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR)); 716: break; 717: 718: /* with this protection, the system gets a protection error, 719: and the user can read and write: */ 720: case 0x3c000000: 1.1.1.2 root 721: case 0x0c000000: 1.1 root 722: pte_flags |= 723: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR) 724: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)); 725: break; 726: 727: /* with this protection, the system gets a protection error, 728: and the user can read: */ 729: case 0x08000000: 730: pte_flags |= 731: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR) 732: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)); 733: break; 734: 735: default: abort(); 736: } 737: if (pte_sun2 & TME_SUN2_PTE_VALID) { 738: pte_flags |= TME_SUN_MMU_PTE_VALID; 739: } 740: pte.tme_sun_mmu_pte_flags = pte_flags; 741: 742: return (tme_sun_mmu_pte_set(sun2->tme_sun2_mmu, 743: sun2->tme_sun2_context_user, 744: address, 745: &pte)); 746: } 747: 748: /* this is called when the system context register is set: */ 749: void 750: _tme_sun2_mmu_context_system_set(struct tme_sun2 *sun2) 751: { 752: /* system context register changes are assumed to be rare. if they 753: were frequent, we'd have to allocate 64 TLB sets for each TLB 754: user - one for each possible combination of user context and 755: system context. instead, when the system context register 756: changes, we simply invalidate all TLB entries everywhere: */ 757: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, 758: (TME_SUN2_LOG_HANDLE(sun2), 759: _("system context now #%d"), 760: sun2->tme_sun2_context_system)); 761: tme_sun_mmu_tlbs_invalidate(sun2->tme_sun2_mmu); 762: } 763: 764: /* this is called when the user context register is set: */ 765: void 766: _tme_sun2_mmu_context_user_set(struct tme_sun2 *sun2) 767: { 1.1.1.5 ! root 768: tme_bus_context_t context_base; 1.1 root 769: 1.1.1.5 ! root 770: /* NB that even though user and supervisor references use the two ! 771: different context registers simultaneously, TLB entries for one ! 772: are never usable by the other. because of this, and because we ! 773: assume that the system context register rarely changes, we choose ! 774: not to factor the system context into the context seen by the ! 775: m68k: */ 1.1 root 776: 1.1.1.5 ! root 777: /* there are sixteen total contexts. contexts zero through seven ! 778: are the not-boot (normal) contexts. contexts eight through ! 779: fifteen are the same contexts, but in the boot state. 1.1 root 780: 1.1.1.5 ! root 781: in the boot state, TLB fills for supervisor program references ! 782: bypass the MMU and are filled to reference the PROM, and data ! 783: fills are filled as normal using the current context: */ 1.1 root 784: 1.1.1.5 ! root 785: /* in the not-boot (i.e., normal, state): */ ! 786: if (__tme_predict_true(sun2->tme_sun2_enable & TME_SUN2_ENA_NOTBOOT)) { 1.1 root 787: 1.1.1.5 ! root 788: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, ! 789: (TME_SUN2_LOG_HANDLE(sun2), ! 790: _("user context now #%d"), ! 791: sun2->tme_sun2_context_user)); 1.1 root 792: 1.1.1.5 ! root 793: /* the normal state contexts are numbered from zero: */ ! 794: context_base = 0; ! 795: } 1.1 root 796: 1.1.1.5 ! root 797: /* in the boot state: */ ! 798: else { 1.1 root 799: 1.1.1.5 ! root 800: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK, ! 801: (TME_SUN2_LOG_HANDLE(sun2), ! 802: _("user context now #%d (boot state)"), ! 803: sun2->tme_sun2_context_user)); 1.1 root 804: 1.1.1.5 ! root 805: /* the boot state contexts are numbered from eight: */ ! 806: context_base = TME_SUN2_CONTEXT_COUNT; 1.1 root 807: } 808: 1.1.1.5 ! root 809: /* update the m68k bus context register: */ ! 810: *sun2->tme_sun2_m68k_bus_context ! 811: = (context_base ! 812: + sun2->tme_sun2_context_user); ! 813: ! 814: /* NB: unlike the sun3, sun2 DVMA TLBS are always filled using the ! 815: system context, meaning they don't need to be invalidated when ! 816: the user context changes, so we don't need to call ! 817: tme_sun_mmu_context_switched() here: */ 1.1 root 818: } 819: 1.1.1.5 ! root 820: /* this adds a new TLB set: */ 1.1 root 821: int 1.1.1.5 ! root 822: _tme_sun2_mmu_tlb_set_add(struct tme_bus_connection *conn_bus_asker, ! 823: struct tme_bus_tlb_set_info *tlb_set_info) 1.1 root 824: { 1.1.1.5 ! root 825: struct tme_sun2 *sun2; ! 826: int rc; ! 827: ! 828: /* recover our sun2: */ ! 829: sun2 = (struct tme_sun2 *) conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private; ! 830: ! 831: /* add the TLB set to the MMU: */ ! 832: rc = tme_sun_mmu_tlb_set_add(sun2->tme_sun2_mmu, ! 833: tlb_set_info); ! 834: assert (rc == TME_OK); ! 835: ! 836: /* if this is the TLB set from the m68k: */ ! 837: if (conn_bus_asker->tme_bus_connection.tme_connection_type == TME_CONNECTION_BUS_M68K) { ! 838: ! 839: /* the m68k must expose a bus context register: */ ! 840: assert (tlb_set_info->tme_bus_tlb_set_info_bus_context != NULL); ! 841: ! 842: /* save the pointer to the m68k bus context register, and ! 843: initialize it: */ ! 844: sun2->tme_sun2_m68k_bus_context ! 845: = tlb_set_info->tme_bus_tlb_set_info_bus_context; ! 846: _tme_sun2_mmu_context_user_set(sun2); ! 847: ! 848: /* return the maximum context number. there are eight ! 849: contexts in the not-boot (normal) state, and each of ! 850: them has a boot state counterpart: */ ! 851: tlb_set_info->tme_bus_tlb_set_info_bus_context_max ! 852: = (TME_SUN2_CONTEXT_COUNT ! 853: + TME_SUN2_CONTEXT_COUNT ! 854: - 1); 1.1 root 855: } 856: 1.1.1.5 ! root 857: return (rc); 1.1 root 858: } 859: 860: /* this creates a Sun-2 MMU: */ 861: void 862: _tme_sun2_mmu_new(struct tme_sun2 *sun2) 863: { 864: struct tme_sun_mmu_info mmu_info; 865: 1.1.1.4 root 866: memset(&mmu_info, 0, sizeof(mmu_info)); 1.1 root 867: mmu_info.tme_sun_mmu_info_element = sun2->tme_sun2_element; 868: mmu_info.tme_sun_mmu_info_address_bits = 24; 869: mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN2_PAGE_SIZE_LOG2; 870: mmu_info.tme_sun_mmu_info_pteindex_bits = 4; 1.1.1.5 ! root 871: mmu_info.tme_sun_mmu_info_contexts = TME_SUN2_CONTEXT_COUNT; 1.1 root 872: mmu_info.tme_sun_mmu_info_pmegs = 256; 873: mmu_info.tme_sun_mmu_info_tlb_fill_private = sun2; 874: mmu_info.tme_sun_mmu_info_tlb_fill = _tme_sun2_tlb_fill_mmu; 875: mmu_info.tme_sun_mmu_info_proterr_private = sun2; 876: mmu_info.tme_sun_mmu_info_proterr = _tme_sun2_mmu_proterr; 877: mmu_info.tme_sun_mmu_info_invalid_private = sun2; 878: mmu_info.tme_sun_mmu_info_invalid = _tme_sun2_mmu_invalid; 879: sun2->tme_sun2_mmu = tme_sun_mmu_new(&mmu_info); 880: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.