mem: update stuff for changes to Packet and Request
[gem5.git] / src / arch / mips / tlb.cc
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/MipsDTB.hh"
49 #include "params/MipsITB.hh"
50 #include "params/MipsTLB.hh"
51 #include "params/MipsUTB.hh"
52
53
54 using namespace std;
55 using namespace MipsISA;
56
57 ///////////////////////////////////////////////////////////////////////
58 //
59 // MIPS TLB
60 //
61
62 #define MODE2MASK(X) (1 << (X))
63
64 TLB::TLB(const Params *p)
65 : BaseTLB(p), size(p->size), nlu(0)
66 {
67 table = new MipsISA::PTE[size];
68 memset(table, 0, sizeof(MipsISA::PTE[size]));
69 smallPages=0;
70 }
71
72 TLB::~TLB()
73 {
74 if (table)
75 delete [] table;
76 }
77
78 // look up an entry in the TLB
79 MipsISA::PTE *
80 TLB::lookup(Addr vpn, uint8_t asn) const
81 {
82 // assume not found...
83 MipsISA::PTE *retval = NULL;
84 PageTable::const_iterator i = lookupTable.find(vpn);
85 if (i != lookupTable.end()) {
86 while (i->first == vpn) {
87 int index = i->second;
88 MipsISA::PTE *pte = &table[index];
89
90 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
91 Addr Mask = pte->Mask;
92 Addr InvMask = ~Mask;
93 Addr VPN = pte->VPN;
94 // warn("Valid: %d - %d\n",pte->V0,pte->V1);
95 if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G || (asn == pte->asid)))
96 { // We have a VPN + ASID Match
97 retval = pte;
98 break;
99 }
100 ++i;
101 }
102 }
103
104 DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn,
105 retval ? "hit" : "miss", retval ? retval->PFN1 : 0);
106 return retval;
107 }
108
109 MipsISA::PTE* TLB::getEntry(unsigned Index) const
110 {
111 // Make sure that Index is valid
112 assert(Index<size);
113 return &table[Index];
114 }
115
116 int TLB::probeEntry(Addr vpn,uint8_t asn) const
117 {
118 // assume not found...
119 MipsISA::PTE *retval = NULL;
120 int Ind=-1;
121 PageTable::const_iterator i = lookupTable.find(vpn);
122 if (i != lookupTable.end()) {
123 while (i->first == vpn) {
124 int index = i->second;
125 MipsISA::PTE *pte = &table[index];
126
127 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
128 Addr Mask = pte->Mask;
129 Addr InvMask = ~Mask;
130 Addr VPN = pte->VPN;
131 if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G || (asn == pte->asid)))
132 { // We have a VPN + ASID Match
133 retval = pte;
134 Ind = index;
135 break;
136 }
137
138 ++i;
139 }
140 }
141 DPRINTF(MipsPRA,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn,asn,Ind);
142 return Ind;
143 }
144 Fault inline
145 TLB::checkCacheability(RequestPtr &req)
146 {
147 Addr VAddrUncacheable = 0xA0000000;
148 // In MIPS, cacheability is controlled by certain bits of the virtual address
149 // or by the TLB entry
150 if((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) {
151 // mark request as uncacheable
152 req->setFlags(Request::UNCACHEABLE);
153 }
154 return NoFault;
155 }
156 void TLB::insertAt(MipsISA::PTE &pte, unsigned Index, int _smallPages)
157 {
158 smallPages=_smallPages;
159 if(Index > size){
160 warn("Attempted to write at index (%d) beyond TLB size (%d)",Index,size);
161 } else {
162 // Update TLB
163 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),
164 ((pte.PFN1 <<6) | (pte.C1 << 3) | (pte.D1 << 2) | (pte.V1 <<1) | pte.G));
165 if(table[Index].V0 == true || table[Index].V1 == true){ // Previous entry is valid
166 PageTable::iterator i = lookupTable.find(table[Index].VPN);
167 lookupTable.erase(i);
168 }
169 table[Index]=pte;
170 // Update fast lookup table
171 lookupTable.insert(make_pair(table[Index].VPN, Index));
172 // int TestIndex=probeEntry(pte.VPN,pte.asid);
173 // warn("Inserted at: %d, Found at: %d (%x)\n",Index,TestIndex,pte.Mask);
174 }
175
176 }
177
178 // insert a new TLB entry
179 void
180 TLB::insert(Addr addr, MipsISA::PTE &pte)
181 {
182 fatal("TLB Insert not yet implemented\n");
183
184
185 /* MipsISA::VAddr vaddr = addr;
186 if (table[nlu].valid) {
187 Addr oldvpn = table[nlu].tag;
188 PageTable::iterator i = lookupTable.find(oldvpn);
189
190 if (i == lookupTable.end())
191 panic("TLB entry not found in lookupTable");
192
193 int index;
194 while ((index = i->second) != nlu) {
195 if (table[index].tag != oldvpn)
196 panic("TLB entry not found in lookupTable");
197
198 ++i;
199 }
200
201 DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn);
202
203 lookupTable.erase(i);
204 }
205
206 DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn);
207
208 table[nlu] = pte;
209 table[nlu].tag = vaddr.vpn();
210 table[nlu].valid = true;
211
212 lookupTable.insert(make_pair(vaddr.vpn(), nlu));
213 nextnlu();
214 */
215 }
216
217 void
218 TLB::flushAll()
219 {
220 DPRINTF(TLB, "flushAll\n");
221 memset(table, 0, sizeof(MipsISA::PTE[size]));
222 lookupTable.clear();
223 nlu = 0;
224 }
225
226 void
227 TLB::serialize(ostream &os)
228 {
229 SERIALIZE_SCALAR(size);
230 SERIALIZE_SCALAR(nlu);
231
232 for (int i = 0; i < size; i++) {
233 nameOut(os, csprintf("%s.PTE%d", name(), i));
234 table[i].serialize(os);
235 }
236 }
237
238 void
239 TLB::unserialize(Checkpoint *cp, const string &section)
240 {
241 UNSERIALIZE_SCALAR(size);
242 UNSERIALIZE_SCALAR(nlu);
243
244 for (int i = 0; i < size; i++) {
245 table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
246 if (table[i].V0 || table[i].V1) {
247 lookupTable.insert(make_pair(table[i].VPN, i));
248 }
249 }
250 }
251
252 void
253 TLB::regStats()
254 {
255 read_hits
256 .name(name() + ".read_hits")
257 .desc("DTB read hits")
258 ;
259
260 read_misses
261 .name(name() + ".read_misses")
262 .desc("DTB read misses")
263 ;
264
265
266 read_accesses
267 .name(name() + ".read_accesses")
268 .desc("DTB read accesses")
269 ;
270
271 write_hits
272 .name(name() + ".write_hits")
273 .desc("DTB write hits")
274 ;
275
276 write_misses
277 .name(name() + ".write_misses")
278 .desc("DTB write misses")
279 ;
280
281
282 write_accesses
283 .name(name() + ".write_accesses")
284 .desc("DTB write accesses")
285 ;
286
287 hits
288 .name(name() + ".hits")
289 .desc("DTB hits")
290 ;
291
292 misses
293 .name(name() + ".misses")
294 .desc("DTB misses")
295 ;
296
297 invalids
298 .name(name() + ".invalids")
299 .desc("DTB access violations")
300 ;
301
302 accesses
303 .name(name() + ".accesses")
304 .desc("DTB accesses")
305 ;
306
307 hits = read_hits + write_hits;
308 misses = read_misses + write_misses;
309 accesses = read_accesses + write_accesses;
310 }
311
312 Fault
313 ITB::translate(RequestPtr &req, ThreadContext *tc)
314 {
315 #if !FULL_SYSTEM
316 Process * p = tc->getProcessPtr();
317
318 Fault fault = p->pTable->translate(req);
319 if(fault != NoFault)
320 return fault;
321
322 return NoFault;
323 #else
324 if(MipsISA::IsKSeg0(req->getVaddr()))
325 {
326 // Address will not be translated through TLB, set response, and go!
327 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
328 if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned())
329 {
330 AddressErrorFault *Flt = new AddressErrorFault();
331 /* BadVAddr must be set */
332 Flt->BadVAddr = req->getVaddr();
333 return Flt;
334 }
335 }
336 else if(MipsISA::IsKSeg1(req->getVaddr()))
337 {
338 // Address will not be translated through TLB, set response, and go!
339 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
340 }
341 else
342 {
343 /* This is an optimization - smallPages is updated every time a TLB operation is performed
344 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
345 do a TLB lookup */
346 Addr VPN;
347 if(smallPages==1){
348 VPN=((req->getVaddr() >> 11));
349 } else {
350 VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC);
351 }
352 uint8_t Asid = req->getAsid();
353 if(req->isMisaligned()){ // Unaligned address!
354 AddressErrorFault *Flt = new AddressErrorFault();
355 /* BadVAddr must be set */
356 Flt->BadVAddr = req->getVaddr();
357 return Flt;
358 }
359 MipsISA::PTE *pte = lookup(VPN,Asid);
360 if(pte != NULL)
361 {// Ok, found something
362 /* Check for valid bits */
363 int EvenOdd;
364 bool Valid;
365 if((((req->getVaddr()) >> pte->AddrShiftAmount) & 1) ==0){
366 // Check even bits
367 Valid = pte->V0;
368 EvenOdd = 0;
369 } else {
370 // Check odd bits
371 Valid = pte->V1;
372 EvenOdd = 1;
373 }
374
375 if(Valid == false)
376 {//Invalid entry
377 ItbInvalidFault *Flt = new ItbInvalidFault();
378 /* EntryHi VPN, ASID fields must be set */
379 Flt->EntryHi_Asid = Asid;
380 Flt->EntryHi_VPN2 = (VPN>>2);
381 Flt->EntryHi_VPN2X = (VPN & 0x3);
382
383 /* BadVAddr must be set */
384 Flt->BadVAddr = req->getVaddr();
385
386 /* Context must be set */
387 Flt->Context_BadVPN2 = (VPN >> 2);
388 return Flt;
389 }
390 else
391 {// Ok, this is really a match, set paddr
392 // hits++;
393 Addr PAddr;
394 if(EvenOdd == 0){
395 PAddr = pte->PFN0;
396 }else{
397 PAddr = pte->PFN1;
398 }
399 PAddr >>= (pte->AddrShiftAmount-12);
400 PAddr <<= pte->AddrShiftAmount;
401 PAddr |= ((req->getVaddr()) & pte->OffsetMask);
402 req->setPaddr(PAddr);
403
404
405 }
406 }
407 else
408 { // Didn't find any match, return a TLB Refill Exception
409 // misses++;
410 ItbRefillFault *Flt=new ItbRefillFault();
411 /* EntryHi VPN, ASID fields must be set */
412 Flt->EntryHi_Asid = Asid;
413 Flt->EntryHi_VPN2 = (VPN>>2);
414 Flt->EntryHi_VPN2X = (VPN & 0x3);
415
416
417 /* BadVAddr must be set */
418 Flt->BadVAddr = req->getVaddr();
419
420 /* Context must be set */
421 Flt->Context_BadVPN2 = (VPN >> 2);
422 return Flt;
423 }
424 }
425 return checkCacheability(req);
426 #endif
427 }
428
429 Fault
430 DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
431 {
432 #if !FULL_SYSTEM
433 Process * p = tc->getProcessPtr();
434
435 Fault fault = p->pTable->translate(req);
436 if(fault != NoFault)
437 return fault;
438
439 return NoFault;
440 #else
441 if(MipsISA::IsKSeg0(req->getVaddr()))
442 {
443 // Address will not be translated through TLB, set response, and go!
444 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
445 if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned())
446 {
447 StoreAddressErrorFault *Flt = new StoreAddressErrorFault();
448 /* BadVAddr must be set */
449 Flt->BadVAddr = req->getVaddr();
450
451 return Flt;
452 }
453 }
454 else if(MipsISA::IsKSeg1(req->getVaddr()))
455 {
456 // Address will not be translated through TLB, set response, and go!
457 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr()));
458 }
459 else
460 {
461 /* This is an optimization - smallPages is updated every time a TLB operation is performed
462 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we
463 do a TLB lookup */
464 Addr VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC);
465 if(smallPages==1){
466 VPN=((req->getVaddr() >> 11));
467 }
468 uint8_t Asid = req->getAsid();
469 MipsISA::PTE *pte = lookup(VPN,Asid);
470 if(req->isMisaligned()){ // Unaligned address!
471 StoreAddressErrorFault *Flt = new StoreAddressErrorFault();
472 /* BadVAddr must be set */
473 Flt->BadVAddr = req->getVaddr();
474 return Flt;
475 }
476 if(pte != NULL)
477 {// Ok, found something
478 /* Check for valid bits */
479 int EvenOdd;
480 bool Valid;
481 bool Dirty;
482 if(((((req->getVaddr()) >> pte->AddrShiftAmount) & 1)) ==0){
483 // Check even bits
484 Valid = pte->V0;
485 Dirty = pte->D0;
486 EvenOdd = 0;
487
488 } else {
489 // Check odd bits
490 Valid = pte->V1;
491 Dirty = pte->D1;
492 EvenOdd = 1;
493 }
494
495 if(Valid == false)
496 {//Invalid entry
497 // invalids++;
498 DtbInvalidFault *Flt = new DtbInvalidFault();
499 /* EntryHi VPN, ASID fields must be set */
500 Flt->EntryHi_Asid = Asid;
501 Flt->EntryHi_VPN2 = (VPN>>2);
502 Flt->EntryHi_VPN2X = (VPN & 0x3);
503
504
505 /* BadVAddr must be set */
506 Flt->BadVAddr = req->getVaddr();
507
508 /* Context must be set */
509 Flt->Context_BadVPN2 = (VPN >> 2);
510
511 return Flt;
512 }
513 else
514 {// Ok, this is really a match, set paddr
515 // hits++;
516 if(!Dirty)
517 {
518 TLBModifiedFault *Flt = new TLBModifiedFault();
519 /* EntryHi VPN, ASID fields must be set */
520 Flt->EntryHi_Asid = Asid;
521 Flt->EntryHi_VPN2 = (VPN>>2);
522 Flt->EntryHi_VPN2X = (VPN & 0x3);
523
524
525 /* BadVAddr must be set */
526 Flt->BadVAddr = req->getVaddr();
527
528 /* Context must be set */
529 Flt->Context_BadVPN2 = (VPN >> 2);
530 return Flt;
531
532 }
533 Addr PAddr;
534 if(EvenOdd == 0){
535 PAddr = pte->PFN0;
536 }else{
537 PAddr = pte->PFN1;
538 }
539 PAddr >>= (pte->AddrShiftAmount-12);
540 PAddr <<= pte->AddrShiftAmount;
541 PAddr |= ((req->getVaddr()) & pte->OffsetMask);
542 req->setPaddr(PAddr);
543 }
544 }
545 else
546 { // Didn't find any match, return a TLB Refill Exception
547 // misses++;
548 DtbRefillFault *Flt=new DtbRefillFault();
549 /* EntryHi VPN, ASID fields must be set */
550 Flt->EntryHi_Asid = Asid;
551 Flt->EntryHi_VPN2 = (VPN>>2);
552 Flt->EntryHi_VPN2X = (VPN & 0x3);
553
554
555 /* BadVAddr must be set */
556 Flt->BadVAddr = req->getVaddr();
557
558 /* Context must be set */
559 Flt->Context_BadVPN2 = (VPN >> 2);
560 return Flt;
561 }
562 }
563 return checkCacheability(req);
564 #endif
565 }
566
567 ///////////////////////////////////////////////////////////////////////
568 //
569 // Mips ITB
570 //
571 ITB::ITB(const Params *p)
572 : TLB(p)
573 {}
574
575
576 // void
577 // ITB::regStats()
578 // {
579 // /* hits - causes failure for some reason
580 // .name(name() + ".hits")
581 // .desc("ITB hits");
582 // misses
583 // .name(name() + ".misses")
584 // .desc("ITB misses");
585 // acv
586 // .name(name() + ".acv")
587 // .desc("ITB acv");
588 // accesses
589 // .name(name() + ".accesses")
590 // .desc("ITB accesses");
591
592 // accesses = hits + misses + invalids; */
593 // }
594
595
596
597 ///////////////////////////////////////////////////////////////////////
598 //
599 // Mips DTB
600 //
601 DTB::DTB(const Params *p)
602 : TLB(p)
603 {}
604
605 ///////////////////////////////////////////////////////////////////////
606 //
607 // Mips UTB
608 //
609 UTB::UTB(const Params *p)
610 : ITB(p), DTB(p)
611 {}
612
613
614
615 MipsISA::PTE &
616 TLB::index(bool advance)
617 {
618 MipsISA::PTE *pte = &table[nlu];
619
620 if (advance)
621 nextnlu();
622
623 return *pte;
624 }
625
626 MipsISA::ITB *
627 MipsITBParams::create()
628 {
629 return new MipsISA::ITB(this);
630 }
631
632 MipsISA::DTB *
633 MipsDTBParams::create()
634 {
635 return new MipsISA::DTB(this);
636 }
637
638 MipsISA::UTB *
639 MipsUTBParams::create()
640 {
641 return new MipsISA::UTB(this);
642 }