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

1.1.1.3 ! root        1: /* $Id: sun-mmu.c,v 1.11 2006/11/16 02:37:05 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.3 ! root       37: _TME_RCSID("$Id: sun-mmu.c,v 1.11 2006/11/16 02:37:05 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)
                     44: 
                     45: /* structures: */
                     46: 
                     47: /* an allocated TLB set in a classic two-level Sun MMU: */
                     48: struct tme_sun_mmu_tlb_set {
                     49: 
                     50:   /* the next allocated TLB set: */
                     51:   struct tme_sun_mmu_tlb_set *tme_sun_mmu_tlb_set_next;
                     52: 
                     53:   /* the user's pointer into the TLB set: */
1.1.1.3 ! root       54:   struct tme_bus_tlb * tme_shared *tme_sun_mmu_tlb_set_pointer;
        !            55:   tme_rwlock_t *tme_sun_mmu_tlb_set_pointer_rwlock;
1.1       root       56: 
                     57:   /* the base of this TLB set: */
                     58:   struct tme_bus_tlb *tme_sun_mmu_tlb_set_base;
                     59: 
                     60:   /* the size of one TLB entry: */
                     61:   unsigned int tme_sun_mmu_tlb_set_sizeof_one;
                     62: 
                     63:   /* the number of TLB entries per context in the set: */
                     64:   unsigned int tme_sun_mmu_tlb_set_count;
                     65: };
                     66: 
                     67: /* one PMEG in a classic two-level Sun MMU: */
                     68: struct tme_sun_mmu_pmeg {
                     69: 
                     70:   /* the current list of TLBs using a page table entry in this PMEG, and
                     71:      the head within that list: */
                     72:   struct tme_bus_tlb *tme_sun_mmu_pmeg_tlbs[TME_SUN_MMU_PMEG_TLBS];
                     73:   unsigned int tme_sun_mmu_pmeg_tlbs_head;
                     74: };
                     75: 
                     76: /* the private structure for a classic two-level Sun MMU: */
                     77: struct tme_sun_mmu {
                     78: 
                     79:   /* the information provided by the user: */
                     80:   struct tme_sun_mmu_info tme_sun_mmu_info;
                     81: #define tme_sun_mmu_element tme_sun_mmu_info.tme_sun_mmu_info_element
                     82: #define tme_sun_mmu_address_bits tme_sun_mmu_info.tme_sun_mmu_info_address_bits
                     83: #define tme_sun_mmu_pgoffset_bits tme_sun_mmu_info.tme_sun_mmu_info_pgoffset_bits
                     84: #define tme_sun_mmu_pteindex_bits tme_sun_mmu_info.tme_sun_mmu_info_pteindex_bits
                     85: #define tme_sun_mmu_contexts tme_sun_mmu_info.tme_sun_mmu_info_contexts
                     86: #define tme_sun_mmu_pmegs_count tme_sun_mmu_info.tme_sun_mmu_info_pmegs
                     87: #define _tme_sun_mmu_tlb_fill_private tme_sun_mmu_info.tme_sun_mmu_info_tlb_fill_private
                     88: #define _tme_sun_mmu_tlb_fill tme_sun_mmu_info.tme_sun_mmu_info_tlb_fill
                     89: 
1.1.1.3 ! root       90:   /* if nonzero, this address space has a hole, and this has only the
        !            91:      last true address bit set: */
        !            92:   tme_uint32_t tme_sun_mmu_address_hole_bit;
        !            93: 
        !            94:   /* a PTE for addresses in the hole.  this is always all-bits-zero: */
        !            95:   struct tme_sun_mmu_pte tme_sun_mmu_address_hole_pte;
        !            96: 
1.1       root       97:   /* the number of bits in a segment map index: */
                     98:   tme_uint8_t tme_sun_mmu_segment_bits;
                     99: 
                    100:   /* the segment map: */
                    101:   unsigned short *tme_sun_mmu_segment_map;
                    102: 
                    103:   /* the PMEGs: */
                    104:   struct tme_sun_mmu_pmeg *tme_sun_mmu_pmegs;
                    105: 
                    106:   /* the PTEs: */
                    107:   struct tme_sun_mmu_pte *tme_sun_mmu_ptes;
                    108: 
                    109:   /* the allocated TLB sets: */
                    110:   struct tme_sun_mmu_tlb_set *tme_sun_mmu_tlb_sets;
                    111: };
                    112: 
                    113: /* this creates a classic two-level Sun MMU: */
                    114: void *
                    115: tme_sun_mmu_new(struct tme_sun_mmu_info *info)
                    116: {
                    117:   struct tme_sun_mmu *mmu;
                    118:   unsigned int segmap_count;
                    119:   unsigned int segmap_i;
                    120: 
                    121:   /* allocate the new private structure: */
                    122:   mmu = tme_new0(struct tme_sun_mmu, 1);
                    123: 
                    124:   /* copy the user-provided information: */
                    125:   mmu->tme_sun_mmu_info = *info;
                    126: 
1.1.1.3 ! root      127:   /* if there is an address hole: */
        !           128:   if (mmu->tme_sun_mmu_info.tme_sun_mmu_info_topindex_bits < 0) {
        !           129: 
        !           130:     /* there must be 32 address bits: */
        !           131:     assert (mmu->tme_sun_mmu_address_bits == 32);
        !           132: 
        !           133:     /* adjust the number of address bits for the hole: */
        !           134:     mmu->tme_sun_mmu_address_bits += (mmu->tme_sun_mmu_info.tme_sun_mmu_info_topindex_bits + 1);
        !           135: 
        !           136:     /* make the hole address bit: */
        !           137:     mmu->tme_sun_mmu_address_hole_bit = TME_BIT(mmu->tme_sun_mmu_address_bits - 1);
        !           138: 
        !           139:     /* zero the number of top index bits: */
        !           140:     mmu->tme_sun_mmu_info.tme_sun_mmu_info_topindex_bits = 0;
        !           141:   }
        !           142: 
1.1       root      143:   /* allocate the segment map and initialize it to all invalid: */
                    144:   mmu->tme_sun_mmu_segment_bits = (mmu->tme_sun_mmu_address_bits
                    145:                                   - (mmu->tme_sun_mmu_pteindex_bits
                    146:                                      + mmu->tme_sun_mmu_pgoffset_bits));
                    147:   segmap_count = (mmu->tme_sun_mmu_contexts
                    148:                  * (1 << mmu->tme_sun_mmu_segment_bits));
                    149:   mmu->tme_sun_mmu_segment_map = tme_new(unsigned short, segmap_count);
                    150:   for (segmap_i = 0; segmap_i < segmap_count; segmap_i++) {
1.1.1.3 ! root      151:     mmu->tme_sun_mmu_segment_map[segmap_i] = mmu->tme_sun_mmu_pmegs_count - 1;
1.1       root      152:   }
                    153: 
                    154:   /* allocate the PMEGs: */
                    155:   mmu->tme_sun_mmu_pmegs = tme_new0(struct tme_sun_mmu_pmeg, mmu->tme_sun_mmu_pmegs_count);
                    156: 
                    157:   /* allocate the PTEs: */
                    158:   mmu->tme_sun_mmu_ptes = 
                    159:     tme_new0(struct tme_sun_mmu_pte, 
                    160:             mmu->tme_sun_mmu_pmegs_count
                    161:             * (1 << mmu->tme_sun_mmu_pteindex_bits));
                    162: 
                    163:   /* done: */
                    164:   return (mmu);
                    165: }
                    166: 
                    167: /* given a context and an address, returns the segment map index and
                    168:    PTE: */
                    169: static unsigned short
                    170: _tme_sun_mmu_lookup(struct tme_sun_mmu *mmu, tme_uint8_t context, tme_uint32_t address,
                    171:                    struct tme_sun_mmu_pte **_pte)
                    172: {
                    173:   unsigned short pteindex;
                    174:   unsigned short segment;
                    175:   unsigned short segment_map_index;
                    176:   unsigned short pmeg;
                    177: 
1.1.1.3 ! root      178:   /* if there is an address hole, and this address is in it: */
        !           179:   if (__tme_predict_false(((address
        !           180:                            + (address & mmu->tme_sun_mmu_address_hole_bit))
        !           181:                           & (((tme_uint32_t) 0)
        !           182:                              - mmu->tme_sun_mmu_address_hole_bit)) != 0)) {
        !           183: 
        !           184:     /* return the hole PTE, and zero for the segment map index: */
        !           185:     *_pte = &mmu->tme_sun_mmu_address_hole_pte;
        !           186:     return (0);
        !           187:   }
        !           188: 
1.1       root      189:   /* lose the page offset bits: */
                    190:   address >>= mmu->tme_sun_mmu_pgoffset_bits;
                    191:     
                    192:   /* get the PTE index: */
                    193:   pteindex = (address
                    194:              & (TME_BIT(mmu->tme_sun_mmu_pteindex_bits) - 1));
                    195:   address >>= mmu->tme_sun_mmu_pteindex_bits;
                    196: 
                    197:   /* get the segment number: */
                    198:   segment = (address
                    199:             & (TME_BIT(mmu->tme_sun_mmu_segment_bits) - 1));
                    200: 
                    201:   /* get the segment map index: */
                    202:   segment_map_index = ((context << mmu->tme_sun_mmu_segment_bits)
                    203:                       | segment);
                    204: 
                    205:   /* get the PMEG: */
                    206:   pmeg = mmu->tme_sun_mmu_segment_map[segment_map_index];
                    207: 
                    208:   /* return the segment map index and the PTE: */
                    209:   *_pte = (mmu->tme_sun_mmu_ptes + (pmeg << mmu->tme_sun_mmu_pteindex_bits) + pteindex);
                    210:   return (segment_map_index);
                    211: }
                    212: 
                    213: /* this invalidates all TLB entries that may be affected by changes to
                    214:    a PMEG: */
                    215: static void
                    216: _tme_sun_mmu_pmeg_invalidate(struct tme_sun_mmu *mmu, unsigned short segment_map_index)
                    217: {
                    218:   struct tme_sun_mmu_pmeg *pmeg;
                    219:   int tlb_i;
                    220:   struct tme_bus_tlb *tlb;
                    221: 
                    222:   /* get the PMEG: */
                    223:   pmeg = mmu->tme_sun_mmu_pmegs + mmu->tme_sun_mmu_segment_map[segment_map_index];
                    224: 
                    225:   /* invalidate all of the TLBs: */
                    226:   for (tlb_i = 0; tlb_i < TME_SUN_MMU_PMEG_TLBS; tlb_i++) {
                    227:     tlb = pmeg->tme_sun_mmu_pmeg_tlbs[tlb_i];
                    228:     pmeg->tme_sun_mmu_pmeg_tlbs[tlb_i] = NULL;
                    229:     if (tlb != NULL) {
                    230:       tme_bus_tlb_invalidate(tlb);
                    231:     }
                    232:   }
                    233: }
                    234: 
                    235: /* this gets a PTE: */
                    236: int
                    237: tme_sun_mmu_pte_get(void *_mmu, tme_uint8_t context, tme_uint32_t address, 
                    238:                    struct tme_sun_mmu_pte *_pte)
                    239: {
                    240:   struct tme_sun_mmu *mmu;
                    241:   unsigned short segment_map_index;
                    242:   struct tme_sun_mmu_pte *pte;
                    243: 
                    244:   /* lookup this address: */
                    245:   mmu = (struct tme_sun_mmu *) _mmu;
                    246:   segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte);
                    247: 
                    248:   /* otherwise, copy the PTE: */
                    249:   *_pte = *pte;
                    250:   return (TME_OK);
                    251: }
                    252: 
                    253: /* this sets a PTE: */
                    254: int
                    255: tme_sun_mmu_pte_set(void *_mmu, tme_uint8_t context, tme_uint32_t address, 
                    256:                    struct tme_sun_mmu_pte *_pte)
                    257: {
                    258:   struct tme_sun_mmu *mmu;
                    259:   unsigned short segment_map_index;
                    260:   struct tme_sun_mmu_pte *pte;
                    261: 
                    262:   /* lookup this address: */
                    263:   mmu = (struct tme_sun_mmu *) _mmu;
                    264:   segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte);
