tlb.cc (3569:ef68c162610f) tlb.cc (3804:fa7a01dddc7a)
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
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;

--- 11 unchanged lines hidden (view full) ---

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 *
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
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;

--- 11 unchanged lines hidden (view full) ---

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: Nathan Binkert
29 * Steve Reinhardt
30 * Andrew Schultz
28 * Authors: Ali Saidi
31 */
32
29 */
30
31#include "arch/sparc/asi.hh"
33#include "arch/sparc/tlb.hh"
34#include "sim/builder.hh"
32#include "arch/sparc/tlb.hh"
33#include "sim/builder.hh"
34#include "arch/sparc/miscregfile.hh"
35#include "cpu/thread_context.hh"
35
36
37/* @todo remove some of the magic constants. -- ali
38 * */
36namespace SparcISA
37{
39namespace SparcISA
40{
38 DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
39
41
40 BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
42TLB::TLB(const std::string &name, int s)
43 : SimObject(name), size(s)
44{
45 // To make this work you'll have to change the hypervisor and OS
46 if (size > 64)
47 fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
41
48
42 Param<int> size;
49 tlb = new TlbEntry[size];
50 memset(tlb, 0, sizeof(TlbEntry) * size);
51}
43
52
44 END_DECLARE_SIM_OBJECT_PARAMS(ITB)
53void
54TLB::clearUsedBits()
55{
56 MapIter i;
57 for (i = lookupTable.begin(); i != lookupTable.end();) {
58 TlbEntry *t = i->second;
59 if (!t->pte.locked()) {
60 t->used = false;
61 usedEntries--;
62 }
63 }
64}
45
65
46 BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
47
66
48 INIT_PARAM_DFLT(size, "TLB size", 48)
67void
68TLB::insert(Addr va, int partition_id, int context_id, bool real,
69 const PageTableEntry& PTE)
70{
49
71
50 END_INIT_SIM_OBJECT_PARAMS(ITB)
51
72
73 MapIter i;
74 TlbEntry *new_entry;
75 int x = -1;
76 for (x = 0; x < size; x++) {
77 if (!tlb[x].valid || !tlb[x].used) {
78 new_entry = &tlb[x];
79 break;
80 }
81 }
52
82
53 CREATE_SIM_OBJECT(ITB)
54 {
55 return new ITB(getInstanceName(), size);
83 // Update the last ently if their all locked
84 if (x == -1)
85 x = size - 1;
86
87 assert(PTE.valid());
88 new_entry->range.va = va;
89 new_entry->range.size = PTE.size();
90 new_entry->range.partitionId = partition_id;
91 new_entry->range.contextId = context_id;
92 new_entry->range.real = real;
93 new_entry->pte = PTE;
94 new_entry->used = true;;
95 new_entry->valid = true;
96 usedEntries++;
97
98
99 // Demap any entry that conflicts
100 i = lookupTable.find(new_entry->range);
101 if (i != lookupTable.end()) {
102 i->second->valid = false;
103 if (i->second->used) {
104 i->second->used = false;
105 usedEntries--;
106 }
107 lookupTable.erase(i);
56 }
57
108 }
109
58 REGISTER_SIM_OBJECT("SparcITB", ITB)
110 lookupTable.insert(new_entry->range, new_entry);;
59
111
60 BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
112 // If all entries have there used bit set, clear it on them all, but the
113 // one we just inserted
114 if (usedEntries == size) {
115 clearUsedBits();
116 new_entry->used = true;
117 usedEntries++;
118 }
61
119
62 Param<int> size;
120}
63
121
64 END_DECLARE_SIM_OBJECT_PARAMS(DTB)
65
122
66 BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
123TlbEntry*
124TLB::lookup(Addr va, int partition_id, bool real, int context_id)
125{
126 MapIter i;
127 TlbRange tr;
128 TlbEntry *t;
67
129
68 INIT_PARAM_DFLT(size, "TLB size", 64)
130 // Assemble full address structure
131 tr.va = va;
132 tr.size = va + MachineBytes;
133 tr.contextId = context_id;
134 tr.partitionId = partition_id;
135 tr.real = real;
69
136
70 END_INIT_SIM_OBJECT_PARAMS(DTB)
137 // Try to find the entry
138 i = lookupTable.find(tr);
139 if (i == lookupTable.end()) {
140 return NULL;
141 }
71
142
143 // Mark the entries used bit and clear other used bits in needed
144 t = i->second;
145 if (!t->used) {
146 t->used = true;
147 usedEntries++;
148 if (usedEntries == size) {
149 clearUsedBits();
150 t->used = true;
151 usedEntries++;
152 }
153 }
72
154
73 CREATE_SIM_OBJECT(DTB)
74 {
75 return new DTB(getInstanceName(), size);
155 return t;
156}
157
158
159void
160TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
161{
162 TlbRange tr;
163 MapIter i;
164
165 // Assemble full address structure
166 tr.va = va;
167 tr.size = va + MachineBytes;
168 tr.contextId = context_id;
169 tr.partitionId = partition_id;
170 tr.real = real;
171
172 // Demap any entry that conflicts
173 i = lookupTable.find(tr);
174 if (i != lookupTable.end()) {
175 i->second->valid = false;
176 if (i->second->used) {
177 i->second->used = false;
178 usedEntries--;
179 }
180 lookupTable.erase(i);
76 }
181 }
182}
77
183
78 REGISTER_SIM_OBJECT("SparcDTB", DTB)
184void
185TLB::demapContext(int partition_id, int context_id)
186{
187 int x;
188 for (x = 0; x < size; x++) {
189 if (tlb[x].range.contextId == context_id &&
190 tlb[x].range.partitionId == partition_id) {
191 tlb[x].valid = false;
192 if (tlb[x].used) {
193 tlb[x].used = false;
194 usedEntries--;
195 }
196 lookupTable.erase(tlb[x].range);
197 }
198 }
79}
199}
200
201void
202TLB::demapAll(int partition_id)
203{
204 int x;
205 for (x = 0; x < size; x++) {
206 if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
207 tlb[x].valid = false;
208 if (tlb[x].used) {
209 tlb[x].used = false;
210 usedEntries--;
211 }
212 lookupTable.erase(tlb[x].range);
213 }
214 }
215}
216
217void
218TLB::invalidateAll()
219{
220 int x;
221 for (x = 0; x < size; x++) {
222 tlb[x].valid = false;
223 }
224 usedEntries = 0;
225}
226
227uint64_t
228TLB::TteRead(int entry) {
229 assert(entry < size);
230 return tlb[entry].pte();
231}
232
233uint64_t
234TLB::TagRead(int entry) {
235 assert(entry < size);
236 uint64_t tag;
237
238 tag = tlb[entry].range.contextId | tlb[entry].range.va |
239 (uint64_t)tlb[entry].range.partitionId << 61;
240 tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
241 tag |= (uint64_t)~tlb[entry].pte._size() << 56;
242 return tag;
243}
244
245bool
246TLB::validVirtualAddress(Addr va, bool am)
247{
248 if (am)
249 return true;
250 if (va >= StartVAddrHole && va <= EndVAddrHole)
251 return false;
252 return true;
253}
254
255void
256TLB::writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct,
257 bool se, FaultTypes ft, int asi)
258{
259 uint64_t sfsr;
260 sfsr = tc->readMiscReg(reg);
261
262 if (sfsr & 0x1)
263 sfsr = 0x3;
264 else
265 sfsr = 1;
266
267 if (write)
268 sfsr |= 1 << 2;
269 sfsr |= ct << 4;
270 if (se)
271 sfsr |= 1 << 6;
272 sfsr |= ft << 7;
273 sfsr |= asi << 16;
274 tc->setMiscReg(reg, sfsr);
275}
276
277
278void
279ITB::writeSfsr(ThreadContext *tc, bool write, ContextType ct,
280 bool se, FaultTypes ft, int asi)
281{
282 TLB::writeSfsr(tc, MISCREG_MMU_ITLB_SFSR, write, ct, se, ft, asi);
283}
284
285void
286DTB::writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct,
287 bool se, FaultTypes ft, int asi)
288{
289 TLB::writeSfsr(tc, MISCREG_MMU_DTLB_SFSR, write, ct, se, ft, asi);
290 tc->setMiscReg(MISCREG_MMU_DTLB_SFAR, a);
291}
292
293
294Fault
295ITB::translate(RequestPtr &req, ThreadContext *tc)
296{
297 uint64_t hpstate = tc->readMiscReg(MISCREG_HPSTATE);
298 uint64_t pstate = tc->readMiscReg(MISCREG_PSTATE);
299 bool lsuIm = tc->readMiscReg(MISCREG_MMU_LSU_CTRL) >> 2 & 0x1;
300 uint64_t tl = tc->readMiscReg(MISCREG_TL);
301 uint64_t part_id = tc->readMiscReg(MISCREG_MMU_PART_ID);
302 bool addr_mask = pstate >> 3 & 0x1;
303 bool priv = pstate >> 2 & 0x1;
304 Addr vaddr = req->getVaddr();
305 int context;
306 ContextType ct;
307 int asi;
308 bool real = false;
309 TlbEntry *e;
310
311 assert(req->getAsi() == ASI_IMPLICIT);
312
313 if (tl > 0) {
314 asi = ASI_N;
315 ct = Nucleus;
316 context = 0;
317 } else {
318 asi = ASI_P;
319 ct = Primary;
320 context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
321 }
322
323 if ( hpstate >> 2 & 0x1 || hpstate >> 5 & 0x1 ) {
324 req->setPaddr(req->getVaddr() & PAddrImplMask);
325 return NoFault;
326 }
327
328 // If the asi is unaligned trap
329 if (vaddr & 0x7) {
330 writeSfsr(tc, false, ct, false, OtherFault, asi);
331 return new MemAddressNotAligned;
332 }
333
334 if (addr_mask)
335 vaddr = vaddr & VAddrAMask;
336
337 if (!validVirtualAddress(vaddr, addr_mask)) {
338 writeSfsr(tc, false, ct, false, VaOutOfRange, asi);
339 return new InstructionAccessException;
340 }
341
342 if (lsuIm) {
343 e = lookup(req->getVaddr(), part_id, true);
344 real = true;
345 context = 0;
346 } else {
347 e = lookup(vaddr, part_id, false, context);
348 }
349
350 if (e == NULL || !e->valid) {
351 tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS,
352 vaddr & ~BytesInPageMask | context);
353 if (real)
354 return new InstructionRealTranslationMiss;
355 else
356 return new FastInstructionAccessMMUMiss;
357 }
358
359 // were not priviledged accesing priv page
360 if (!priv && e->pte.priv()) {
361 writeSfsr(tc, false, ct, false, PrivViolation, asi);
362 return new InstructionAccessException;
363 }
364
365 req->setPaddr(e->pte.paddr() & ~e->pte.size() |
366 req->getVaddr() & e->pte.size());
367 return NoFault;
368}
369
370
371
372Fault
373DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
374{
375 /* @todo this could really use some profiling and fixing to make it faster! */
376 uint64_t hpstate = tc->readMiscReg(MISCREG_HPSTATE);
377 uint64_t pstate = tc->readMiscReg(MISCREG_PSTATE);
378 bool lsuDm = tc->readMiscReg(MISCREG_MMU_LSU_CTRL) >> 3 & 0x1;
379 uint64_t tl = tc->readMiscReg(MISCREG_TL);
380 uint64_t part_id = tc->readMiscReg(MISCREG_MMU_PART_ID);
381 bool hpriv = hpstate >> 2 & 0x1;
382 bool red = hpstate >> 5 >> 0x1;
383 bool addr_mask = pstate >> 3 & 0x1;
384 bool priv = pstate >> 2 & 0x1;
385 bool implicit = false;
386 bool real = false;
387 Addr vaddr = req->getVaddr();
388 ContextType ct;
389 int context;
390 ASI asi;
391
392 TlbEntry *e;
393
394
395 asi = (ASI)req->getAsi();
396 if (asi == ASI_IMPLICIT)
397 implicit = true;
398
399 if (implicit) {
400 if (tl > 0) {
401 asi = ASI_N;
402 ct = Nucleus;
403 context = 0;
404 } else {
405 asi = ASI_P;
406 ct = Primary;
407 context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
408 }
409 } else if (!hpriv && !red) {
410 if (tl > 0) {
411 ct = Nucleus;
412 context = 0;
413 } else if (AsiIsSecondary(asi)) {
414 ct = Secondary;
415 context = tc->readMiscReg(MISCREG_MMU_S_CONTEXT);
416 } else {
417 context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
418 ct = Primary; //???
419 }
420
421 // We need to check for priv level/asi priv
422 if (!priv && !AsiIsUnPriv(asi)) {
423 // It appears that context should be Nucleus in these cases?
424 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
425 return new PrivilegedAction;
426 }
427 if (priv && AsiIsHPriv(asi)) {
428 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
429 return new DataAccessException;
430 }
431
432 }
433
434 // If the asi is unaligned trap
435 if (AsiIsBlock(asi) && vaddr & 0x3f || vaddr & 0x7) {
436 writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
437 return new MemAddressNotAligned;
438 }
439
440 if (addr_mask)
441 vaddr = vaddr & VAddrAMask;
442
443 if (!validVirtualAddress(vaddr, addr_mask)) {
444 writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi);
445 return new DataAccessException;
446 }
447
448 if (!implicit) {
449 if (AsiIsLittle(asi))
450 panic("Little Endian ASIs not supported\n");
451 if (AsiIsBlock(asi))
452 panic("Block ASIs not supported\n");
453 if (AsiIsNoFault(asi))
454 panic("No Fault ASIs not supported\n");
455 if (AsiIsTwin(asi))
456 panic("Twin ASIs not supported\n");
457 if (AsiIsPartialStore(asi))
458 panic("Partial Store ASIs not supported\n");
459 if (AsiIsMmu(asi))
460 goto handleMmuRegAccess;
461
462 if (AsiIsScratchPad(asi))
463 goto handleScratchRegAccess;
464 }
465
466 if ((!lsuDm && !hpriv) || AsiIsReal(asi)) {
467 real = true;
468 context = 0;
469 };
470
471 if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
472 req->setPaddr(req->getVaddr() & PAddrImplMask);
473 return NoFault;
474 }
475
476 e = lookup(req->getVaddr(), part_id, real, context);
477
478 if (e == NULL || !e->valid) {
479 tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
480 vaddr & ~BytesInPageMask | context);
481 if (real)
482 return new DataRealTranslationMiss;
483 else
484 return new FastDataAccessMMUMiss;
485
486 }
487
488
489 if (write && !e->pte.writable()) {
490 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
491 return new FastDataAccessProtection;
492 }
493
494 if (e->pte.nofault() && !AsiIsNoFault(asi)) {
495 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
496 return new DataAccessException;
497 }
498
499 if (e->pte.sideffect())
500 req->setFlags(req->getFlags() | UNCACHEABLE);
501
502
503 if (!priv && e->pte.priv()) {
504 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
505 return new DataAccessException;
506 }
507
508 req->setPaddr(e->pte.paddr() & ~e->pte.size() |
509 req->getVaddr() & e->pte.size());
510 return NoFault;
511 /*** End of normal Path ***/
512
513handleMmuRegAccess:
514handleScratchRegAccess:
515 panic("How are we ever going to deal with this?\n");
516};
517
518void
519TLB::serialize(std::ostream &os)
520{
521 panic("Need to implement serialize tlb for SPARC\n");
522}
523
524void
525TLB::unserialize(Checkpoint *cp, const std::string &section)
526{
527 panic("Need to implement unserialize tlb for SPARC\n");
528}
529
530
531DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
532
533BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
534
535 Param<int> size;
536
537END_DECLARE_SIM_OBJECT_PARAMS(ITB)
538
539BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
540
541 INIT_PARAM_DFLT(size, "TLB size", 48)
542
543END_INIT_SIM_OBJECT_PARAMS(ITB)
544
545
546CREATE_SIM_OBJECT(ITB)
547{
548 return new ITB(getInstanceName(), size);
549}
550
551REGISTER_SIM_OBJECT("SparcITB", ITB)
552
553BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
554
555 Param<int> size;
556
557END_DECLARE_SIM_OBJECT_PARAMS(DTB)
558
559BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
560
561 INIT_PARAM_DFLT(size, "TLB size", 64)
562
563END_INIT_SIM_OBJECT_PARAMS(DTB)
564
565
566CREATE_SIM_OBJECT(DTB)
567{
568 return new DTB(getInstanceName(), size);
569}
570
571REGISTER_SIM_OBJECT("SparcDTB", DTB)
572}