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

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

unix.superglobalmegacorp.com

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