1.1.1.3 ! root      265:   if (__tme_predict_false(pte == &mmu->tme_sun_mmu_address_hole_pte)) {
        !           266:     return (TME_OK);
1.1       root      267:   }
                    268: 
                    269:   /* invalidate all TLB entries that are affected by changes to this PMEG: */
                    270:   _tme_sun_mmu_pmeg_invalidate(mmu, segment_map_index);
                    271: 
                    272:   /* otherwise, copy the PTE: */
                    273:   *pte = *_pte;
                    274:   return (TME_OK);
                    275: }
                    276: 
                    277: /* this gets a segment map entry: */
                    278: unsigned short
                    279: tme_sun_mmu_segmap_get(void *_mmu, tme_uint8_t context, tme_uint32_t address)
                    280: {
                    281:   struct tme_sun_mmu *mmu;
                    282:   struct tme_sun_mmu_pte *pte;
                    283:   unsigned short segment_map_index, pmeg;
                    284: 
                    285:   /* lookup this address: */
                    286:   mmu = (struct tme_sun_mmu *) _mmu;
                    287:   segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte);
1.1.1.3 ! root      288:   if (__tme_predict_false(pte == &mmu->tme_sun_mmu_address_hole_pte)) {
        !           289:     return (mmu->tme_sun_mmu_pmegs_count - 1);
        !           290:   }
