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

1.1.1.4 ! root        1: /* $Id: sun-mmu.c,v 1.12 2010/02/15 21:55:55 fredette Exp $ */
1.1       root        2: 
                      3: /* machine/sun/sun-mmu.c - classic Sun MMU emulation implementation: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2003 Matt Fredette
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Matt Fredette.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35: 
                     36: #include <tme/common.h>
1.1.1.4 ! root       37: _TME_RCSID("$Id: sun-mmu.c,v 1.12 2010/02/15 21:55:55 fredette Exp $");
1.1       root       38: 
                     39: /* includes: */
                     40: #include <tme/machine/sun.h>
                     41: 
                     42: /* macros: */
                     43: #define TME_SUN_MMU_PMEG_TLBS  (16)
1.1.1.4 ! root       44: #define TME_SUN_MMU_CONTEXT_TLBS       (8)
1.1       root       45: 
                     46: /* structures: */
                     47: 
                     48: /* an allocated TLB set in a classic two-level Sun MMU: */
                     49: struct tme_sun_mmu_tlb_set {
                     50: 
                     51:   /* the next allocated TLB set: */
                     52:   struct tme_sun_mmu_tlb_set *tme_sun_mmu_tlb_set_next;
                     53: 
1.1.1.4 ! root       54:   /* the TLB set information: */
        !            55:   struct tme_bus_tlb_set_info tme_sun_mmu_tlb_set_info;
1.1       root       56: };
                     57: 
                     58: /* one PMEG in a classic two-level Sun MMU: */
                     59: struct tme_sun_mmu_pmeg {
                     60: 
                     61:   /* the current list of TLBs using a page table entry in this PMEG, and
                     62:      the head within that list: */
1.1.1.4 ! root       63:   struct tme_token *tme_sun_mmu_pmeg_tlb_tokens[TME_SUN_MMU_PMEG_TLBS];
1.1       root       64:   unsigned int tme_sun_mmu_pmeg_tlbs_head;
                     65: };
                     66: 
                     67: /* the private structure for a classic two-level Sun MMU: */
                     68: struct tme_sun_mmu {
                     69: 
                     70:   /* the information provided by the user: */
                     71:   struct tme_sun_mmu_info tme_sun_mmu_info;
                     72: #define tme_sun_mmu_element tme_sun_mmu_info.tme_sun_mmu_info_element
                     73: #define tme_sun_mmu_address_bits tme_sun_mmu_info.tme_sun_mmu_info_address_bits
                     74: #define tme_sun_mmu_pgoffset_bits tme_sun_mmu_info.tme_sun_mmu_info_pgoffset_bits
                     75: #define tme_sun_mmu_pteindex_bits tme_sun_mmu_info.tme_sun_mmu_info_pteindex_bits
                     76: #define tme_sun_mmu_contexts tme_sun_mmu_info.tme_sun_mmu_info_contexts
                     77: #define tme_sun_mmu_pmegs_count tme_sun_mmu_info.tme_sun_mmu_info_pmegs
                     78: #define _tme_sun_mmu_tlb_fill_private tme_sun_mmu_info.tme_sun_mmu_info_tlb_fill_private
                     79: #define _tme_sun_mmu_tlb_fill tme_sun_mmu_info.tme_sun_mmu_info_tlb_fill
                     80: 
1.1.1.3   root       81:   /* if nonzero, this address space has a hole, and this has only the
                     82:      last true address bit set: */
                     83:   tme_uint32_t tme_sun_mmu_address_hole_bit;
                     84: 
                     85:   /* a PTE for addresses in the hole.  this is always all-bits-zero: */
                     86:   struct tme_sun_mmu_pte tme_sun_mmu_address_hole_pte;
                     87: 
1.1       root       88:   /* the number of bits in a segment map index: */
                     89:   tme_uint8_t tme_sun_mmu_segment_bits;
                     90: 
                     91:   /* the segment map: */
                     92:   unsigned short *tme_sun_mmu_segment_map;
                     93: 
                     94:   /* the PMEGs: */
                     95:   struct tme_sun_mmu_pmeg *tme_sun_mmu_pmegs;
                     96: 
                     97:   /* the PTEs: */
                     98:   struct tme_sun_mmu_pte *tme_sun_mmu_ptes;
                     99: 
                    100:   /* the allocated TLB sets: */
                    101:   struct tme_sun_mmu_tlb_set *tme_sun_mmu_tlb_sets;
1.1.1.4 ! root      102: 
        !           103:   /* the current list of TLBs that must be invalidated when the
        !           104:      context changes: */
        !           105:   struct tme_token *tme_sun_mmu_context_tlb_tokens[TME_SUN_MMU_CONTEXT_TLBS];
        !           106:   unsigned int tme_sun_mmu_context_tlbs_head;
1.1       root      107: };
                    108: 
                    109: /* this creates a classic two-level Sun MMU: */
                    110: void *
                    111: tme_sun_mmu_new(struct tme_sun_mmu_info *info)
                    112: {
                    113:   struct tme_sun_mmu *mmu;
                    114:   unsigned int segmap_count;
                    115:   unsigned int segmap_i;
                    116: 
                    117:   /* allocate the new private structure: */
                    118:   mmu = tme_new0(struct tme_sun_mmu, 1);
                    119: 
                    120:   /* copy the user-provided information: */
                    121:   mmu->tme_sun_mmu_info = *info;
                    122: 
1.1.1.3   root      123:   /* if there is an address hole: */
                    124:   if (mmu->tme_sun_mmu_info.tme_sun_mmu_info_topindex_bits < 0) {
                    125: 
                    126:     /* there must be 32 address bits: */
                    127:     assert (mmu->tme_sun_mmu_address_bits == 32);
                    128: 
                    129:     /* adjust the number of address bits for the hole: */
                    130:     mmu->tme_sun_mmu_address_bits += (mmu->tme_sun_mmu_info.tme_sun_mmu_info_topindex_bits + 1);
                    131: 
                    132:     /* make the hole address bit: */
                    133:     mmu->tme_sun_mmu_address_hole_bit = TME_BIT(mmu->tme_sun_mmu_address_bits - 1);
                    134: 
                    135:     /* zero the number of top index bits: */
                    136:     mmu->tme_sun_mmu_info.tme_sun_mmu_info_topindex_bits = 0;
                    137:   }
                    138: 
1.1       root      139:   /* allocate the segment map and initialize it to all invalid: */
                    140:   mmu->tme_sun_mmu_segment_bits = (mmu->tme_sun_mmu_address_bits
                    141:                                   - (mmu->tme_sun_mmu_pteindex_bits
                    142:                                      + mmu->tme_sun_mmu_pgoffset_bits));
                    143:   segmap_count = (mmu->tme_sun_mmu_contexts
                    144:                  * (1 << mmu->tme_sun_mmu_segment_bits));
                    145:   mmu->tme_sun_mmu_segment_map = tme_new(unsigned short, segmap_count);
                    146:   for (segmap_i = 0; segmap_i < segmap_count; segmap_i++) {
1.1.1.3   root      147:     mmu->tme_sun_mmu_segment_map[segmap_i] = mmu->tme_sun_mmu_pmegs_count - 1;
1.1       root      148:   }
                    149: 
                    150:   /* allocate the PMEGs: */
                    151:   mmu->tme_sun_mmu_pmegs = tme_new0(struct tme_sun_mmu_pmeg, mmu->tme_sun_mmu_pmegs_count);
                    152: 
                    153:   /* allocate the PTEs: */
                    154:   mmu->tme_sun_mmu_ptes = 
                    155:     tme_new0(struct tme_sun_mmu_pte, 
                    156:             mmu->tme_sun_mmu_pmegs_count
                    157:             * (1 << mmu->tme_sun_mmu_pteindex_bits));
                    158: 
                    159:   /* done: */
                    160:   return (mmu);
                    161: }
                    162: 
                    163: /* given a context and an address, returns the segment map index and
                    164:    PTE: */
                    165: static unsigned short
                    166: _tme_sun_mmu_lookup(struct tme_sun_mmu *mmu, tme_uint8_t context, tme_uint32_t address,
                    167:                    struct tme_sun_mmu_pte **_pte)
                    168: {
                    169:   unsigned short pteindex;
                    170:   unsigned short segment;
                    171:   unsigned short segment_map_index;
                    172:   unsigned short pmeg;
                    173: 
1.1.1.3   root      174:   /* if there is an address hole, and this address is in it: */
                    175:   if (__tme_predict_false(((address
                    176:                            + (address & mmu->tme_sun_mmu_address_hole_bit))
                    177:                           & (((tme_uint32_t) 0)
                    178:                              - mmu->tme_sun_mmu_address_hole_bit)) != 0)) {
                    179: 
                    180:     /* return the hole PTE, and zero for the segment map index: */
                    181:     *_pte = &mmu->tme_sun_mmu_address_hole_pte;
                    182:     return (0);
                    183:   }
                    184: 
1.1       root      185:   /* lose the page offset bits: */
                    186:   address >>= mmu->tme_sun_mmu_pgoffset_bits;
                    187:     
                    188:   /* get the PTE index: */
                    189:   pteindex = (address
                    190:              & (TME_BIT(mmu->tme_sun_mmu_pteindex_bits) - 1));
                    191:   address >>= mmu->tme_sun_mmu_pteindex_bits;
                    192: 
                    193:   /* get the segment number: */
                    194:   segment = (address
                    195:             & (TME_BIT(mmu->tme_sun_mmu_segment_bits) - 1));
                    196: 
                    197:   /* get the segment map index: */
                    198:   segment_map_index = ((context << mmu->tme_sun_mmu_segment_bits)
                    199:                       | segment);
                    200: 
                    201:   /* get the PMEG: */
                    202:   pmeg = mmu->tme_sun_mmu_segment_map[segment_map_index];
                    203: 
                    204:   /* return the segment map index and the PTE: */
                    205:   *_pte = (mmu->tme_sun_mmu_ptes + (pmeg << mmu->tme_sun_mmu_pteindex_bits) + pteindex);
                    206:   return (segment_map_index);
                    207: }
                    208: 
                    209: /* this invalidates all TLB entries that may be affected by changes to
                    210:    a PMEG: */
                    211: static void
                    212: _tme_sun_mmu_pmeg_invalidate(struct tme_sun_mmu *mmu, unsigned short segment_map_index)
                    213: {
                    214:   struct tme_sun_mmu_pmeg *pmeg;
                    215:   int tlb_i;
1.1.1.4 ! root      216:   struct tme_token *token;
1.1       root      217: 
                    218:   /* get the PMEG: */
                    219:   pmeg = mmu->tme_sun_mmu_pmegs + mmu->tme_sun_mmu_segment_map[segment_map_index];
                    220: 
                    221:   /* invalidate all of the TLBs: */
                    222:   for (tlb_i = 0; tlb_i < TME_SUN_MMU_PMEG_TLBS; tlb_i++) {
1.1.1.4 ! root      223:     token = pmeg->tme_sun_mmu_pmeg_tlb_tokens[tlb_i];
        !           224:     pmeg->tme_sun_mmu_pmeg_tlb_tokens[tlb_i] = NULL;
        !           225:     if (token != NULL) {
        !           226:       tme_token_invalidate(token);
1.1       root      227:     }
                    228:   }
                    229: }
                    230: 
                    231: /* this gets a PTE: */
                    232: int
                    233: tme_sun_mmu_pte_get(void *_mmu, tme_uint8_t context, tme_uint32_t address, 
                    234:                    struct tme_sun_mmu_pte *_pte)
                    235: {
                    236:   struct tme_sun_mmu *mmu;
                    237:   unsigned short segment_map_index;
                    238:   struct tme_sun_mmu_pte *pte;
                    239: 
                    240:   /* lookup this address: */
                    241:   mmu = (struct tme_sun_mmu *) _mmu;
                    242:   segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte);
                    243: 
                    244:   /* otherwise, copy the PTE: */
                    245:   *_pte = *pte;
                    246:   return (TME_OK);
                    247: }
                    248: 
                    249: /* this sets a PTE: */
                    250: int
                    251: tme_sun_mmu_pte_set(void *_mmu, tme_uint8_t context, tme_uint32_t address, 
                    252:                    struct tme_sun_mmu_pte *_pte)
                    253: {
                    254:   struct tme_sun_mmu *mmu;
                    255:   unsigned short segment_map_index;
                    256:   struct tme_sun_mmu_pte *pte;
                    257: 
                    258:   /* lookup this address: */
                    259:   mmu = (struct tme_sun_mmu *) _mmu;
                    260:   segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte);
