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

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

unix.superglobalmegacorp.com

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