1.1       root      291:   pmeg = mmu->tme_sun_mmu_segment_map[segment_map_index];
                    292:   tme_log(&mmu->tme_sun_mmu_element->tme_element_log_handle, 1000, TME_OK,
                    293:          (&mmu->tme_sun_mmu_element->tme_element_log_handle,
                    294:           "segmap_get: SEGMAP[%d:0x%08x] -> 0x%04x", 
                    295:           context,
                    296:           address,
                    297:           pmeg));
                    298:   return (pmeg);
                    299: }
                    300: 
                    301: /* this sets a segment map entry: */
                    302: void
                    303: tme_sun_mmu_segmap_set(void *_mmu, tme_uint8_t context, tme_uint32_t address, unsigned short pmeg)
                    304: {
                    305:   struct tme_sun_mmu *mmu;
                    306:   unsigned short segment_map_index;
                    307:   struct tme_sun_mmu_pte *pte;
                    308: 
                    309:   /* lookup this address: */
                    310:   mmu = (struct tme_sun_mmu *) _mmu;
                    311:   segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte);
1.1.1.3 ! root      312:   if (__tme_predict_false(pte == &mmu->tme_sun_mmu_address_hole_pte)) {
        !           313:     return;
1.1       root      314:   }
                    315: 
1.1.1.3 ! root      316:   /* invalidate all TLB entries that are affected by changes to this
        !           317:      PMEG - losing a spot in the segment map counts as such a change: */
        !           318:   _tme_sun_mmu_pmeg_invalidate(mmu, segment_map_index);
        !           319: 
