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

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

unix.superglobalmegacorp.com

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