fix MIPS headers
[gem5.git] / src / arch / mips / tlb.cc
1 /*
2 * Copyright (c) 2007 MIPS Technologies, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Jaidev Patwardhan
29 */
30
31 #include <string>
32 #include <vector>
33
34 #include "arch/mips/pra_constants.hh"
35 #include "arch/mips/pagetable.hh"
36 #include "arch/mips/tlb.hh"
37 #include "arch/mips/faults.hh"
38 #include "arch/mips/utility.hh"
39 #include "base/inifile.hh"
40 #include "base/str.hh"
41 #include "base/trace.hh"
42 #include "cpu/thread_context.hh"
43 #include "sim/process.hh"
44 #include "mem/page_table.hh"
45 #include "params/MipsDTB.hh"
46 #include "params/MipsITB.hh"
47 #include "params/MipsTLB.hh"
48 #include "params/MipsUTB.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 TLB::TLB(const Params *p)
62 : SimObject(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
69 TLB::~TLB()
70 {
71 if (table)
72 delete [] table;
73 }
74
75 // look up an entry in the TLB
76 MipsISA::PTE *
77 TLB::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
106 MipsISA::PTE* TLB::getEntry(unsigned Index) const
107 {
108 // Make sure that Index is valid
109 assert(Index<size);
110 return &table[Index];
111 }
112
113 int 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 }
141 Fault inline
142 TLB::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(req->getFlags() | UNCACHEABLE);
150 }
151 return NoFault;
152 }
153 void 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
176 void
177 TLB::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
214 void
215 TLB::flushAll()
216 {
217 DPRINTF(TLB, "flushAll\n");
218 memset(table, 0, sizeof(MipsISA::PTE[size]));
219 lookupTable.clear();
220 nlu = 0;
221 }
222
223 void
224 TLB::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
235 void
236 TLB::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
249 void
250 TLB::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
309 Fault
310 ITB::translate(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
426 Fault
427 DTB::translate(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
564 ///////////////////////////////////////////////////////////////////////
565 //
566 // Mips ITB
567 //
568 ITB::ITB(const Params *p)
569 : TLB(p)
570 {}
571
572
573 // void
574 // ITB::regStats()
575 // {
576 // /* hits - causes failure for some reason
577 // .name(name() + ".hits")
578 // .desc("ITB hits");
579 // misses
580 // .name(name() + ".misses")
581 // .desc("ITB misses");
582 // acv
583 // .name(name() + ".acv")
584 // .desc("ITB acv");
585 // accesses
586 // .name(name() + ".accesses")
587 // .desc("ITB accesses");
588
589 // accesses = hits + misses + invalids; */
590 // }
591
592
593
594 ///////////////////////////////////////////////////////////////////////
595 //
596 // Mips DTB
597 //
598 DTB::DTB(const Params *p)
599 : TLB(p)
600 {}
601
602 ///////////////////////////////////////////////////////////////////////
603 //
604 // Mips UTB
605 //
606 UTB::UTB(const Params *p)
607 : ITB(p), DTB(p)
608 {}
609
610
611
612 MipsISA::PTE &
613 TLB::index(bool advance)
614 {
615 MipsISA::PTE *pte = &table[nlu];
616
617 if (advance)
618 nextnlu();
619
620 return *pte;
621 }
622
623 MipsISA::ITB *
624 MipsITBParams::create()
625 {
626 return new MipsISA::ITB(this);
627 }
628
629 MipsISA::DTB *
630 MipsDTBParams::create()
631 {
632 return new MipsISA::DTB(this);
633 }
634
635 MipsISA::UTB *
636 MipsUTBParams::create()
637 {
638 return new MipsISA::UTB(this);
639 }