1.1       root      320:   /* set the new segment: */
                    321:   mmu->tme_sun_mmu_segment_map[segment_map_index] = pmeg;
                    322:   tme_log(&mmu->tme_sun_mmu_element->tme_element_log_handle, 1000, TME_OK,
                    323:          (&mmu->tme_sun_mmu_element->tme_element_log_handle,
                    324:           "segmap_set: SEGMAP[%d:0x%08x] <- 0x%04x", 
                    325:           context,
                    326:           address,
                    327:           pmeg));
                    328: }
                    329: 
                    330: /* this fills a TLB entry: */
                    331: unsigned short
                    332: tme_sun_mmu_tlb_fill(void *_mmu, struct tme_bus_tlb *tlb, 
                    333:                     tme_uint8_t context, tme_uint32_t address, unsigned short access)
                    334: {
                    335:   struct tme_sun_mmu *mmu;
                    336:   unsigned short segment_map_index;
                    337:   struct tme_sun_mmu_pte *pte;
                    338:   tme_bus_addr_t addr_first, addr_last;
                    339:   unsigned short protection, protection_other, tlb_valid_for;
                    340:   tme_uint32_t physical_address;
                    341:   struct tme_sun_mmu_pmeg *pmeg;
                    342:   struct tme_bus_tlb tlb_virtual, *tlb_old;
                    343:   int tlb_i;
                    344: 
                    345:   /* the access must be a read or write by the system or user: */
                    346:   assert(access != 0
                    347:         && (access == TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)
                    348:             || access == TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
                    349:             || access == TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)
                    350:             || access == TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)));
                    351: 
                    352:   /* lookup this address: */
                    353:   mmu = (struct tme_sun_mmu *) _mmu;
                    354:   segment_map_index = _tme_sun_mmu_lookup(mmu, context, address, &pte);
                    355:   addr_first = (address & ~(TME_BIT(mmu->tme_sun_mmu_pgoffset_bits) - 1));
                    356:   addr_last = (address | (TME_BIT(mmu->tme_sun_mmu_pgoffset_bits) - 1));
                    357: 
                    358:   /* remember this TLB entry in the PMEG: */
