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