1.1.1.3   root      261:   if (__tme_predict_false(pte == &mmu->tme_sun_mmu_address_hole_pte)) {
                    262:     return (TME_OK);
1.1       root      263:   }
                    264: 
                    265:   /* invalidate all TLB entries that are affected by changes to this PMEG: */
                    266:   _tme_sun_mmu_pmeg_invalidate(mmu, segment_map_index);
                    267: 
                    268:   /* otherwise, copy the PTE: */
                    269:   *pte = *_pte;
                    270:   return (TME_OK);
                    271: }
                    272: 
                    273: /* this gets a segment map entry: */
                    274: unsigned short
                    275: tme_sun_mmu_segmap_get(void *_mmu, tme_uint8_t context, tme_uint32_t address)
                    276: {
                    277:   struct tme_sun_mmu *mmu;
                    278:   struct tme_sun_mmu_pte *pte;
                    279:   unsigned short segment_map_index, pmeg;
                    280: 
                    281:   /* lookup this address: */
                    282:   mmu = (struct tme_sun_mmu *) _mmu;
                    283:   segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte);
1.1.1.3   root      284:   if (__tme_predict_false(pte == &mmu->tme_sun_mmu_address_hole_pte)) {
                    285:     return (mmu->tme_sun_mmu_pmegs_count - 1);
                    286:   }
