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

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

unix.superglobalmegacorp.com

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