Annotation of tme/machine/sun2/sun2-mmu.c, revision 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.