1.1       root      287:   pmeg = mmu->tme_sun_mmu_segment_map[segment_map_index];
                    288:   tme_log(&mmu->tme_sun_mmu_element->tme_element_log_handle, 1000, TME_OK,
                    289:          (&mmu->tme_sun_mmu_element->tme_element_log_handle,
                    290:           "segmap_get: SEGMAP[%d:0x%08x] -> 0x%04x", 
                    291:           context,
                    292:           address,
                    293:           pmeg));
                    294:   return (pmeg);
                    295: }
                    296: 
                    297: /* this sets a segment map entry: */
                    298: void
                    299: tme_sun_mmu_segmap_set(void *_mmu, tme_uint8_t context, tme_uint32_t address, unsigned short pmeg)
                    300: {
                    301:   struct tme_sun_mmu *mmu;
                    302:   unsigned short segment_map_index;
                    303:   struct tme_sun_mmu_pte *pte;
                    304: 
                    305:   /* lookup this address: */
                    306:   mmu = (struct tme_sun_mmu *) _mmu;
                    307:   segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte);
1.1.1.3   root      308:   if (__tme_predict_false(pte == &mmu->tme_sun_mmu_address_hole_pte)) {
                    309:     return;
1.1       root      310:   }
                    311: 
1.1.1.3   root      312:   /* invalidate all TLB entries that are affected by changes to this
                    313:      PMEG - losing a spot in the segment map counts as such a change: */
                    314:   _tme_sun_mmu_pmeg_invalidate(mmu, segment_map_index);
                    315: 