1.1.1.3 ! root      359:   if (__tme_predict_true(pte != &mmu->tme_sun_mmu_address_hole_pte)) {
        !           360:     pmeg = mmu->tme_sun_mmu_pmegs + mmu->tme_sun_mmu_segment_map[segment_map_index];
        !           361:     tlb_i = pmeg->tme_sun_mmu_pmeg_tlbs_head;
        !           362:     tlb_old = pmeg->tme_sun_mmu_pmeg_tlbs[tlb_i];
        !           363:     if (tlb_old != NULL
        !           364:        && tlb_old != tlb->tme_bus_tlb_global) {
        !           365:       tme_bus_tlb_invalidate(tlb_old);
        !           366:     }
        !           367:     pmeg->tme_sun_mmu_pmeg_tlbs[tlb_i]
        !           368:       = tlb->tme_bus_tlb_global;
        !           369:     pmeg->tme_sun_mmu_pmeg_tlbs_head = (tlb_i + 1) & (TME_SUN_MMU_PMEG_TLBS - 1);
        !           370:   }
1.1       root      371: 
                    372:   /* if this page is invalid, return the page-invalid cycle handler,
                    373:      which is valid for reading and writing for the user and system: */
                    374:   if (!(pte->tme_sun_mmu_pte_flags & TME_SUN_MMU_PTE_VALID)) {
                    375:     tme_bus_tlb_initialize(tlb);
1.1.1.3 ! root      376:     tlb->tme_bus_tlb_addr_first = addr_first;
        !           377:     tlb->tme_bus_tlb_addr_last = addr_last;
1.1       root      378:     tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    379:     tlb->tme_bus_tlb_cycle_private = mmu->tme_sun_mmu_info.tme_sun_mmu_info_invalid_private;
                    380:     tlb->tme_bus_tlb_cycle = mmu->tme_sun_mmu_info.tme_sun_mmu_info_invalid;
                    381:     return (TME_SUN_MMU_TLB_SYSTEM | TME_SUN_MMU_TLB_USER);
                    382:   }
                    383: 
                    384:   /* otherwise, this page is valid.  get the relevant part of the
                    385:      protection for this accessor (system or user), the part of the
                    386:      protection covering the other accessor (system or user), adjust
                    387:      "access" to be an unshifted TME_SUN_MMU_PTE_PROT_ value, and get
                    388:      the accessor (user or system) that this TLB entry will definitely
                    389:      be valid for: */
                    390:   protection = pte->tme_sun_mmu_pte_flags;
                    391:   if (access & TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_MASK)) {
                    392:     protection_other = protection / TME_SUN_MMU_PTE_PROT_USER(1);
                    393:     access /= TME_SUN_MMU_PTE_PROT_SYSTEM(1);
                    394:     protection /= TME_SUN_MMU_PTE_PROT_SYSTEM(1);
                    395:     tlb_valid_for = TME_SUN_MMU_TLB_SYSTEM;
                    396:   }
                    397:   else {
                    398:     protection_other = protection / TME_SUN_MMU_PTE_PROT_SYSTEM(1);
                    399:     access /= TME_SUN_MMU_PTE_PROT_USER(1);
                    400:     protection /= TME_SUN_MMU_PTE_PROT_USER(1);
                    401:     tlb_valid_for = TME_SUN_MMU_TLB_USER;
                    402:   }
                    403: 
                    404:   /* NB that the following code assumes a particular ordering of
                    405:      TME_SUN_MMU_PTE_PROT_ values.  specifically, it assumes that
                    406:      ABORT < ERROR < RO < RW: */
                    407: 
                    408:   /* if the part of the protection covering the other accessor (system
                    409:      or user) allows at least as much access as the relevant part of
                    410:      the protection, this TLB entry will be valid for that other
                    411:      successor as well.  we rely on particular definitions of the
                    412:      TME_SUN_MMU_TLB_ macros to make this fast: */
                    413: #if (3 - TME_SUN_MMU_TLB_SYSTEM) != TME_SUN_MMU_TLB_USER
                    414: #error "TME_SUN_MMU_TLB_USER and TME_SUN_MMU_TLB_SYSTEM are incompatible"
                    415: #endif
                    416:   protection &= TME_SUN_MMU_PTE_PROT_MASK;
                    417:   protection_other &= TME_SUN_MMU_PTE_PROT_MASK;
                    418:   if (protection_other >= protection) {
                    419:     tlb_valid_for |= (3 - tlb_valid_for);
                    420:   }
                    421: 
                    422:   /* if the access is protected, return the protection-error cycle
                    423:      handler: */
                    424:   if (protection < access) {
                    425:     if (protection == TME_SUN_MMU_PTE_PROT_ABORT) {
                    426:       abort();
                    427:     }
                    428:     tme_bus_tlb_initialize(tlb);
1.1.1.3 ! root      429:     tlb->tme_bus_tlb_addr_first = addr_first;
        !           430:     tlb->tme_bus_tlb_addr_last = addr_last;
1.1       root      431:     tlb->tme_bus_tlb_cycles_ok = (TME_BUS_CYCLE_WRITE
                    432:                                  | (protection == TME_SUN_MMU_PTE_PROT_ERROR
                    433:                                     ? TME_BUS_CYCLE_READ
                    434:                                     : 0));
                    435:     tlb->tme_bus_tlb_cycle_private = mmu->tme_sun_mmu_info.tme_sun_mmu_info_proterr_private;
                    436:     tlb->tme_bus_tlb_cycle = mmu->tme_sun_mmu_info.tme_sun_mmu_info_proterr;
                    437:     return (tlb_valid_for);
                    438:   }
                    439: 
                    440:   /* this access is OK.  fill the TLB with physical bus information.
                    441:      we pass in the virtual address as the initial physical address
                    442:      because sometimes the virtual part of the address can influence
                    443:      the physical address (as in the Sun-2 PROM mapping): */
                    444:   physical_address = address;
                    445:   (*mmu->_tme_sun_mmu_tlb_fill)
                    446:     (mmu->_tme_sun_mmu_tlb_fill_private, 
                    447:      tlb, 
                    448:      pte,
                    449:      &physical_address,
                    450:      ((access == TME_SUN_MMU_PTE_PROT_RW)
                    451:       ? TME_BUS_CYCLE_WRITE
                    452:       : TME_BUS_CYCLE_READ));
                    453: 
                    454:   /* create the mapping TLB entry, and update the PTE flags: */
