tlb.cc revision 6022:410194bb3049
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * Copyright (c) 2007 MIPS Technologies, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Authors: Nathan Binkert
30 *          Steve Reinhardt
31 *          Jaidev Patwardhan
32 */
33
34#include <string>
35#include <vector>
36
37#include "arch/mips/pra_constants.hh"
38#include "arch/mips/pagetable.hh"
39#include "arch/mips/tlb.hh"
40#include "arch/mips/faults.hh"
41#include "arch/mips/utility.hh"
42#include "base/inifile.hh"
43#include "base/str.hh"
44#include "base/trace.hh"
45#include "cpu/thread_context.hh"
46#include "sim/process.hh"
47#include "mem/page_table.hh"
48#include "params/MipsTLB.hh"
49
50
51using namespace std;
52using namespace MipsISA;
53
54///////////////////////////////////////////////////////////////////////
55//
56//  MIPS TLB
57//
58
59#define MODE2MASK(X)                    (1 << (X))
60
61TLB::TLB(const Params *p)
62    : BaseTLB(p), size(p->size), nlu(0)
63{
64    table = new MipsISA::PTE[size];
65    memset(table, 0, sizeof(MipsISA::PTE[size]));
66    smallPages=0;
67}
68
69TLB::~TLB()
70{
71    if (table)
72        delete [] table;
73}
74
75// look up an entry in the TLB
76MipsISA::PTE *
77TLB::lookup(Addr vpn, uint8_t asn) const
78{
79    // assume not found...
80    MipsISA::PTE *retval = NULL;
81    PageTable::const_iterator i = lookupTable.find(vpn);
82    if (i != lookupTable.end()) {
83        while (i->first == vpn) {
84            int index = i->second;
85            MipsISA::PTE *pte = &table[index];
86
87            /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
88            Addr Mask = pte->Mask;
89            Addr InvMask = ~Mask;
90            Addr VPN  = pte->VPN;
91            //      warn("Valid: %d - %d\n",pte->V0,pte->V1);
92            if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G  || (asn == pte->asid)))
93              { // We have a VPN + ASID Match
94                retval = pte;
95                break;
96              }
97            ++i;
98        }
99    }
100
101    DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn,
102            retval ? "hit" : "miss", retval ? retval->PFN1 : 0);
103    return retval;
104}
105
106MipsISA::PTE* TLB::getEntry(unsigned Index) const
107{
108    // Make sure that Index is valid
109    assert(Index<size);
110    return &table[Index];
111}
112
113int TLB::probeEntry(Addr vpn,uint8_t asn) const
114{
115    // assume not found...
116    MipsISA::PTE *retval = NULL;
117    int Ind=-1;
118    PageTable::const_iterator i = lookupTable.find(vpn);
119    if (i != lookupTable.end()) {
120        while (i->first == vpn) {
121            int index = i->second;
122            MipsISA::PTE *pte = &table[index];
123
124            /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
125            Addr Mask = pte->Mask;
126            Addr InvMask = ~Mask;
127            Addr VPN  = pte->VPN;
128            if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G  || (asn == pte->asid)))
129              { // We have a VPN + ASID Match
130                retval = pte;
131                Ind = index;
132                break;
133              }
134
135            ++i;
136        }
137    }
138    DPRINTF(MipsPRA,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn,asn,Ind);
139    return Ind;
140}
141Fault inline
142TLB::checkCacheability(RequestPtr &req)
143{
144  Addr VAddrUncacheable = 0xA0000000;
145  // In MIPS, cacheability is controlled by certain bits of the virtual address
146  // or by the TLB entry
147  if((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) {
148    // mark request as uncacheable
149      req->setFlags(Request::UNCACHEABLE);
150  }
151  return NoFault;
152}
153void TLB::insertAt(MipsISA::PTE &pte, unsigned Index, int _smallPages)
154{
155  smallPages=_smallPages;
156  if(Index > size){
157    warn("Attempted to write at index (%d) beyond TLB size (%d)",Index,size);
158  } else {
159    // Update TLB
160    DPRINTF(TLB,"TLB[%d]: %x %x %x %x\n",Index,pte.Mask<<11,((pte.VPN << 11) | pte.asid),((pte.PFN0 <<6) | (pte.C0 << 3) | (pte.D0 << 2) | (pte.V0 <<1) | pte.G),
161            ((pte.PFN1 <<6) | (pte.C1 << 3) | (pte.D1 << 2) | (pte.V1 <<1) | pte.G));
162    if(table[Index].V0 == true || table[Index].V1 == true){ // Previous entry is valid
163      PageTable::iterator i = lookupTable.find(table[Index].VPN);
164      lookupTable.erase(i);
165    }
166    table[Index]=pte;
167    // Update fast lookup table
168    lookupTable.insert(make_pair(table[Index].VPN, Index));
169    //    int TestIndex=probeEntry(pte.VPN,pte.asid);
170    //    warn("Inserted at: %d, Found at: %d (%x)\n",Index,TestIndex,pte.Mask);
171  }
172
173}
174
175// insert a new TLB entry
176void
177TLB::insert(Addr addr, MipsISA::PTE &pte)
178{
179  fatal("TLB Insert not yet implemented\n");
180
181
182  /*    MipsISA::VAddr vaddr = addr;
183    if (table[nlu].valid) {
184        Addr oldvpn = table[nlu].tag;
185        PageTable::iterator i = lookupTable.find(oldvpn);
186
187        if (i == lookupTable.end())
188            panic("TLB entry not found in lookupTable");
189
190        int index;
191        while ((index = i->second) != nlu) {
192            if (table[index].tag != oldvpn)
193                panic("TLB entry not found in lookupTable");
194
195            ++i;
196        }
197
198        DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn);
199
200        lookupTable.erase(i);
201    }
202
203    DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn);
204
205    table[nlu] = pte;
206    table[nlu].tag = vaddr.vpn();
207    table[nlu].valid = true;
208
209    lookupTable.insert(make_pair(vaddr.vpn(), nlu));
210    nextnlu();
211  */
212}
213
214void
215TLB::flushAll()
216{
217    DPRINTF(TLB, "flushAll\n");
218    memset(table, 0, sizeof(MipsISA::PTE[size]));
219    lookupTable.clear();
220    nlu = 0;
221}
222
223void
224TLB::serialize(ostream &os)
225{
226    SERIALIZE_SCALAR(size);
227    SERIALIZE_SCALAR(nlu);
228
229    for (int i = 0; i < size; i++) {
230        nameOut(os, csprintf("%s.PTE%d", name(), i));
231        table[i].serialize(os);
232    }
233}
234
235void
236TLB::unserialize(Checkpoint *cp, const string &section)
237{
238    UNSERIALIZE_SCALAR(size);
239    UNSERIALIZE_SCALAR(nlu);
240
241    for (int i = 0; i < size; i++) {
242        table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
243        if (table[i].V0 || table[i].V1) {
244            lookupTable.insert(make_pair(table[i].VPN, i));
245        }
246    }
247}
248
249void
250TLB::regStats()
251{
252    read_hits
253        .name(name() + ".read_hits")
254        .desc("DTB read hits")
255        ;
256
257    read_misses
258        .name(name() + ".read_misses")
259        .desc("DTB read misses")
260        ;
261
262
263    read_accesses
264        .name(name() + ".read_accesses")
265        .desc("DTB read accesses")
266        ;
267
268    write_hits
269        .name(name() + ".write_hits")
270        .desc("DTB write hits")
271        ;
272
273    write_misses
274        .name(name() + ".write_misses")
275        .desc("DTB write misses")
276        ;
277
278
279    write_accesses
280        .name(name() + ".write_accesses")
281        .desc("DTB write accesses")
282        ;
283
284    hits
285        .name(name() + ".hits")
286        .desc("DTB hits")
287        ;
288
289    misses
290        .name(name() + ".misses")
291        .desc("DTB misses")
292        ;
293
294    invalids
295        .name(name() + ".invalids")
296        .desc("DTB access violations")
297        ;
298
299    accesses
300        .name(name() + ".accesses")
301        .desc("DTB accesses")
302        ;
303
304    hits = read_hits + write_hits;
305    misses = read_misses + write_misses;
306    accesses = read_accesses + write_accesses;
307}
308
309Fault
310TLB::translateInst(RequestPtr req, ThreadContext *tc)
311{
312#if !FULL_SYSTEM
313    Process * p = tc->getProcessPtr();
314
315    Fault fault = p->pTable->translate(req);
316    if(fault != NoFault)
317        return fault;
318
319    return NoFault;
320#else
321  if(MipsISA::IsKSeg0(req->getVaddr()))
322    {
323      // Address will not be translated through TLB, set response, and go!
324      req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
325      if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned())
326        {
327          AddressErrorFault *Flt = new AddressErrorFault();
328          /* BadVAddr must be set */
329          Flt->BadVAddr = req->getVaddr();
330          return Flt;
331        }
332    }
333  else if(MipsISA::IsKSeg1(req->getVaddr()))
334    {
335      // Address will not be translated through TLB, set response, and go!
336      req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
337    }
338  else
339    {
340      /* This is an optimization - smallPages is updated every time a TLB operation is performed
341         That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
342         do a TLB lookup */
343      Addr VPN;
344      if(smallPages==1){
345        VPN=((req->getVaddr() >> 11));
346      } else {
347        VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC);
348      }
349      uint8_t Asid = req->getAsid();
350      if(req->isMisaligned()){ // Unaligned address!
351        AddressErrorFault *Flt = new AddressErrorFault();
352        /* BadVAddr must be set */
353        Flt->BadVAddr = req->getVaddr();
354        return Flt;
355      }
356      MipsISA::PTE *pte = lookup(VPN,Asid);
357      if(pte != NULL)
358        {// Ok, found something
359          /* Check for valid bits */
360          int EvenOdd;
361          bool Valid;
362          if((((req->getVaddr()) >> pte->AddrShiftAmount) & 1) ==0){
363            // Check even bits
364            Valid = pte->V0;
365            EvenOdd = 0;
366          } else {
367            // Check odd bits
368            Valid = pte->V1;
369            EvenOdd = 1;
370          }
371
372          if(Valid == false)
373            {//Invalid entry
374              ItbInvalidFault *Flt = new ItbInvalidFault();
375              /* EntryHi VPN, ASID fields must be set */
376              Flt->EntryHi_Asid = Asid;
377              Flt->EntryHi_VPN2 = (VPN>>2);
378              Flt->EntryHi_VPN2X = (VPN & 0x3);
379
380              /* BadVAddr must be set */
381              Flt->BadVAddr = req->getVaddr();
382
383              /* Context must be set */
384              Flt->Context_BadVPN2 = (VPN >> 2);
385              return Flt;
386            }
387          else
388            {// Ok, this is really a match, set paddr
389              //              hits++;
390              Addr PAddr;
391              if(EvenOdd == 0){
392                PAddr = pte->PFN0;
393              }else{
394                PAddr = pte->PFN1;
395              }
396              PAddr >>= (pte->AddrShiftAmount-12);
397              PAddr <<= pte->AddrShiftAmount;
398              PAddr |= ((req->getVaddr()) & pte->OffsetMask);
399              req->setPaddr(PAddr);
400
401
402            }
403        }
404      else
405        { // Didn't find any match, return a TLB Refill Exception
406          //      misses++;
407          ItbRefillFault *Flt=new ItbRefillFault();
408          /* EntryHi VPN, ASID fields must be set */
409          Flt->EntryHi_Asid = Asid;
410          Flt->EntryHi_VPN2 = (VPN>>2);
411          Flt->EntryHi_VPN2X = (VPN & 0x3);
412
413
414          /* BadVAddr must be set */
415          Flt->BadVAddr = req->getVaddr();
416
417          /* Context must be set */
418          Flt->Context_BadVPN2 = (VPN >> 2);
419          return Flt;
420        }
421    }
422  return checkCacheability(req);
423#endif
424}
425
426Fault
427TLB::translateData(RequestPtr req, ThreadContext *tc, bool write)
428{
429#if !FULL_SYSTEM
430    Process * p = tc->getProcessPtr();
431
432    Fault fault = p->pTable->translate(req);
433    if(fault != NoFault)
434        return fault;
435
436    return NoFault;
437#else
438  if(MipsISA::IsKSeg0(req->getVaddr()))
439    {
440      // Address will not be translated through TLB, set response, and go!
441      req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
442      if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned())
443        {
444          StoreAddressErrorFault *Flt = new StoreAddressErrorFault();
445          /* BadVAddr must be set */
446          Flt->BadVAddr = req->getVaddr();
447
448          return Flt;
449        }
450    }
451  else if(MipsISA::IsKSeg1(req->getVaddr()))
452    {
453      // Address will not be translated through TLB, set response, and go!
454      req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
455    }
456  else
457    {
458      /* This is an optimization - smallPages is updated every time a TLB operation is performed
459         That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
460         do a TLB lookup */
461      Addr VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC);
462      if(smallPages==1){
463        VPN=((req->getVaddr() >> 11));
464      }
465      uint8_t Asid = req->getAsid();
466      MipsISA::PTE *pte = lookup(VPN,Asid);
467      if(req->isMisaligned()){ // Unaligned address!
468        StoreAddressErrorFault *Flt = new StoreAddressErrorFault();
469        /* BadVAddr must be set */
470        Flt->BadVAddr = req->getVaddr();
471        return Flt;
472      }
473      if(pte != NULL)
474        {// Ok, found something
475          /* Check for valid bits */
476          int EvenOdd;
477          bool Valid;
478          bool Dirty;
479          if(((((req->getVaddr()) >> pte->AddrShiftAmount) & 1)) ==0){
480            // Check even bits
481            Valid = pte->V0;
482            Dirty = pte->D0;
483            EvenOdd = 0;
484
485          } else {
486            // Check odd bits
487            Valid = pte->V1;
488            Dirty = pte->D1;
489            EvenOdd = 1;
490          }
491
492          if(Valid == false)
493            {//Invalid entry
494              //              invalids++;
495              DtbInvalidFault *Flt = new DtbInvalidFault();
496              /* EntryHi VPN, ASID fields must be set */
497              Flt->EntryHi_Asid = Asid;
498              Flt->EntryHi_VPN2 = (VPN>>2);
499              Flt->EntryHi_VPN2X = (VPN & 0x3);
500
501
502              /* BadVAddr must be set */
503              Flt->BadVAddr = req->getVaddr();
504
505              /* Context must be set */
506              Flt->Context_BadVPN2 = (VPN >> 2);
507
508              return Flt;
509            }
510          else
511            {// Ok, this is really a match, set paddr
512              //              hits++;
513              if(!Dirty)
514                {
515                  TLBModifiedFault *Flt = new TLBModifiedFault();
516                  /* EntryHi VPN, ASID fields must be set */
517                  Flt->EntryHi_Asid = Asid;
518                  Flt->EntryHi_VPN2 = (VPN>>2);
519                  Flt->EntryHi_VPN2X = (VPN & 0x3);
520
521
522                  /* BadVAddr must be set */
523                  Flt->BadVAddr = req->getVaddr();
524
525                  /* Context must be set */
526                  Flt->Context_BadVPN2 = (VPN >> 2);
527                  return Flt;
528
529                }
530              Addr PAddr;
531              if(EvenOdd == 0){
532                PAddr = pte->PFN0;
533              }else{
534                PAddr = pte->PFN1;
535              }
536              PAddr >>= (pte->AddrShiftAmount-12);
537              PAddr <<= pte->AddrShiftAmount;
538              PAddr |= ((req->getVaddr()) & pte->OffsetMask);
539              req->setPaddr(PAddr);
540            }
541        }
542      else
543        { // Didn't find any match, return a TLB Refill Exception
544          //      misses++;
545          DtbRefillFault *Flt=new DtbRefillFault();
546          /* EntryHi VPN, ASID fields must be set */
547          Flt->EntryHi_Asid = Asid;
548          Flt->EntryHi_VPN2 = (VPN>>2);
549          Flt->EntryHi_VPN2X = (VPN & 0x3);
550
551
552          /* BadVAddr must be set */
553          Flt->BadVAddr = req->getVaddr();
554
555          /* Context must be set */
556          Flt->Context_BadVPN2 = (VPN >> 2);
557          return Flt;
558        }
559    }
560    return checkCacheability(req);
561#endif
562}
563
564Fault
565TLB::translateAtomic(RequestPtr req, ThreadContext *tc,
566        bool write, bool execute)
567{
568    if (execute)
569        return translateInst(req, tc);
570    else
571        return translateData(req, tc, write);
572}
573
574void
575TLB::translateTiming(RequestPtr req, ThreadContext *tc,
576        Translation *translation, bool write, bool execute)
577{
578    assert(translation);
579    translation->finish(translateAtomic(req, tc, write, execute),
580            req, tc, write, execute);
581}
582
583
584MipsISA::PTE &
585TLB::index(bool advance)
586{
587    MipsISA::PTE *pte = &table[nlu];
588
589    if (advance)
590        nextnlu();
591
592    return *pte;
593}
594
595MipsISA::TLB *
596MipsTLBParams::create()
597{
598    return new MipsISA::TLB(this);
599}
600