Annotation of tme/machine/sun2/sun2-mmu.c, revision 1.1.1.5

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.