1.1.1.3 ! root      455:   tlb_virtual.tme_bus_tlb_addr_first = addr_first;
        !           456:   tlb_virtual.tme_bus_tlb_addr_last = addr_last;
1.1       root      457:   pte->tme_sun_mmu_pte_flags |= TME_SUN_MMU_PTE_REF;
                    458:   tlb_virtual.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ;
                    459:   if (access == TME_SUN_MMU_PTE_PROT_RW) {
                    460:     pte->tme_sun_mmu_pte_flags |= TME_SUN_MMU_PTE_MOD;
                    461:   }
1.1.1.2   root      462:   if (protection == TME_SUN_MMU_PTE_PROT_RW
                    463:       && (pte->tme_sun_mmu_pte_flags & TME_SUN_MMU_PTE_MOD)) {
1.1       root      464:     tlb_virtual.tme_bus_tlb_cycles_ok |= TME_BUS_CYCLE_WRITE;
                    465:   }
                    466:   
                    467:   /* map the filled TLB entry: */
                    468:   tme_bus_tlb_map(tlb, physical_address, &tlb_virtual, address);
                    469: 
                    470:   /* return who this TLB entry is good for: */
                    471:   return (tlb_valid_for);
                    472: }
                    473: 
                    474: /* this invalidates all TLB entries in all TLB sets: */
                    475: void
                    476: tme_sun_mmu_tlbs_invalidate(void *_mmu)
                    477: {
                    478:   struct tme_sun_mmu *mmu;
                    479:   struct tme_sun_mmu_tlb_set *tlb_set;
                    480:   struct tme_bus_tlb *tlb;
                    481:   unsigned long tlb_i;
                    482: 
                    483:   /* recover our MMU: */
                    484:   mmu = (struct tme_sun_mmu *) _mmu;
                    485: 
                    486:   /* invalidate all TLB entries in all sets: */
                    487:   for (tlb_set = mmu->tme_sun_mmu_tlb_sets;
                    488:        tlb_set != NULL;
                    489:        tlb_set = tlb_set->tme_sun_mmu_tlb_set_next) {
                    490:     tlb = tlb_set->tme_sun_mmu_tlb_set_base;
                    491:     tlb_i = ((unsigned long) tlb_set->tme_sun_mmu_tlb_set_count) * mmu->tme_sun_mmu_contexts;
                    492:     for (; tlb_i-- > 0; ) {
                    493:       tme_bus_tlb_invalidate(tlb);
                    494:       tlb = (struct tme_bus_tlb *) (((tme_uint8_t *) tlb) + tlb_set->tme_sun_mmu_tlb_set_sizeof_one);
                    495:     }
                    496:   }
                    497: }
                    498: 
                    499: /* this sets the user context register: */
                    500: void
                    501: tme_sun_mmu_tlbs_context_set(void *_mmu, tme_uint8_t context)
                    502: {
                    503:   struct tme_sun_mmu *mmu;
                    504:   struct tme_sun_mmu_tlb_set *tlb_set;
                    505: 
                    506:   /* recover our MMU: */
                    507:   mmu = (struct tme_sun_mmu *) _mmu;
                    508: 
                    509:   /* we have to update each TLB set to reflect the context change: */
                    510:   for (tlb_set = mmu->tme_sun_mmu_tlb_sets;
                    511:        tlb_set != NULL;
                    512:        tlb_set = tlb_set->tme_sun_mmu_tlb_set_next) {
1.1.1.3 ! root      513:     tme_memory_atomic_pointer_write(struct tme_bus_tlb *,
        !           514:                                    *tlb_set->tme_sun_mmu_tlb_set_pointer,
        !           515:                                    (struct tme_bus_tlb *)
        !           516:                                    (((tme_uint8_t *) tlb_set->tme_sun_mmu_tlb_set_base)
        !           517:                                     + (((unsigned long) tlb_set->tme_sun_mmu_tlb_set_count)
        !           518:                                        * tlb_set->tme_sun_mmu_tlb_set_sizeof_one
        !           519:                                        * context)),
        !           520:                                    tlb_set->tme_sun_mmu_tlb_set_pointer_rwlock);
1.1       root      521:   }
                    522: }
                    523: 
                    524: /* this allocates a new TLB set: */
                    525: int
                    526: tme_sun_mmu_tlb_set_allocate(void *_mmu,
                    527:                             unsigned int count, unsigned int sizeof_one, 
1.1.1.3 ! root      528:                             struct tme_bus_tlb * tme_shared *_tlbs,
        !           529:                             tme_rwlock_t *_tlbs_rwlock)
