tlb.cc revision 6038:4c21637acedd
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    //@TODO: This should actually use TLB instead of going directly
431    //       to the page table in syscall mode.
432    /**
433     * Check for alignment faults
434     */
435    if (req->getVaddr() & (req->getSize() - 1)) {
436        DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(),
437                req->getSize());
438        return new AlignmentFault();
439    }
440
441
442    Process * p = tc->getProcessPtr();
443
444    Fault fault = p->pTable->translate(req);
445    if(fault != NoFault)
446        return fault;
447
448    return NoFault;
449#else
450  if(MipsISA::IsKSeg0(req->getVaddr()))
451    {
452      // Address will not be translated through TLB, set response, and go!
453      req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
454      if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned())
455        {
456          StoreAddressErrorFault *Flt = new StoreAddressErrorFault();
457          /* BadVAddr must be set */
458          Flt->BadVAddr = req->getVaddr();
459
460          return Flt;
461        }
462    }
463  else if(MipsISA::IsKSeg1(req->getVaddr()))
464    {
465      // Address will not be translated through TLB, set response, and go!
466      req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
467    }
468  else
469    {
470      /* This is an optimization - smallPages is updated every time a TLB operation is performed
471         That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
472         do a TLB lookup */
473      Addr VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC);
474      if(smallPages==1){
475        VPN=((req->getVaddr() >> 11));
476      }
477      uint8_t Asid = req->getAsid();
478      MipsISA::PTE *pte = lookup(VPN,Asid);
479      if(req->isMisaligned()){ // Unaligned address!
480        StoreAddressErrorFault *Flt = new StoreAddressErrorFault();
481        /* BadVAddr must be set */
482        Flt->BadVAddr = req->getVaddr();
483        return Flt;
484      }
485      if(pte != NULL)
486        {// Ok, found something
487          /* Check for valid bits */
488          int EvenOdd;
489          bool Valid;
490          bool Dirty;
491          if(((((req->getVaddr()) >> pte->AddrShiftAmount) & 1)) ==0){
492            // Check even bits
493            Valid = pte->V0;
494            Dirty = pte->D0;
495            EvenOdd = 0;
496
497          } else {
498            // Check odd bits
499            Valid = pte->V1;
500            Dirty = pte->D1;
501            EvenOdd = 1;
502          }
503
504          if(Valid == false)
505            {//Invalid entry
506              //              invalids++;
507              DtbInvalidFault *Flt = new DtbInvalidFault();
508              /* EntryHi VPN, ASID fields must be set */
509              Flt->EntryHi_Asid = Asid;
510              Flt->EntryHi_VPN2 = (VPN>>2);
511              Flt->EntryHi_VPN2X = (VPN & 0x3);
512
513
514              /* BadVAddr must be set */
515              Flt->BadVAddr = req->getVaddr();
516
517              /* Context must be set */
518              Flt->Context_BadVPN2 = (VPN >> 2);
519
520              return Flt;
521            }
522          else
523            {// Ok, this is really a match, set paddr
524              //              hits++;
525              if(!Dirty)
526                {
527                  TLBModifiedFault *Flt = new TLBModifiedFault();
528                  /* EntryHi VPN, ASID fields must be set */
529                  Flt->EntryHi_Asid = Asid;
530                  Flt->EntryHi_VPN2 = (VPN>>2);
531                  Flt->EntryHi_VPN2X = (VPN & 0x3);
532
533
534                  /* BadVAddr must be set */
535                  Flt->BadVAddr = req->getVaddr();
536
537                  /* Context must be set */
538                  Flt->Context_BadVPN2 = (VPN >> 2);
539                  return Flt;
540
541                }
542              Addr PAddr;
543              if(EvenOdd == 0){
544                PAddr = pte->PFN0;
545              }else{
546                PAddr = pte->PFN1;
547              }
548              PAddr >>= (pte->AddrShiftAmount-12);
549              PAddr <<= pte->AddrShiftAmount;
550              PAddr |= ((req->getVaddr()) & pte->OffsetMask);
551              req->setPaddr(PAddr);
552            }
553        }
554      else
555        { // Didn't find any match, return a TLB Refill Exception
556          //      misses++;
557          DtbRefillFault *Flt=new DtbRefillFault();
558          /* EntryHi VPN, ASID fields must be set */
559          Flt->EntryHi_Asid = Asid;
560          Flt->EntryHi_VPN2 = (VPN>>2);
561          Flt->EntryHi_VPN2X = (VPN & 0x3);
562
563
564          /* BadVAddr must be set */
565          Flt->BadVAddr = req->getVaddr();
566
567          /* Context must be set */
568          Flt->Context_BadVPN2 = (VPN >> 2);
569          return Flt;
570        }
571    }
572    return checkCacheability(req);
573#endif
574}
575
576Fault
577TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
578{
579    if (mode == Execute)
580        return translateInst(req, tc);
581    else
582        return translateData(req, tc, mode == Write);
583}
584
585void
586TLB::translateTiming(RequestPtr req, ThreadContext *tc,
587        Translation *translation, Mode mode)
588{
589    assert(translation);
590    translation->finish(translateAtomic(req, tc, mode), req, tc, mode);
591}
592
593
594MipsISA::PTE &
595TLB::index(bool advance)
596{
597    MipsISA::PTE *pte = &table[nlu];
598
599    if (advance)
600        nextnlu();
601
602    return *pte;
603}
604
605MipsISA::TLB *
606MipsTLBParams::create()
607{
608    return new MipsISA::TLB(this);
609}
610