1.1       root      316:   /* set the new segment: */
                    317:   mmu->tme_sun_mmu_segment_map[segment_map_index] = pmeg;
                    318:   tme_log(&mmu->tme_sun_mmu_element->tme_element_log_handle, 1000, TME_OK,
                    319:          (&mmu->tme_sun_mmu_element->tme_element_log_handle,
                    320:           "segmap_set: SEGMAP[%d:0x%08x] <- 0x%04x", 
                    321:           context,
                    322:           address,
                    323:           pmeg));
                    324: }
                    325: 
                    326: /* this fills a TLB entry: */
                    327: unsigned short
                    328: tme_sun_mmu_tlb_fill(void *_mmu, struct tme_bus_tlb *tlb, 
                    329:                     tme_uint8_t context, tme_uint32_t address, unsigned short access)
                    330: {
                    331:   struct tme_sun_mmu *mmu;
                    332:   unsigned short segment_map_index;
                    333:   struct tme_sun_mmu_pte *pte;
1.1.1.4 ! root      334:   tme_bus_addr32_t addr_first, addr_last;
1.1       root      335:   unsigned short protection, protection_other, tlb_valid_for;
                    336:   tme_uint32_t physical_address;
                    337:   struct tme_sun_mmu_pmeg *pmeg;
1.1.1.4 ! root      338:   struct tme_bus_tlb tlb_virtual;
        !           339:   struct tme_token *token_old;
1.1       root      340:   int tlb_i;
                    341: 
                    342:   /* the access must be a read or write by the system or user: */
                    343:   assert(access != 0
                    344:         && (access == TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)
                    345:             || access == TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
                    346:             || access == TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)
                    347:             || access == TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)));
                    348: 
                    349:   /* lookup this address: */
                    350:   mmu = (struct tme_sun_mmu *) _mmu;
                    351:   segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte);
                    352:   addr_first = (address & ~(TME_BIT(mmu->tme_sun_mmu_pgoffset_bits) - 1));
                    353:   addr_last = (address | (TME_BIT(mmu->tme_sun_mmu_pgoffset_bits) - 1));
                    354: 
                    355:   /* remember this TLB entry in the PMEG: */