1.1       root      530: {
                    531:   struct tme_sun_mmu *mmu;
                    532:   struct tme_bus_tlb *tlbs, *tlb;
                    533:   unsigned long tlb_i;
                    534:   struct tme_sun_mmu_tlb_set *tlb_set;
                    535: 
                    536:   /* recover our mmu: */
                    537:   mmu = (struct tme_sun_mmu *) _mmu;
                    538: 
                    539:   /* allocate and initialize a set of TLBs: */
                    540:   tlb_i = ((unsigned long) mmu->tme_sun_mmu_contexts) * count;
                    541:   tlbs = (struct tme_bus_tlb *) tme_malloc(tlb_i * sizeof_one);
                    542:   tlb = tlbs;
                    543:   for (; tlb_i-- > 0; ) {
1.1.1.3 ! root      544:     tme_bus_tlb_construct(tlb);
1.1       root      545:     tlb = (struct tme_bus_tlb *) (((tme_uint8_t *) tlb) + sizeof_one);
                    546:   }
                    547: 
                    548:   /* remember this set: */
                    549:   tlb_set = tme_new0(struct tme_sun_mmu_tlb_set, 1);
                    550:   tlb_set->tme_sun_mmu_tlb_set_next = mmu->tme_sun_mmu_tlb_sets;
                    551:   tlb_set->tme_sun_mmu_tlb_set_pointer = _tlbs;
1.1.1.3 ! root      552:   tlb_set->tme_sun_mmu_tlb_set_pointer_rwlock = _tlbs_rwlock;
1.1       root      553:   tlb_set->tme_sun_mmu_tlb_set_base = tlbs;
                    554:   tlb_set->tme_sun_mmu_tlb_set_sizeof_one = sizeof_one;
                    555:   tlb_set->tme_sun_mmu_tlb_set_count = count;
                    556:   mmu->tme_sun_mmu_tlb_sets = tlb_set;
                    557:   
1.1.1.3 ! root      558:   tme_memory_atomic_pointer_write(struct tme_bus_tlb *,
        !           559:                                  *_tlbs,
        !           560:                                  tlbs,
        !           561:                                  _tlbs_rwlock);
1.1       root      562:   return (TME_OK);
                    563: }
                    564: 

unix.superglobalmegacorp.com

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