1.1.1.3   root      356:   if (__tme_predict_true(pte != &mmu->tme_sun_mmu_address_hole_pte)) {
                    357:     pmeg = mmu->tme_sun_mmu_pmegs + mmu->tme_sun_mmu_segment_map[segment_map_index];
                    358:     tlb_i = pmeg->tme_sun_mmu_pmeg_tlbs_head;
1.1.1.4 ! root      359:     token_old = pmeg->tme_sun_mmu_pmeg_tlb_tokens[tlb_i];
        !           360:     if (token_old != NULL
        !           361:        && token_old != tlb->tme_bus_tlb_token) {
        !           362:       tme_token_invalidate(token_old);
1.1.1.3   root      363:     }
1.1.1.4 ! root      364:     pmeg->tme_sun_mmu_pmeg_tlb_tokens[tlb_i]
        !           365:       = tlb->tme_bus_tlb_token;
1.1.1.3   root      366:     pmeg->tme_sun_mmu_pmeg_tlbs_head = (tlb_i + 1) & (TME_SUN_MMU_PMEG_TLBS - 1);
                    367:   }
1.1       root      368: 
                    369:   /* if this page is invalid, return the page-invalid cycle handler,
                    370:      which is valid for reading and writing for the user and system: */
                    371:   if (!(pte->tme_sun_mmu_pte_flags & TME_SUN_MMU_PTE_VALID)) {
                    372:     tme_bus_tlb_initialize(tlb);
1.1.1.3   root      373:     tlb->tme_bus_tlb_addr_first = addr_first;
                    374:     tlb->tme_bus_tlb_addr_last = addr_last;
1.1       root      375:     tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    376:     tlb->tme_bus_tlb_cycle_private = mmu->tme_sun_mmu_info.tme_sun_mmu_info_invalid_private;
                    377:     tlb->tme_bus_tlb_cycle = mmu->tme_sun_mmu_info.tme_sun_mmu_info_invalid;
                    378:     return (TME_SUN_MMU_TLB_SYSTEM | TME_SUN_MMU_TLB_USER);
                    379:   }
                    380: 
                    381:   /* otherwise, this page is valid.  get the relevant part of the
                    382:      protection for this accessor (system or user), the part of the
                    383:      protection covering the other accessor (system or user), adjust
                    384:      "access" to be an unshifted TME_SUN_MMU_PTE_PROT_ value, and get
                    385:      the accessor (user or system) that this TLB entry will definitely
                    386:      be valid for: */
                    387:   protection = pte->tme_sun_mmu_pte_flags;
                    388:   if (access & TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_MASK)) {
                    389:     protection_other = protection / TME_SUN_MMU_PTE_PROT_USER(1);
                    390:     access /= TME_SUN_MMU_PTE_PROT_SYSTEM(1);
                    391:     protection /= TME_SUN_MMU_PTE_PROT_SYSTEM(1);
                    392:     tlb_valid_for = TME_SUN_MMU_TLB_SYSTEM;
                    393:   }
                    394:   else {
                    395:     protection_other = protection / TME_SUN_MMU_PTE_PROT_SYSTEM(1);
                    396:     access /= TME_SUN_MMU_PTE_PROT_USER(1);
                    397:     protection /= TME_SUN_MMU_PTE_PROT_USER(1);
                    398:     tlb_valid_for = TME_SUN_MMU_TLB_USER;
                    399:   }
                    400: 
                    401:   /* NB that the following code assumes a particular ordering of
                    402:      TME_SUN_MMU_PTE_PROT_ values.  specifically, it assumes that
                    403:      ABORT < ERROR < RO < RW: */
                    404: 
                    405:   /* if the part of the protection covering the other accessor (system
                    406:      or user) allows at least as much access as the relevant part of
                    407:      the protection, this TLB entry will be valid for that other
                    408:      successor as well.  we rely on particular definitions of the
                    409:      TME_SUN_MMU_TLB_ macros to make this fast: */
                    410: #if (3 - TME_SUN_MMU_TLB_SYSTEM) != TME_SUN_MMU_TLB_USER
                    411: #error "TME_SUN_MMU_TLB_USER and TME_SUN_MMU_TLB_SYSTEM are incompatible"
                    412: #endif
                    413:   protection &= TME_SUN_MMU_PTE_PROT_MASK;
                    414:   protection_other &= TME_SUN_MMU_PTE_PROT_MASK;
                    415:   if (protection_other >= protection) {
                    416:     tlb_valid_for |= (3 - tlb_valid_for);
                    417:   }
                    418: 
                    419:   /* if the access is protected, return the protection-error cycle
                    420:      handler: */
                    421:   if (protection < access) {
                    422:     if (protection == TME_SUN_MMU_PTE_PROT_ABORT) {
                    423:       abort();
                    424:     }
                    425:     tme_bus_tlb_initialize(tlb);
1.1.1.3   root      426:     tlb->tme_bus_tlb_addr_first = addr_first;
                    427:     tlb->tme_bus_tlb_addr_last = addr_last;
1.1       root      428:     tlb->tme_bus_tlb_cycles_ok = (TME_BUS_CYCLE_WRITE
                    429:                                  | (protection == TME_SUN_MMU_PTE_PROT_ERROR
                    430:                                     ? TME_BUS_CYCLE_READ
                    431:                                     : 0));
                    432:     tlb->tme_bus_tlb_cycle_private = mmu->tme_sun_mmu_info.tme_sun_mmu_info_proterr_private;
                    433:     tlb->tme_bus_tlb_cycle = mmu->tme_sun_mmu_info.tme_sun_mmu_info_proterr;
                    434:     return (tlb_valid_for);
                    435:   }
                    436: 
                    437:   /* this access is OK.  fill the TLB with physical bus information.
                    438:      we pass in the virtual address as the initial physical address
                    439:      because sometimes the virtual part of the address can influence
                    440:      the physical address (as in the Sun-2 PROM mapping): */
                    441:   physical_address = address;
                    442:   (*mmu->_tme_sun_mmu_tlb_fill)
                    443:     (mmu->_tme_sun_mmu_tlb_fill_private, 
                    444:      tlb, 
                    445:      pte,
                    446:      &physical_address,
                    447:      ((access == TME_SUN_MMU_PTE_PROT_RW)
                    448:       ? TME_BUS_CYCLE_WRITE
                    449:       : TME_BUS_CYCLE_READ));
                    450: 
                    451:   /* create the mapping TLB entry, and update the PTE flags: */
1.1.1.3   root      452:   tlb_virtual.tme_bus_tlb_addr_first = addr_first;
                    453:   tlb_virtual.tme_bus_tlb_addr_last = addr_last;
1.1       root      454:   pte->tme_sun_mmu_pte_flags |= TME_SUN_MMU_PTE_REF;
                    455:   tlb_virtual.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ;
                    456:   if (access == TME_SUN_MMU_PTE_PROT_RW) {
                    457:     pte->tme_sun_mmu_pte_flags |= TME_SUN_MMU_PTE_MOD;
                    458:   }
1.1.1.2   root      459:   if (protection == TME_SUN_MMU_PTE_PROT_RW
                    460:       && (pte->tme_sun_mmu_pte_flags & TME_SUN_MMU_PTE_MOD)) {
1.1       root      461:     tlb_virtual.tme_bus_tlb_cycles_ok |= TME_BUS_CYCLE_WRITE;
                    462:   }
                    463:   
                    464:   /* map the filled TLB entry: */
                    465:   tme_bus_tlb_map(tlb, physical_address, &tlb_virtual, address);
                    466: 
                    467:   /* return who this TLB entry is good for: */
                    468:   return (tlb_valid_for);
                    469: }
                    470: 
                    471: /* this invalidates all TLB entries in all TLB sets: */
                    472: void
                    473: tme_sun_mmu_tlbs_invalidate(void *_mmu)
                    474: {
                    475:   struct tme_sun_mmu *mmu;
                    476:   struct tme_sun_mmu_tlb_set *tlb_set;
                    477: 
                    478:   /* recover our MMU: */
                    479:   mmu = (struct tme_sun_mmu *) _mmu;
                    480: 
                    481:   /* invalidate all TLB entries in all sets: */
                    482:   for (tlb_set = mmu->tme_sun_mmu_tlb_sets;
                    483:        tlb_set != NULL;
                    484:        tlb_set = tlb_set->tme_sun_mmu_tlb_set_next) {
1.1.1.4 ! root      485:     tme_bus_tlb_set_invalidate(&tlb_set->tme_sun_mmu_tlb_set_info);
1.1       root      486:   }
                    487: }
                    488: 
1.1.1.4 ! root      489: /* this adds a TLB entry as dependent on the current context: */
1.1       root      490: void
1.1.1.4 ! root      491: tme_sun_mmu_context_add(void *_mmu,
        !           492:                        const struct tme_bus_tlb *tlb)
1.1       root      493: {
                    494:   struct tme_sun_mmu *mmu;
1.1.1.4 ! root      495:   tme_uint32_t address;
        !           496:   tme_uint32_t segment_bits;
        !           497:   tme_uint32_t segments_per_context;
        !           498:   signed long segment_map_index;
        !           499:   tme_uint32_t pmeg;
        !           500:   unsigned long tlb_i;
        !           501:   struct tme_token *token_old;
1.1       root      502: 
                    503:   /* recover our MMU: */
                    504:   mmu = (struct tme_sun_mmu *) _mmu;
                    505: 
1.1.1.4 ! root      506:   /* get the address used with the MMU: */
        !           507:   /* NB: if there is an address hole, this address could be in it.  if
        !           508:      it is, it doesn't matter if we decide that this TLB entry is
        !           509:      valid in all contexts or not - this TLB entry never needs to be
        !           510:      invalidated because of a context change: */
        !           511:   address = tlb->tme_bus_tlb_addr_first;
        !           512: 
        !           513:   /* get the number of bits in a segment number: */
        !           514:   segment_bits = mmu->tme_sun_mmu_segment_bits;
        !           515: 
        !           516:   /* get the number of segment map entries per context: */
        !           517:   segments_per_context = 1 << segment_bits;
        !           518: 
        !           519:   /* get the segment map index for this address in the last
        !           520:      context: */
        !           521:   segment_map_index
        !           522:     = (((address
        !           523:         >> (mmu->tme_sun_mmu_pgoffset_bits
        !           524:             + mmu->tme_sun_mmu_pteindex_bits))
        !           525:        & (segments_per_context - 1))
        !           526:        + ((mmu->tme_sun_mmu_contexts - 1)
        !           527:          << segment_bits));
        !           528: 
        !           529:   /* get the PMEG for this address in the last context: */
        !           530:   pmeg = mmu->tme_sun_mmu_segment_map[segment_map_index];
        !           531: 
        !           532:   /* there must be at least two contexts: */
        !           533:   assert (mmu->tme_sun_mmu_contexts >= 2);
        !           534: 
        !           535:   /* loop over the segment map indices for this address in all other
        !           536:      contexts: */
        !           537:   segment_map_index -= segments_per_context;
        !           538:   do {
        !           539: 
        !           540:     /* if the PMEG for this address in this context is different: */
        !           541:     if (__tme_predict_false(mmu->tme_sun_mmu_segment_map[segment_map_index] != pmeg)) {
        !           542: 
        !           543:       /* this address doesn't have the same mapping in all contexts,
        !           544:         so we must invalidate this TLB entry when the context
        !           545:         changes: */
        !           546:       tlb_i = mmu->tme_sun_mmu_context_tlbs_head;
        !           547:       token_old = mmu->tme_sun_mmu_context_tlb_tokens[tlb_i];
        !           548:       if (token_old != NULL
        !           549:          && token_old != tlb->tme_bus_tlb_token) {
        !           550:        tme_token_invalidate(token_old);
        !           551:       }
        !           552:       mmu->tme_sun_mmu_context_tlb_tokens[tlb_i] = tlb->tme_bus_tlb_token;
        !           553:       mmu->tme_sun_mmu_context_tlbs_head = (tlb_i + 1) % TME_SUN_MMU_CONTEXT_TLBS;
        !           554: 
        !           555:       return;
        !           556:     }
        !           557: 
        !           558:   } while ((segment_map_index -= segments_per_context) >= 0);
        !           559: 
        !           560:   /* this address has the same mapping in all contexts, so we don't
        !           561:      need to invalidate this TLB entry when the context changes: */
        !           562: }
        !           563: 
        !           564: /* this is called after a context switch, to invalidate TLB entries
        !           565:    that were dependent on the previous context: */
        !           566: void
        !           567: tme_sun_mmu_context_switched(void *_mmu)
        !           568: {
        !           569:   struct tme_sun_mmu *mmu;
        !           570:   signed long tlb_i;
        !           571:   struct tme_token *token;
        !           572: 
        !           573:   /* recover our MMU: */
        !           574:   mmu = (struct tme_sun_mmu *) _mmu;
        !           575: 
        !           576:   /* invalidate all of the TLBs that depended on the previous
        !           577:      context: */
        !           578:   tlb_i = TME_SUN_MMU_CONTEXT_TLBS - 1;
        !           579:   do {
        !           580:     token = mmu->tme_sun_mmu_context_tlb_tokens[tlb_i];
        !           581:     mmu->tme_sun_mmu_context_tlb_tokens[tlb_i] = NULL;
        !           582:     if (token != NULL) {
        !           583:       tme_token_invalidate(token);
        !           584:     }
        !           585:   } while (--tlb_i >= 0);
1.1       root      586: }
                    587: 
1.1.1.4 ! root      588: /* this adds a new TLB set: */
1.1       root      589: int
1.1.1.4 ! root      590: tme_sun_mmu_tlb_set_add(void *_mmu,
        !           591:                        struct tme_bus_tlb_set_info *tlb_set_info)
1.1       root      592: {
                    593:   struct tme_sun_mmu *mmu;
                    594:   struct tme_sun_mmu_tlb_set *tlb_set;
                    595: 
                    596:   /* recover our mmu: */
                    597:   mmu = (struct tme_sun_mmu *) _mmu;
                    598: 
                    599:   /* remember this set: */
                    600:   tlb_set = tme_new0(struct tme_sun_mmu_tlb_set, 1);
                    601:   tlb_set->tme_sun_mmu_tlb_set_next = mmu->tme_sun_mmu_tlb_sets;
1.1.1.4 ! root      602:   tlb_set->tme_sun_mmu_tlb_set_info = *tlb_set_info;
1.1       root      603:   mmu->tme_sun_mmu_tlb_sets = tlb_set;
                    604:   
                    605:   return (TME_OK);
                    606: }
                    607: 

unix.superglobalmegacorp.com

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