tlb.cc (3881:f06ef65cd746) tlb.cc (3899:389e4ea5f98e)
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;
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: Ali Saidi
29 */
30
31#include "arch/sparc/asi.hh"
32#include "arch/sparc/miscregfile.hh"
33#include "arch/sparc/tlb.hh"
34#include "base/bitfield.hh"
35#include "base/trace.hh"
36#include "cpu/thread_context.hh"
37#include "cpu/base.hh"
38#include "mem/packet_access.hh"
39#include "mem/request.hh"
40#include "sim/builder.hh"
41
42/* @todo remove some of the magic constants. -- ali
43 * */
44namespace SparcISA
45{
46
47TLB::TLB(const std::string &name, int s)
48 : SimObject(name), size(s), usedEntries(0), lastReplaced(0),
49 cacheValid(false)
50{
51 // To make this work you'll have to change the hypervisor and OS
52 if (size > 64)
53 fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
54
55 tlb = new TlbEntry[size];
56 memset(tlb, 0, sizeof(TlbEntry) * size);
57
58 for (int x = 0; x < size; x++)
59 freeList.push_back(&tlb[x]);
60}
61
62void
63TLB::clearUsedBits()
64{
65 MapIter i;
66 for (i = lookupTable.begin(); i != lookupTable.end(); i++) {
67 TlbEntry *t = i->second;
68 if (!t->pte.locked()) {
69 t->used = false;
70 usedEntries--;
71 }
72 }
73}
74
75
76void
77TLB::insert(Addr va, int partition_id, int context_id, bool real,
78 const PageTableEntry& PTE, int entry)
79{
80
81
82 MapIter i;
83 TlbEntry *new_entry = NULL;
84 TlbRange tr;
85 int x;
86
87 cacheValid = false;
88 tr.va = va;
89 tr.size = PTE.size() - 1;
90 tr.contextId = context_id;
91 tr.partitionId = partition_id;
92 tr.real = real;
93
94
95 DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
96 va, PTE.paddr(), partition_id, context_id, (int)real, entry);
97
98 // Demap any entry that conflicts
99 i = lookupTable.find(tr);
100 if (i != lookupTable.end()) {
101 i->second->valid = false;
102 if (i->second->used) {
103 i->second->used = false;
104 usedEntries--;
105 }
106 freeList.push_front(i->second);
107 DPRINTF(TLB, "TLB: Found conflicting entry %#X , deleting it\n",
108 i->second);
109 lookupTable.erase(i);
110 }
111
112
113 if (entry != -1) {
114 assert(entry < size && entry >= 0);
115 new_entry = &tlb[entry];
116 } else {
117 if (!freeList.empty()) {
118 new_entry = freeList.front();
119 } else {
120 x = lastReplaced;
121 do {
122 ++x;
123 if (x == size)
124 x = 0;
125 if (x == lastReplaced)
126 goto insertAllLocked;
127 } while (tlb[x].pte.locked());
128 lastReplaced = x;
129 new_entry = &tlb[x];
130 lookupTable.erase(new_entry->range);
131 }
132 /*
133 for (x = 0; x < size; x++) {
134 if (!tlb[x].valid || !tlb[x].used) {
135 new_entry = &tlb[x];
136 break;
137 }
138 }*/
139 }
140
141insertAllLocked:
142 // Update the last ently if their all locked
143 if (!new_entry) {
144 new_entry = &tlb[size-1];
145 lookupTable.erase(new_entry->range);
146 }
147
148 freeList.remove(new_entry);
149 DPRINTF(TLB, "Using entry: %#X\n", new_entry);
150
151 assert(PTE.valid());
152 new_entry->range.va = va;
153 new_entry->range.size = PTE.size() - 1;
154 new_entry->range.partitionId = partition_id;
155 new_entry->range.contextId = context_id;
156 new_entry->range.real = real;
157 new_entry->pte = PTE;
158 new_entry->used = true;;
159 new_entry->valid = true;
160 usedEntries++;
161
162
163
164 i = lookupTable.insert(new_entry->range, new_entry);
165 assert(i != lookupTable.end());
166
167 // If all entries have there used bit set, clear it on them all, but the
168 // one we just inserted
169 if (usedEntries == size) {
170 clearUsedBits();
171 new_entry->used = true;
172 usedEntries++;
173 }
174
175}
176
177
178TlbEntry*
179TLB::lookup(Addr va, int partition_id, bool real, int context_id)
180{
181 MapIter i;
182 TlbRange tr;
183 TlbEntry *t;
184
185 DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n",
186 va, partition_id, context_id, real);
187 // Assemble full address structure
188 tr.va = va;
189 tr.size = MachineBytes;
190 tr.contextId = context_id;
191 tr.partitionId = partition_id;
192 tr.real = real;
193
194 // Try to find the entry
195 i = lookupTable.find(tr);
196 if (i == lookupTable.end()) {
197 DPRINTF(TLB, "TLB: No valid entry found\n");
198 return NULL;
199 }
200
201 // Mark the entries used bit and clear other used bits in needed
202 t = i->second;
203 DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
204 t->pte.size());
205 if (!t->used) {
206 t->used = true;
207 usedEntries++;
208 if (usedEntries == size) {
209 clearUsedBits();
210 t->used = true;
211 usedEntries++;
212 }
213 }
214
215 return t;
216}
217
218void
219TLB::dumpAll()
220{
221 MapIter i;
222 for (int x = 0; x < size; x++) {
223 if (tlb[x].valid) {
224 DPRINTFN("%4d: %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",
225 x, tlb[x].range.partitionId, tlb[x].range.contextId,
226 tlb[x].range.real ? 'R' : ' ', tlb[x].range.size,
227 tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte());
228 }
229 }
230}
231
232void
233TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
234{
235 TlbRange tr;
236 MapIter i;
237
238 DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n",
239 va, partition_id, context_id, real);
240
241 cacheValid = false;
242
243 // Assemble full address structure
244 tr.va = va;
245 tr.size = MachineBytes;
246 tr.contextId = context_id;
247 tr.partitionId = partition_id;
248 tr.real = real;
249
250 // Demap any entry that conflicts
251 i = lookupTable.find(tr);
252 if (i != lookupTable.end()) {
253 DPRINTF(IPR, "TLB: Demapped page\n");
254 i->second->valid = false;
255 if (i->second->used) {
256 i->second->used = false;
257 usedEntries--;
258 }
259 freeList.push_front(i->second);
260 DPRINTF(TLB, "Freeing TLB entry : %#X\n", i->second);
261 lookupTable.erase(i);
262 }
263}
264
265void
266TLB::demapContext(int partition_id, int context_id)
267{
268 int x;
269 DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
270 partition_id, context_id);
271 cacheValid = false;
272 for (x = 0; x < size; x++) {
273 if (tlb[x].range.contextId == context_id &&
274 tlb[x].range.partitionId == partition_id) {
275 if (tlb[x].valid == true) {
276 freeList.push_front(&tlb[x]);
277 DPRINTF(TLB, "Freeing TLB entry : %#X\n", &tlb[x]);
278 }
279 tlb[x].valid = false;
280 if (tlb[x].used) {
281 tlb[x].used = false;
282 usedEntries--;
283 }
284 lookupTable.erase(tlb[x].range);
285 }
286 }
287}
288
289void
290TLB::demapAll(int partition_id)
291{
292 int x;
293 DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
294 cacheValid = false;
295 for (x = 0; x < size; x++) {
296 if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
297 if (tlb[x].valid == true){
298 freeList.push_front(&tlb[x]);
299 DPRINTF(TLB, "Freeing TLB entry : %#X\n", &tlb[x]);
300 }
301 tlb[x].valid = false;
302 if (tlb[x].used) {
303 tlb[x].used = false;
304 usedEntries--;
305 }
306 lookupTable.erase(tlb[x].range);
307 }
308 }
309}
310
311void
312TLB::invalidateAll()
313{
314 int x;
315 cacheValid = false;
316
317 freeList.clear();
318 for (x = 0; x < size; x++) {
319 if (tlb[x].valid == true)
320 freeList.push_back(&tlb[x]);
321 tlb[x].valid = false;
322 }
323 usedEntries = 0;
324}
325
326uint64_t
327TLB::TteRead(int entry) {
328 if (entry >= size)
329 panic("entry: %d\n", entry);
330
331 assert(entry < size);
332 if (tlb[entry].valid)
333 return tlb[entry].pte();
334 else
335 return (uint64_t)-1ll;
336}
337
338uint64_t
339TLB::TagRead(int entry) {
340 assert(entry < size);
341 uint64_t tag;
342 if (!tlb[entry].valid)
343 return (uint64_t)-1ll;
344
345 tag = tlb[entry].range.contextId;
346 tag |= tlb[entry].range.va;
347 tag |= (uint64_t)tlb[entry].range.partitionId << 61;
348 tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
349 tag |= (uint64_t)~tlb[entry].pte._size() << 56;
350 return tag;
351}
352
353bool
354TLB::validVirtualAddress(Addr va, bool am)
355{
356 if (am)
357 return true;
358 if (va >= StartVAddrHole && va <= EndVAddrHole)
359 return false;
360 return true;
361}
362
363void
364TLB::writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct,
365 bool se, FaultTypes ft, int asi)
366{
367 uint64_t sfsr;
368 sfsr = tc->readMiscReg(reg);
369
370 if (sfsr & 0x1)
371 sfsr = 0x3;
372 else
373 sfsr = 1;
374
375 if (write)
376 sfsr |= 1 << 2;
377 sfsr |= ct << 4;
378 if (se)
379 sfsr |= 1 << 6;
380 sfsr |= ft << 7;
381 sfsr |= asi << 16;
382 tc->setMiscRegWithEffect(reg, sfsr);
383}
384
385void
386TLB::writeTagAccess(ThreadContext *tc, int reg, Addr va, int context)
387{
388 tc->setMiscRegWithEffect(reg, mbits(va, 63,13) | mbits(context,12,0));
389}
390
391void
392ITB::writeSfsr(ThreadContext *tc, bool write, ContextType ct,
393 bool se, FaultTypes ft, int asi)
394{
395 DPRINTF(TLB, "TLB: ITB Fault: w=%d ct=%d ft=%d asi=%d\n",
396 (int)write, ct, ft, asi);
397 TLB::writeSfsr(tc, MISCREG_MMU_ITLB_SFSR, write, ct, se, ft, asi);
398}
399
400void
401ITB::writeTagAccess(ThreadContext *tc, Addr va, int context)
402{
403 TLB::writeTagAccess(tc, MISCREG_MMU_ITLB_TAG_ACCESS, va, context);
404}
405
406void
407DTB::writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct,
408 bool se, FaultTypes ft, int asi)
409{
410 DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n",
411 a, (int)write, ct, ft, asi);
412 TLB::writeSfsr(tc, MISCREG_MMU_DTLB_SFSR, write, ct, se, ft, asi);
413 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_SFAR, a);
414}
415
416void
417DTB::writeTagAccess(ThreadContext *tc, Addr va, int context)
418{
419 TLB::writeTagAccess(tc, MISCREG_MMU_DTLB_TAG_ACCESS, va, context);
420}
421
422
423
424Fault
425ITB::translate(RequestPtr &req, ThreadContext *tc)
426{
427 uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA);
428
429 Addr vaddr = req->getVaddr();
430 TlbEntry *e;
431
432 assert(req->getAsi() == ASI_IMPLICIT);
433
434 DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n",
435 vaddr, req->getSize());
436
437 // Be fast if we can!
438 if (cacheValid && cacheState == tlbdata) {
439 if (cacheEntry) {
440 if (cacheEntry->range.va < vaddr + sizeof(MachInst) &&
441 cacheEntry->range.va + cacheEntry->range.size >= vaddr) {
442 req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) |
443 vaddr & cacheEntry->pte.size()-1 );
444 return NoFault;
445 }
446 } else {
447 req->setPaddr(vaddr & PAddrImplMask);
448 return NoFault;
449 }
450 }
451
452 bool hpriv = bits(tlbdata,0,0);
453 bool red = bits(tlbdata,1,1);
454 bool priv = bits(tlbdata,2,2);
455 bool addr_mask = bits(tlbdata,3,3);
456 bool lsu_im = bits(tlbdata,4,4);
457
458 int part_id = bits(tlbdata,15,8);
459 int tl = bits(tlbdata,18,16);
460 int pri_context = bits(tlbdata,47,32);
461 int context;
462 ContextType ct;
463 int asi;
464 bool real = false;
465
466 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n",
467 priv, hpriv, red, lsu_im, part_id);
468
469 if (tl > 0) {
470 asi = ASI_N;
471 ct = Nucleus;
472 context = 0;
473 } else {
474 asi = ASI_P;
475 ct = Primary;
476 context = pri_context;
477 }
478
479 if ( hpriv || red ) {
480 cacheValid = true;
481 cacheState = tlbdata;
482 cacheEntry = NULL;
483 req->setPaddr(vaddr & PAddrImplMask);
484 return NoFault;
485 }
486
487 // If the access is unaligned trap
488 if (vaddr & 0x3) {
489 writeSfsr(tc, false, ct, false, OtherFault, asi);
490 return new MemAddressNotAligned;
491 }
492
493 if (addr_mask)
494 vaddr = vaddr & VAddrAMask;
495
496 if (!validVirtualAddress(vaddr, addr_mask)) {
497 writeSfsr(tc, false, ct, false, VaOutOfRange, asi);
498 return new InstructionAccessException;
499 }
500
501 if (!lsu_im) {
502 e = lookup(vaddr, part_id, true);
503 real = true;
504 context = 0;
505 } else {
506 e = lookup(vaddr, part_id, false, context);
507 }
508
509 if (e == NULL || !e->valid) {
510 tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS,
511 vaddr & ~BytesInPageMask | context);
512 if (real)
513 return new InstructionRealTranslationMiss;
514 else
515 return new FastInstructionAccessMMUMiss;
516 }
517
518 // were not priviledged accesing priv page
519 if (!priv && e->pte.priv()) {
520 writeSfsr(tc, false, ct, false, PrivViolation, asi);
521 return new InstructionAccessException;
522 }
523
524 // cache translation date for next translation
525 cacheValid = true;
526 cacheState = tlbdata;
527 cacheEntry = e;
528
529 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
530 vaddr & e->pte.size()-1 );
531 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
532 return NoFault;
533}
534
535
536
537Fault
538DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
539{
540 /* @todo this could really use some profiling and fixing to make it faster! */
541 uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA);
542 Addr vaddr = req->getVaddr();
543 Addr size = req->getSize();
544 ASI asi;
545 asi = (ASI)req->getAsi();
546 bool implicit = false;
547 bool hpriv = bits(tlbdata,0,0);
548
549 DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
550 vaddr, size, asi);
551
552 if (asi == ASI_IMPLICIT)
553 implicit = true;
554
555 if (hpriv && implicit) {
556 req->setPaddr(vaddr & PAddrImplMask);
557 return NoFault;
558 }
559
560 // Be fast if we can!
561 if (cacheValid && cacheState == tlbdata) {
562 if (cacheEntry[0] && cacheAsi[0] == asi && cacheEntry[0]->range.va < vaddr + size &&
563 cacheEntry[0]->range.va + cacheEntry[0]->range.size > vaddr) {
564 req->setPaddr(cacheEntry[0]->pte.paddr() & ~(cacheEntry[0]->pte.size()-1) |
565 vaddr & cacheEntry[0]->pte.size()-1 );
566 return NoFault;
567 }
568 if (cacheEntry[1] && cacheAsi[1] == asi && cacheEntry[1]->range.va < vaddr + size &&
569 cacheEntry[1]->range.va + cacheEntry[1]->range.size > vaddr) {
570 req->setPaddr(cacheEntry[1]->pte.paddr() & ~(cacheEntry[1]->pte.size()-1) |
571 vaddr & cacheEntry[1]->pte.size()-1 );
572 return NoFault;
573 }
574 }
575
576 bool red = bits(tlbdata,1,1);
577 bool priv = bits(tlbdata,2,2);
578 bool addr_mask = bits(tlbdata,3,3);
579 bool lsu_dm = bits(tlbdata,5,5);
580
581 int part_id = bits(tlbdata,15,8);
582 int tl = bits(tlbdata,18,16);
583 int pri_context = bits(tlbdata,47,32);
584 int sec_context = bits(tlbdata,47,32);
585
586 bool real = false;
587 ContextType ct = Primary;
588 int context = 0;
589
590 TlbEntry *e;
591
592 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
593 priv, hpriv, red, lsu_dm, part_id);
594
595 if (implicit) {
596 if (tl > 0) {
597 asi = ASI_N;
598 ct = Nucleus;
599 context = 0;
600 } else {
601 asi = ASI_P;
602 ct = Primary;
603 context = pri_context;
604 }
605 } else if (!hpriv && !red) {
606 if (tl > 0 || AsiIsNucleus(asi)) {
607 ct = Nucleus;
608 context = 0;
609 } else if (AsiIsSecondary(asi)) {
610 ct = Secondary;
611 context = sec_context;
612 } else {
613 context = pri_context;
614 ct = Primary; //???
615 }
616
617 // We need to check for priv level/asi priv
618 if (!priv && !AsiIsUnPriv(asi)) {
619 // It appears that context should be Nucleus in these cases?
620 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
621 return new PrivilegedAction;
622 }
623 if (priv && AsiIsHPriv(asi)) {
624 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
625 return new DataAccessException;
626 }
627
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;
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: Ali Saidi
29 */
30
31#include "arch/sparc/asi.hh"
32#include "arch/sparc/miscregfile.hh"
33#include "arch/sparc/tlb.hh"
34#include "base/bitfield.hh"
35#include "base/trace.hh"
36#include "cpu/thread_context.hh"
37#include "cpu/base.hh"
38#include "mem/packet_access.hh"
39#include "mem/request.hh"
40#include "sim/builder.hh"
41
42/* @todo remove some of the magic constants. -- ali
43 * */
44namespace SparcISA
45{
46
47TLB::TLB(const std::string &name, int s)
48 : SimObject(name), size(s), usedEntries(0), lastReplaced(0),
49 cacheValid(false)
50{
51 // To make this work you'll have to change the hypervisor and OS
52 if (size > 64)
53 fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
54
55 tlb = new TlbEntry[size];
56 memset(tlb, 0, sizeof(TlbEntry) * size);
57
58 for (int x = 0; x < size; x++)
59 freeList.push_back(&tlb[x]);
60}
61
62void
63TLB::clearUsedBits()
64{
65 MapIter i;
66 for (i = lookupTable.begin(); i != lookupTable.end(); i++) {
67 TlbEntry *t = i->second;
68 if (!t->pte.locked()) {
69 t->used = false;
70 usedEntries--;
71 }
72 }
73}
74
75
76void
77TLB::insert(Addr va, int partition_id, int context_id, bool real,
78 const PageTableEntry& PTE, int entry)
79{
80
81
82 MapIter i;
83 TlbEntry *new_entry = NULL;
84 TlbRange tr;
85 int x;
86
87 cacheValid = false;
88 tr.va = va;
89 tr.size = PTE.size() - 1;
90 tr.contextId = context_id;
91 tr.partitionId = partition_id;
92 tr.real = real;
93
94
95 DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
96 va, PTE.paddr(), partition_id, context_id, (int)real, entry);
97
98 // Demap any entry that conflicts
99 i = lookupTable.find(tr);
100 if (i != lookupTable.end()) {
101 i->second->valid = false;
102 if (i->second->used) {
103 i->second->used = false;
104 usedEntries--;
105 }
106 freeList.push_front(i->second);
107 DPRINTF(TLB, "TLB: Found conflicting entry %#X , deleting it\n",
108 i->second);
109 lookupTable.erase(i);
110 }
111
112
113 if (entry != -1) {
114 assert(entry < size && entry >= 0);
115 new_entry = &tlb[entry];
116 } else {
117 if (!freeList.empty()) {
118 new_entry = freeList.front();
119 } else {
120 x = lastReplaced;
121 do {
122 ++x;
123 if (x == size)
124 x = 0;
125 if (x == lastReplaced)
126 goto insertAllLocked;
127 } while (tlb[x].pte.locked());
128 lastReplaced = x;
129 new_entry = &tlb[x];
130 lookupTable.erase(new_entry->range);
131 }
132 /*
133 for (x = 0; x < size; x++) {
134 if (!tlb[x].valid || !tlb[x].used) {
135 new_entry = &tlb[x];
136 break;
137 }
138 }*/
139 }
140
141insertAllLocked:
142 // Update the last ently if their all locked
143 if (!new_entry) {
144 new_entry = &tlb[size-1];
145 lookupTable.erase(new_entry->range);
146 }
147
148 freeList.remove(new_entry);
149 DPRINTF(TLB, "Using entry: %#X\n", new_entry);
150
151 assert(PTE.valid());
152 new_entry->range.va = va;
153 new_entry->range.size = PTE.size() - 1;
154 new_entry->range.partitionId = partition_id;
155 new_entry->range.contextId = context_id;
156 new_entry->range.real = real;
157 new_entry->pte = PTE;
158 new_entry->used = true;;
159 new_entry->valid = true;
160 usedEntries++;
161
162
163
164 i = lookupTable.insert(new_entry->range, new_entry);
165 assert(i != lookupTable.end());
166
167 // If all entries have there used bit set, clear it on them all, but the
168 // one we just inserted
169 if (usedEntries == size) {
170 clearUsedBits();
171 new_entry->used = true;
172 usedEntries++;
173 }
174
175}
176
177
178TlbEntry*
179TLB::lookup(Addr va, int partition_id, bool real, int context_id)
180{
181 MapIter i;
182 TlbRange tr;
183 TlbEntry *t;
184
185 DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n",
186 va, partition_id, context_id, real);
187 // Assemble full address structure
188 tr.va = va;
189 tr.size = MachineBytes;
190 tr.contextId = context_id;
191 tr.partitionId = partition_id;
192 tr.real = real;
193
194 // Try to find the entry
195 i = lookupTable.find(tr);
196 if (i == lookupTable.end()) {
197 DPRINTF(TLB, "TLB: No valid entry found\n");
198 return NULL;
199 }
200
201 // Mark the entries used bit and clear other used bits in needed
202 t = i->second;
203 DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
204 t->pte.size());
205 if (!t->used) {
206 t->used = true;
207 usedEntries++;
208 if (usedEntries == size) {
209 clearUsedBits();
210 t->used = true;
211 usedEntries++;
212 }
213 }
214
215 return t;
216}
217
218void
219TLB::dumpAll()
220{
221 MapIter i;
222 for (int x = 0; x < size; x++) {
223 if (tlb[x].valid) {
224 DPRINTFN("%4d: %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",
225 x, tlb[x].range.partitionId, tlb[x].range.contextId,
226 tlb[x].range.real ? 'R' : ' ', tlb[x].range.size,
227 tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte());
228 }
229 }
230}
231
232void
233TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
234{
235 TlbRange tr;
236 MapIter i;
237
238 DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n",
239 va, partition_id, context_id, real);
240
241 cacheValid = false;
242
243 // Assemble full address structure
244 tr.va = va;
245 tr.size = MachineBytes;
246 tr.contextId = context_id;
247 tr.partitionId = partition_id;
248 tr.real = real;
249
250 // Demap any entry that conflicts
251 i = lookupTable.find(tr);
252 if (i != lookupTable.end()) {
253 DPRINTF(IPR, "TLB: Demapped page\n");
254 i->second->valid = false;
255 if (i->second->used) {
256 i->second->used = false;
257 usedEntries--;
258 }
259 freeList.push_front(i->second);
260 DPRINTF(TLB, "Freeing TLB entry : %#X\n", i->second);
261 lookupTable.erase(i);
262 }
263}
264
265void
266TLB::demapContext(int partition_id, int context_id)
267{
268 int x;
269 DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
270 partition_id, context_id);
271 cacheValid = false;
272 for (x = 0; x < size; x++) {
273 if (tlb[x].range.contextId == context_id &&
274 tlb[x].range.partitionId == partition_id) {
275 if (tlb[x].valid == true) {
276 freeList.push_front(&tlb[x]);
277 DPRINTF(TLB, "Freeing TLB entry : %#X\n", &tlb[x]);
278 }
279 tlb[x].valid = false;
280 if (tlb[x].used) {
281 tlb[x].used = false;
282 usedEntries--;
283 }
284 lookupTable.erase(tlb[x].range);
285 }
286 }
287}
288
289void
290TLB::demapAll(int partition_id)
291{
292 int x;
293 DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
294 cacheValid = false;
295 for (x = 0; x < size; x++) {
296 if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
297 if (tlb[x].valid == true){
298 freeList.push_front(&tlb[x]);
299 DPRINTF(TLB, "Freeing TLB entry : %#X\n", &tlb[x]);
300 }
301 tlb[x].valid = false;
302 if (tlb[x].used) {
303 tlb[x].used = false;
304 usedEntries--;
305 }
306 lookupTable.erase(tlb[x].range);
307 }
308 }
309}
310
311void
312TLB::invalidateAll()
313{
314 int x;
315 cacheValid = false;
316
317 freeList.clear();
318 for (x = 0; x < size; x++) {
319 if (tlb[x].valid == true)
320 freeList.push_back(&tlb[x]);
321 tlb[x].valid = false;
322 }
323 usedEntries = 0;
324}
325
326uint64_t
327TLB::TteRead(int entry) {
328 if (entry >= size)
329 panic("entry: %d\n", entry);
330
331 assert(entry < size);
332 if (tlb[entry].valid)
333 return tlb[entry].pte();
334 else
335 return (uint64_t)-1ll;
336}
337
338uint64_t
339TLB::TagRead(int entry) {
340 assert(entry < size);
341 uint64_t tag;
342 if (!tlb[entry].valid)
343 return (uint64_t)-1ll;
344
345 tag = tlb[entry].range.contextId;
346 tag |= tlb[entry].range.va;
347 tag |= (uint64_t)tlb[entry].range.partitionId << 61;
348 tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
349 tag |= (uint64_t)~tlb[entry].pte._size() << 56;
350 return tag;
351}
352
353bool
354TLB::validVirtualAddress(Addr va, bool am)
355{
356 if (am)
357 return true;
358 if (va >= StartVAddrHole && va <= EndVAddrHole)
359 return false;
360 return true;
361}
362
363void
364TLB::writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct,
365 bool se, FaultTypes ft, int asi)
366{
367 uint64_t sfsr;
368 sfsr = tc->readMiscReg(reg);
369
370 if (sfsr & 0x1)
371 sfsr = 0x3;
372 else
373 sfsr = 1;
374
375 if (write)
376 sfsr |= 1 << 2;
377 sfsr |= ct << 4;
378 if (se)
379 sfsr |= 1 << 6;
380 sfsr |= ft << 7;
381 sfsr |= asi << 16;
382 tc->setMiscRegWithEffect(reg, sfsr);
383}
384
385void
386TLB::writeTagAccess(ThreadContext *tc, int reg, Addr va, int context)
387{
388 tc->setMiscRegWithEffect(reg, mbits(va, 63,13) | mbits(context,12,0));
389}
390
391void
392ITB::writeSfsr(ThreadContext *tc, bool write, ContextType ct,
393 bool se, FaultTypes ft, int asi)
394{
395 DPRINTF(TLB, "TLB: ITB Fault: w=%d ct=%d ft=%d asi=%d\n",
396 (int)write, ct, ft, asi);
397 TLB::writeSfsr(tc, MISCREG_MMU_ITLB_SFSR, write, ct, se, ft, asi);
398}
399
400void
401ITB::writeTagAccess(ThreadContext *tc, Addr va, int context)
402{
403 TLB::writeTagAccess(tc, MISCREG_MMU_ITLB_TAG_ACCESS, va, context);
404}
405
406void
407DTB::writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct,
408 bool se, FaultTypes ft, int asi)
409{
410 DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n",
411 a, (int)write, ct, ft, asi);
412 TLB::writeSfsr(tc, MISCREG_MMU_DTLB_SFSR, write, ct, se, ft, asi);
413 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_SFAR, a);
414}
415
416void
417DTB::writeTagAccess(ThreadContext *tc, Addr va, int context)
418{
419 TLB::writeTagAccess(tc, MISCREG_MMU_DTLB_TAG_ACCESS, va, context);
420}
421
422
423
424Fault
425ITB::translate(RequestPtr &req, ThreadContext *tc)
426{
427 uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA);
428
429 Addr vaddr = req->getVaddr();
430 TlbEntry *e;
431
432 assert(req->getAsi() == ASI_IMPLICIT);
433
434 DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n",
435 vaddr, req->getSize());
436
437 // Be fast if we can!
438 if (cacheValid && cacheState == tlbdata) {
439 if (cacheEntry) {
440 if (cacheEntry->range.va < vaddr + sizeof(MachInst) &&
441 cacheEntry->range.va + cacheEntry->range.size >= vaddr) {
442 req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) |
443 vaddr & cacheEntry->pte.size()-1 );
444 return NoFault;
445 }
446 } else {
447 req->setPaddr(vaddr & PAddrImplMask);
448 return NoFault;
449 }
450 }
451
452 bool hpriv = bits(tlbdata,0,0);
453 bool red = bits(tlbdata,1,1);
454 bool priv = bits(tlbdata,2,2);
455 bool addr_mask = bits(tlbdata,3,3);
456 bool lsu_im = bits(tlbdata,4,4);
457
458 int part_id = bits(tlbdata,15,8);
459 int tl = bits(tlbdata,18,16);
460 int pri_context = bits(tlbdata,47,32);
461 int context;
462 ContextType ct;
463 int asi;
464 bool real = false;
465
466 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n",
467 priv, hpriv, red, lsu_im, part_id);
468
469 if (tl > 0) {
470 asi = ASI_N;
471 ct = Nucleus;
472 context = 0;
473 } else {
474 asi = ASI_P;
475 ct = Primary;
476 context = pri_context;
477 }
478
479 if ( hpriv || red ) {
480 cacheValid = true;
481 cacheState = tlbdata;
482 cacheEntry = NULL;
483 req->setPaddr(vaddr & PAddrImplMask);
484 return NoFault;
485 }
486
487 // If the access is unaligned trap
488 if (vaddr & 0x3) {
489 writeSfsr(tc, false, ct, false, OtherFault, asi);
490 return new MemAddressNotAligned;
491 }
492
493 if (addr_mask)
494 vaddr = vaddr & VAddrAMask;
495
496 if (!validVirtualAddress(vaddr, addr_mask)) {
497 writeSfsr(tc, false, ct, false, VaOutOfRange, asi);
498 return new InstructionAccessException;
499 }
500
501 if (!lsu_im) {
502 e = lookup(vaddr, part_id, true);
503 real = true;
504 context = 0;
505 } else {
506 e = lookup(vaddr, part_id, false, context);
507 }
508
509 if (e == NULL || !e->valid) {
510 tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS,
511 vaddr & ~BytesInPageMask | context);
512 if (real)
513 return new InstructionRealTranslationMiss;
514 else
515 return new FastInstructionAccessMMUMiss;
516 }
517
518 // were not priviledged accesing priv page
519 if (!priv && e->pte.priv()) {
520 writeSfsr(tc, false, ct, false, PrivViolation, asi);
521 return new InstructionAccessException;
522 }
523
524 // cache translation date for next translation
525 cacheValid = true;
526 cacheState = tlbdata;
527 cacheEntry = e;
528
529 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
530 vaddr & e->pte.size()-1 );
531 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
532 return NoFault;
533}
534
535
536
537Fault
538DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
539{
540 /* @todo this could really use some profiling and fixing to make it faster! */
541 uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA);
542 Addr vaddr = req->getVaddr();
543 Addr size = req->getSize();
544 ASI asi;
545 asi = (ASI)req->getAsi();
546 bool implicit = false;
547 bool hpriv = bits(tlbdata,0,0);
548
549 DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
550 vaddr, size, asi);
551
552 if (asi == ASI_IMPLICIT)
553 implicit = true;
554
555 if (hpriv && implicit) {
556 req->setPaddr(vaddr & PAddrImplMask);
557 return NoFault;
558 }
559
560 // Be fast if we can!
561 if (cacheValid && cacheState == tlbdata) {
562 if (cacheEntry[0] && cacheAsi[0] == asi && cacheEntry[0]->range.va < vaddr + size &&
563 cacheEntry[0]->range.va + cacheEntry[0]->range.size > vaddr) {
564 req->setPaddr(cacheEntry[0]->pte.paddr() & ~(cacheEntry[0]->pte.size()-1) |
565 vaddr & cacheEntry[0]->pte.size()-1 );
566 return NoFault;
567 }
568 if (cacheEntry[1] && cacheAsi[1] == asi && cacheEntry[1]->range.va < vaddr + size &&
569 cacheEntry[1]->range.va + cacheEntry[1]->range.size > vaddr) {
570 req->setPaddr(cacheEntry[1]->pte.paddr() & ~(cacheEntry[1]->pte.size()-1) |
571 vaddr & cacheEntry[1]->pte.size()-1 );
572 return NoFault;
573 }
574 }
575
576 bool red = bits(tlbdata,1,1);
577 bool priv = bits(tlbdata,2,2);
578 bool addr_mask = bits(tlbdata,3,3);
579 bool lsu_dm = bits(tlbdata,5,5);
580
581 int part_id = bits(tlbdata,15,8);
582 int tl = bits(tlbdata,18,16);
583 int pri_context = bits(tlbdata,47,32);
584 int sec_context = bits(tlbdata,47,32);
585
586 bool real = false;
587 ContextType ct = Primary;
588 int context = 0;
589
590 TlbEntry *e;
591
592 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
593 priv, hpriv, red, lsu_dm, part_id);
594
595 if (implicit) {
596 if (tl > 0) {
597 asi = ASI_N;
598 ct = Nucleus;
599 context = 0;
600 } else {
601 asi = ASI_P;
602 ct = Primary;
603 context = pri_context;
604 }
605 } else if (!hpriv && !red) {
606 if (tl > 0 || AsiIsNucleus(asi)) {
607 ct = Nucleus;
608 context = 0;
609 } else if (AsiIsSecondary(asi)) {
610 ct = Secondary;
611 context = sec_context;
612 } else {
613 context = pri_context;
614 ct = Primary; //???
615 }
616
617 // We need to check for priv level/asi priv
618 if (!priv && !AsiIsUnPriv(asi)) {
619 // It appears that context should be Nucleus in these cases?
620 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
621 return new PrivilegedAction;
622 }
623 if (priv && AsiIsHPriv(asi)) {
624 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
625 return new DataAccessException;
626 }
627
628 } else if (hpriv) {
628 } /*else if (hpriv) {*/
629 if (asi == ASI_P) {
630 ct = Primary;
631 context = pri_context;
632 goto continueDtbFlow;
633 }
629 if (asi == ASI_P) {
630 ct = Primary;
631 context = pri_context;
632 goto continueDtbFlow;
633 }
634 }
634 //}
635
636 if (!implicit) {
637 if (AsiIsLittle(asi))
638 panic("Little Endian ASIs not supported\n");
639 if (AsiIsBlock(asi))
640 panic("Block ASIs not supported\n");
641 if (AsiIsNoFault(asi))
642 panic("No Fault ASIs not supported\n");
643 if (write && asi == ASI_LDTX_P)
644 // block init store (like write hint64)
645 goto continueDtbFlow;
646 if (!write && asi == ASI_QUAD_LDD)
647 goto continueDtbFlow;
648
649 if (AsiIsTwin(asi))
650 panic("Twin ASIs not supported\n");
651 if (AsiIsPartialStore(asi))
652 panic("Partial Store ASIs not supported\n");
653 if (AsiIsInterrupt(asi))
654 panic("Interrupt ASIs not supported\n");
655
656 if (AsiIsMmu(asi))
657 goto handleMmuRegAccess;
658 if (AsiIsScratchPad(asi))
659 goto handleScratchRegAccess;
660 if (AsiIsQueue(asi))
661 goto handleQueueRegAccess;
662 if (AsiIsSparcError(asi))
663 goto handleSparcErrorRegAccess;
664
665 if (!AsiIsReal(asi) && !AsiIsNucleus(asi))
666 panic("Accessing ASI %#X. Should we?\n", asi);
667 }
668
669continueDtbFlow:
670 // If the asi is unaligned trap
671 if (vaddr & size-1) {
672 writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
673 return new MemAddressNotAligned;
674 }
675
676 if (addr_mask)
677 vaddr = vaddr & VAddrAMask;
678
679 if (!validVirtualAddress(vaddr, addr_mask)) {
680 writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi);
681 return new DataAccessException;
682 }
683
684
685 if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) {
686 real = true;
687 context = 0;
688 };
689
690 if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
691 req->setPaddr(vaddr & PAddrImplMask);
692 return NoFault;
693 }
694
695 e = lookup(vaddr, part_id, real, context);
696
697 if (e == NULL || !e->valid) {
698 tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
699 vaddr & ~BytesInPageMask | context);
700 DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
701 if (real)
702 return new DataRealTranslationMiss;
703 else
704 return new FastDataAccessMMUMiss;
705
706 }
707
708
709 if (write && !e->pte.writable()) {
710 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
711 return new FastDataAccessProtection;
712 }
713
714 if (e->pte.nofault() && !AsiIsNoFault(asi)) {
715 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
716 return new DataAccessException;
717 }
718
719 if (e->pte.sideffect())
720 req->setFlags(req->getFlags() | UNCACHEABLE);
721
722
723 if (!priv && e->pte.priv()) {
724 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
725 return new DataAccessException;
726 }
727
728 // cache translation date for next translation
729 cacheState = tlbdata;
730 if (!cacheValid) {
731 cacheEntry[1] = NULL;
732 cacheEntry[0] = NULL;
733 }
734
735 if (cacheEntry[0] != e && cacheEntry[1] != e) {
736 cacheEntry[1] = cacheEntry[0];
737 cacheEntry[0] = e;
738 cacheAsi[1] = cacheAsi[0];
739 cacheAsi[0] = asi;
740 if (implicit)
741 cacheAsi[0] = (ASI)0;
742 }
743 cacheValid = true;
744 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
745 vaddr & e->pte.size()-1);
746 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
747 return NoFault;
748 /** Normal flow ends here. */
749
750handleScratchRegAccess:
751 if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
752 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
753 return new DataAccessException;
754 }
755 goto regAccessOk;
756
757handleQueueRegAccess:
758 if (!priv && !hpriv) {
759 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
760 return new PrivilegedAction;
761 }
762 if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
763 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
764 return new DataAccessException;
765 }
766 goto regAccessOk;
767
768handleSparcErrorRegAccess:
769 if (!hpriv) {
770 if (priv) {
771 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
772 return new DataAccessException;
773 } else {
774 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
775 return new PrivilegedAction;
776 }
777 }
778 goto regAccessOk;
779
780
781regAccessOk:
782handleMmuRegAccess:
783 DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
784 req->setMmapedIpr(true);
785 req->setPaddr(req->getVaddr());
786 return NoFault;
787};
788
789Tick
790DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
791{
792 Addr va = pkt->getAddr();
793 ASI asi = (ASI)pkt->req->getAsi();
794 uint64_t temp, data;
795 uint64_t tsbtemp, cnftemp;
796
797 DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
798 (uint32_t)pkt->req->getAsi(), pkt->getAddr());
799
800 switch (asi) {
801 case ASI_LSU_CONTROL_REG:
802 assert(va == 0);
803 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_LSU_CTRL));
804 break;
805 case ASI_MMU:
806 switch (va) {
807 case 0x8:
808 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT));
809 break;
810 case 0x10:
811 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT));
812 break;
813 default:
814 goto doMmuReadError;
815 }
816 break;
817 case ASI_QUEUE:
818 pkt->set(tc->readMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
819 (va >> 4) - 0x3c));
820 break;
821 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
822 assert(va == 0);
823 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0));
824 break;
825 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
826 assert(va == 0);
827 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1));
828 break;
829 case ASI_DMMU_CTXT_ZERO_CONFIG:
830 assert(va == 0);
831 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG));
832 break;
833 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
834 assert(va == 0);
835 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0));
836 break;
837 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
838 assert(va == 0);
839 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1));
840 break;
841 case ASI_IMMU_CTXT_ZERO_CONFIG:
842 assert(va == 0);
843 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG));
844 break;
845 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
846 assert(va == 0);
847 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0));
848 break;
849 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
850 assert(va == 0);
851 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1));
852 break;
853 case ASI_DMMU_CTXT_NONZERO_CONFIG:
854 assert(va == 0);
855 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG));
856 break;
857 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
858 assert(va == 0);
859 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0));
860 break;
861 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
862 assert(va == 0);
863 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1));
864 break;
865 case ASI_IMMU_CTXT_NONZERO_CONFIG:
866 assert(va == 0);
867 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG));
868 break;
869 case ASI_SPARC_ERROR_STATUS_REG:
870 warn("returning 0 for SPARC ERROR regsiter read\n");
871 pkt->set(0);
872 break;
873 case ASI_HYP_SCRATCHPAD:
874 case ASI_SCRATCHPAD:
875 pkt->set(tc->readMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
876 break;
877 case ASI_IMMU:
878 switch (va) {
879 case 0x0:
880 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
881 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
882 break;
883 case 0x30:
884 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS));
885 break;
886 default:
887 goto doMmuReadError;
888 }
889 break;
890 case ASI_DMMU:
891 switch (va) {
892 case 0x0:
893 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
894 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
895 break;
896 case 0x30:
897 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS));
898 break;
899 case 0x80:
900 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID));
901 break;
902 default:
903 goto doMmuReadError;
904 }
905 break;
906 case ASI_DMMU_TSB_PS0_PTR_REG:
907 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
908 if (bits(temp,12,0) == 0) {
909 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0);
910 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
911 } else {
912 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0);
913 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
914 }
915 data = mbits(tsbtemp,63,13);
916 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
917 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
918 pkt->set(data);
919 break;
920 case ASI_DMMU_TSB_PS1_PTR_REG:
921 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
922 if (bits(temp,12,0) == 0) {
923 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1);
924 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
925 } else {
926 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1);
927 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
928 }
929 data = mbits(tsbtemp,63,13);
930 if (bits(tsbtemp,12,12))
931 data |= ULL(1) << (13+bits(tsbtemp,3,0));
932 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
933 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
934 pkt->set(data);
935 break;
635
636 if (!implicit) {
637 if (AsiIsLittle(asi))
638 panic("Little Endian ASIs not supported\n");
639 if (AsiIsBlock(asi))
640 panic("Block ASIs not supported\n");
641 if (AsiIsNoFault(asi))
642 panic("No Fault ASIs not supported\n");
643 if (write && asi == ASI_LDTX_P)
644 // block init store (like write hint64)
645 goto continueDtbFlow;
646 if (!write && asi == ASI_QUAD_LDD)
647 goto continueDtbFlow;
648
649 if (AsiIsTwin(asi))
650 panic("Twin ASIs not supported\n");
651 if (AsiIsPartialStore(asi))
652 panic("Partial Store ASIs not supported\n");
653 if (AsiIsInterrupt(asi))
654 panic("Interrupt ASIs not supported\n");
655
656 if (AsiIsMmu(asi))
657 goto handleMmuRegAccess;
658 if (AsiIsScratchPad(asi))
659 goto handleScratchRegAccess;
660 if (AsiIsQueue(asi))
661 goto handleQueueRegAccess;
662 if (AsiIsSparcError(asi))
663 goto handleSparcErrorRegAccess;
664
665 if (!AsiIsReal(asi) && !AsiIsNucleus(asi))
666 panic("Accessing ASI %#X. Should we?\n", asi);
667 }
668
669continueDtbFlow:
670 // If the asi is unaligned trap
671 if (vaddr & size-1) {
672 writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
673 return new MemAddressNotAligned;
674 }
675
676 if (addr_mask)
677 vaddr = vaddr & VAddrAMask;
678
679 if (!validVirtualAddress(vaddr, addr_mask)) {
680 writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi);
681 return new DataAccessException;
682 }
683
684
685 if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) {
686 real = true;
687 context = 0;
688 };
689
690 if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
691 req->setPaddr(vaddr & PAddrImplMask);
692 return NoFault;
693 }
694
695 e = lookup(vaddr, part_id, real, context);
696
697 if (e == NULL || !e->valid) {
698 tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
699 vaddr & ~BytesInPageMask | context);
700 DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
701 if (real)
702 return new DataRealTranslationMiss;
703 else
704 return new FastDataAccessMMUMiss;
705
706 }
707
708
709 if (write && !e->pte.writable()) {
710 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
711 return new FastDataAccessProtection;
712 }
713
714 if (e->pte.nofault() && !AsiIsNoFault(asi)) {
715 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
716 return new DataAccessException;
717 }
718
719 if (e->pte.sideffect())
720 req->setFlags(req->getFlags() | UNCACHEABLE);
721
722
723 if (!priv && e->pte.priv()) {
724 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
725 return new DataAccessException;
726 }
727
728 // cache translation date for next translation
729 cacheState = tlbdata;
730 if (!cacheValid) {
731 cacheEntry[1] = NULL;
732 cacheEntry[0] = NULL;
733 }
734
735 if (cacheEntry[0] != e && cacheEntry[1] != e) {
736 cacheEntry[1] = cacheEntry[0];
737 cacheEntry[0] = e;
738 cacheAsi[1] = cacheAsi[0];
739 cacheAsi[0] = asi;
740 if (implicit)
741 cacheAsi[0] = (ASI)0;
742 }
743 cacheValid = true;
744 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
745 vaddr & e->pte.size()-1);
746 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
747 return NoFault;
748 /** Normal flow ends here. */
749
750handleScratchRegAccess:
751 if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
752 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
753 return new DataAccessException;
754 }
755 goto regAccessOk;
756
757handleQueueRegAccess:
758 if (!priv && !hpriv) {
759 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
760 return new PrivilegedAction;
761 }
762 if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
763 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
764 return new DataAccessException;
765 }
766 goto regAccessOk;
767
768handleSparcErrorRegAccess:
769 if (!hpriv) {
770 if (priv) {
771 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
772 return new DataAccessException;
773 } else {
774 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
775 return new PrivilegedAction;
776 }
777 }
778 goto regAccessOk;
779
780
781regAccessOk:
782handleMmuRegAccess:
783 DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
784 req->setMmapedIpr(true);
785 req->setPaddr(req->getVaddr());
786 return NoFault;
787};
788
789Tick
790DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
791{
792 Addr va = pkt->getAddr();
793 ASI asi = (ASI)pkt->req->getAsi();
794 uint64_t temp, data;
795 uint64_t tsbtemp, cnftemp;
796
797 DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
798 (uint32_t)pkt->req->getAsi(), pkt->getAddr());
799
800 switch (asi) {
801 case ASI_LSU_CONTROL_REG:
802 assert(va == 0);
803 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_LSU_CTRL));
804 break;
805 case ASI_MMU:
806 switch (va) {
807 case 0x8:
808 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT));
809 break;
810 case 0x10:
811 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT));
812 break;
813 default:
814 goto doMmuReadError;
815 }
816 break;
817 case ASI_QUEUE:
818 pkt->set(tc->readMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
819 (va >> 4) - 0x3c));
820 break;
821 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
822 assert(va == 0);
823 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0));
824 break;
825 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
826 assert(va == 0);
827 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1));
828 break;
829 case ASI_DMMU_CTXT_ZERO_CONFIG:
830 assert(va == 0);
831 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG));
832 break;
833 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
834 assert(va == 0);
835 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0));
836 break;
837 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
838 assert(va == 0);
839 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1));
840 break;
841 case ASI_IMMU_CTXT_ZERO_CONFIG:
842 assert(va == 0);
843 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG));
844 break;
845 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
846 assert(va == 0);
847 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0));
848 break;
849 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
850 assert(va == 0);
851 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1));
852 break;
853 case ASI_DMMU_CTXT_NONZERO_CONFIG:
854 assert(va == 0);
855 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG));
856 break;
857 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
858 assert(va == 0);
859 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0));
860 break;
861 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
862 assert(va == 0);
863 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1));
864 break;
865 case ASI_IMMU_CTXT_NONZERO_CONFIG:
866 assert(va == 0);
867 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG));
868 break;
869 case ASI_SPARC_ERROR_STATUS_REG:
870 warn("returning 0 for SPARC ERROR regsiter read\n");
871 pkt->set(0);
872 break;
873 case ASI_HYP_SCRATCHPAD:
874 case ASI_SCRATCHPAD:
875 pkt->set(tc->readMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
876 break;
877 case ASI_IMMU:
878 switch (va) {
879 case 0x0:
880 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
881 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
882 break;
883 case 0x30:
884 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS));
885 break;
886 default:
887 goto doMmuReadError;
888 }
889 break;
890 case ASI_DMMU:
891 switch (va) {
892 case 0x0:
893 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
894 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
895 break;
896 case 0x30:
897 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS));
898 break;
899 case 0x80:
900 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID));
901 break;
902 default:
903 goto doMmuReadError;
904 }
905 break;
906 case ASI_DMMU_TSB_PS0_PTR_REG:
907 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
908 if (bits(temp,12,0) == 0) {
909 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0);
910 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
911 } else {
912 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0);
913 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
914 }
915 data = mbits(tsbtemp,63,13);
916 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
917 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
918 pkt->set(data);
919 break;
920 case ASI_DMMU_TSB_PS1_PTR_REG:
921 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
922 if (bits(temp,12,0) == 0) {
923 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1);
924 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
925 } else {
926 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1);
927 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
928 }
929 data = mbits(tsbtemp,63,13);
930 if (bits(tsbtemp,12,12))
931 data |= ULL(1) << (13+bits(tsbtemp,3,0));
932 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
933 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
934 pkt->set(data);
935 break;
936 case ASI_IMMU_TSB_PS0_PTR_REG:
937 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
938 if (bits(temp,12,0) == 0) {
939 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0);
940 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG);
941 } else {
942 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0);
943 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG);
944 }
945 data = mbits(tsbtemp,63,13);
946 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
947 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
948 pkt->set(data);
949 break;
950 case ASI_IMMU_TSB_PS1_PTR_REG:
951 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
952 if (bits(temp,12,0) == 0) {
953 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1);
954 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG);
955 } else {
956 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1);
957 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG);
958 }
959 data = mbits(tsbtemp,63,13);
960 if (bits(tsbtemp,12,12))
961 data |= ULL(1) << (13+bits(tsbtemp,3,0));
962 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
963 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
964 pkt->set(data);
965 break;
936
937 default:
938doMmuReadError:
939 panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
940 (uint32_t)asi, va);
941 }
942 pkt->result = Packet::Success;
943 return tc->getCpuPtr()->cycles(1);
944}
945
946Tick
947DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
948{
949 uint64_t data = gtoh(pkt->get<uint64_t>());
950 Addr va = pkt->getAddr();
951 ASI asi = (ASI)pkt->req->getAsi();
952
953 Addr ta_insert;
954 Addr va_insert;
955 Addr ct_insert;
956 int part_insert;
957 int entry_insert = -1;
958 bool real_insert;
959 bool ignore;
960 int part_id;
961 int ctx_id;
962 PageTableEntry pte;
963
964 DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
965 (uint32_t)asi, va, data);
966
967 switch (asi) {
968 case ASI_LSU_CONTROL_REG:
969 assert(va == 0);
970 tc->setMiscRegWithEffect(MISCREG_MMU_LSU_CTRL, data);
971 break;
972 case ASI_MMU:
973 switch (va) {
974 case 0x8:
975 tc->setMiscRegWithEffect(MISCREG_MMU_P_CONTEXT, data);
976 break;
977 case 0x10:
978 tc->setMiscRegWithEffect(MISCREG_MMU_S_CONTEXT, data);
979 break;
980 default:
981 goto doMmuWriteError;
982 }
983 break;
984 case ASI_QUEUE:
985 assert(mbits(data,13,6) == data);
986 tc->setMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
987 (va >> 4) - 0x3c, data);
988 break;
989 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
990 assert(va == 0);
991 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0, data);
992 break;
993 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
994 assert(va == 0);
995 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1, data);
996 break;
997 case ASI_DMMU_CTXT_ZERO_CONFIG:
998 assert(va == 0);
999 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG, data);
1000 break;
1001 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1002 assert(va == 0);
1003 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0, data);
1004 break;
1005 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1006 assert(va == 0);
1007 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1, data);
1008 break;
1009 case ASI_IMMU_CTXT_ZERO_CONFIG:
1010 assert(va == 0);
1011 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG, data);
1012 break;
1013 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1014 assert(va == 0);
1015 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0, data);
1016 break;
1017 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1018 assert(va == 0);
1019 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1, data);
1020 break;
1021 case ASI_DMMU_CTXT_NONZERO_CONFIG:
1022 assert(va == 0);
1023 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG, data);
1024 break;
1025 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1026 assert(va == 0);
1027 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0, data);
1028 break;
1029 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1030 assert(va == 0);
1031 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1, data);
1032 break;
1033 case ASI_IMMU_CTXT_NONZERO_CONFIG:
1034 assert(va == 0);
1035 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG, data);
1036 break;
1037 case ASI_SPARC_ERROR_EN_REG:
1038 case ASI_SPARC_ERROR_STATUS_REG:
1039 warn("Ignoring write to SPARC ERROR regsiter\n");
1040 break;
1041 case ASI_HYP_SCRATCHPAD:
1042 case ASI_SCRATCHPAD:
1043 tc->setMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1044 break;
1045 case ASI_IMMU:
1046 switch (va) {
1047 case 0x30:
1048 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data);
1049 break;
1050 default:
1051 goto doMmuWriteError;
1052 }
1053 break;
1054 case ASI_ITLB_DATA_ACCESS_REG:
1055 entry_insert = bits(va, 8,3);
1056 case ASI_ITLB_DATA_IN_REG:
1057 assert(entry_insert != -1 || mbits(va,10,9) == va);
1058 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
1059 va_insert = mbits(ta_insert, 63,13);
1060 ct_insert = mbits(ta_insert, 12,0);
1061 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1062 real_insert = bits(va, 9,9);
1063 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1064 PageTableEntry::sun4u);
1065 tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1066 pte, entry_insert);
1067 break;
1068 case ASI_DTLB_DATA_ACCESS_REG:
1069 entry_insert = bits(va, 8,3);
1070 case ASI_DTLB_DATA_IN_REG:
1071 assert(entry_insert != -1 || mbits(va,10,9) == va);
1072 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
1073 va_insert = mbits(ta_insert, 63,13);
1074 ct_insert = mbits(ta_insert, 12,0);
1075 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1076 real_insert = bits(va, 9,9);
1077 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1078 PageTableEntry::sun4u);
1079 insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
1080 break;
1081 case ASI_IMMU_DEMAP:
1082 ignore = false;
1083 ctx_id = -1;
1084 part_id = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1085 switch (bits(va,5,4)) {
1086 case 0:
1087 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
1088 break;
1089 case 1:
1090 ignore = true;
1091 break;
1092 case 3:
1093 ctx_id = 0;
1094 break;
1095 default:
1096 ignore = true;
1097 }
1098
1099 switch(bits(va,7,6)) {
1100 case 0: // demap page
1101 if (!ignore)
1102 tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1103 bits(va,9,9), ctx_id);
1104 break;
1105 case 1: //demap context
1106 if (!ignore)
1107 tc->getITBPtr()->demapContext(part_id, ctx_id);
1108 break;
1109 case 2:
1110 tc->getITBPtr()->demapAll(part_id);
1111 break;
1112 default:
1113 panic("Invalid type for IMMU demap\n");
1114 }
1115 break;
1116 case ASI_DMMU:
1117 switch (va) {
1118 case 0x30:
1119 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data);
1120 break;
1121 case 0x80:
1122 tc->setMiscRegWithEffect(MISCREG_MMU_PART_ID, data);
1123 break;
1124 default:
1125 goto doMmuWriteError;
1126 }
1127 break;
1128 case ASI_DMMU_DEMAP:
1129 ignore = false;
1130 ctx_id = -1;
1131 part_id = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1132 switch (bits(va,5,4)) {
1133 case 0:
1134 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
1135 break;
1136 case 1:
1137 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT);
1138 break;
1139 case 3:
1140 ctx_id = 0;
1141 break;
1142 default:
1143 ignore = true;
1144 }
1145
1146 switch(bits(va,7,6)) {
1147 case 0: // demap page
1148 if (!ignore)
1149 demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1150 break;
1151 case 1: //demap context
1152 if (!ignore)
1153 demapContext(part_id, ctx_id);
1154 break;
1155 case 2:
1156 demapAll(part_id);
1157 break;
1158 default:
1159 panic("Invalid type for IMMU demap\n");
1160 }
1161 break;
1162 default:
1163doMmuWriteError:
1164 panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1165 (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1166 }
1167 pkt->result = Packet::Success;
1168 return tc->getCpuPtr()->cycles(1);
1169}
1170
1171void
1172TLB::serialize(std::ostream &os)
1173{
1174 panic("Need to implement serialize tlb for SPARC\n");
1175}
1176
1177void
1178TLB::unserialize(Checkpoint *cp, const std::string &section)
1179{
1180 panic("Need to implement unserialize tlb for SPARC\n");
1181}
1182
1183
1184DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
1185
1186BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
1187
1188 Param<int> size;
1189
1190END_DECLARE_SIM_OBJECT_PARAMS(ITB)
1191
1192BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
1193
1194 INIT_PARAM_DFLT(size, "TLB size", 48)
1195
1196END_INIT_SIM_OBJECT_PARAMS(ITB)
1197
1198
1199CREATE_SIM_OBJECT(ITB)
1200{
1201 return new ITB(getInstanceName(), size);
1202}
1203
1204REGISTER_SIM_OBJECT("SparcITB", ITB)
1205
1206BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
1207
1208 Param<int> size;
1209
1210END_DECLARE_SIM_OBJECT_PARAMS(DTB)
1211
1212BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
1213
1214 INIT_PARAM_DFLT(size, "TLB size", 64)
1215
1216END_INIT_SIM_OBJECT_PARAMS(DTB)
1217
1218
1219CREATE_SIM_OBJECT(DTB)
1220{
1221 return new DTB(getInstanceName(), size);
1222}
1223
1224REGISTER_SIM_OBJECT("SparcDTB", DTB)
1225}
966
967 default:
968doMmuReadError:
969 panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
970 (uint32_t)asi, va);
971 }
972 pkt->result = Packet::Success;
973 return tc->getCpuPtr()->cycles(1);
974}
975
976Tick
977DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
978{
979 uint64_t data = gtoh(pkt->get<uint64_t>());
980 Addr va = pkt->getAddr();
981 ASI asi = (ASI)pkt->req->getAsi();
982
983 Addr ta_insert;
984 Addr va_insert;
985 Addr ct_insert;
986 int part_insert;
987 int entry_insert = -1;
988 bool real_insert;
989 bool ignore;
990 int part_id;
991 int ctx_id;
992 PageTableEntry pte;
993
994 DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
995 (uint32_t)asi, va, data);
996
997 switch (asi) {
998 case ASI_LSU_CONTROL_REG:
999 assert(va == 0);
1000 tc->setMiscRegWithEffect(MISCREG_MMU_LSU_CTRL, data);
1001 break;
1002 case ASI_MMU:
1003 switch (va) {
1004 case 0x8:
1005 tc->setMiscRegWithEffect(MISCREG_MMU_P_CONTEXT, data);
1006 break;
1007 case 0x10:
1008 tc->setMiscRegWithEffect(MISCREG_MMU_S_CONTEXT, data);
1009 break;
1010 default:
1011 goto doMmuWriteError;
1012 }
1013 break;
1014 case ASI_QUEUE:
1015 assert(mbits(data,13,6) == data);
1016 tc->setMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
1017 (va >> 4) - 0x3c, data);
1018 break;
1019 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
1020 assert(va == 0);
1021 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0, data);
1022 break;
1023 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
1024 assert(va == 0);
1025 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1, data);
1026 break;
1027 case ASI_DMMU_CTXT_ZERO_CONFIG:
1028 assert(va == 0);
1029 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG, data);
1030 break;
1031 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1032 assert(va == 0);
1033 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0, data);
1034 break;
1035 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1036 assert(va == 0);
1037 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1, data);
1038 break;
1039 case ASI_IMMU_CTXT_ZERO_CONFIG:
1040 assert(va == 0);
1041 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG, data);
1042 break;
1043 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1044 assert(va == 0);
1045 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0, data);
1046 break;
1047 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1048 assert(va == 0);
1049 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1, data);
1050 break;
1051 case ASI_DMMU_CTXT_NONZERO_CONFIG:
1052 assert(va == 0);
1053 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG, data);
1054 break;
1055 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1056 assert(va == 0);
1057 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0, data);
1058 break;
1059 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1060 assert(va == 0);
1061 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1, data);
1062 break;
1063 case ASI_IMMU_CTXT_NONZERO_CONFIG:
1064 assert(va == 0);
1065 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG, data);
1066 break;
1067 case ASI_SPARC_ERROR_EN_REG:
1068 case ASI_SPARC_ERROR_STATUS_REG:
1069 warn("Ignoring write to SPARC ERROR regsiter\n");
1070 break;
1071 case ASI_HYP_SCRATCHPAD:
1072 case ASI_SCRATCHPAD:
1073 tc->setMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1074 break;
1075 case ASI_IMMU:
1076 switch (va) {
1077 case 0x30:
1078 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data);
1079 break;
1080 default:
1081 goto doMmuWriteError;
1082 }
1083 break;
1084 case ASI_ITLB_DATA_ACCESS_REG:
1085 entry_insert = bits(va, 8,3);
1086 case ASI_ITLB_DATA_IN_REG:
1087 assert(entry_insert != -1 || mbits(va,10,9) == va);
1088 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
1089 va_insert = mbits(ta_insert, 63,13);
1090 ct_insert = mbits(ta_insert, 12,0);
1091 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1092 real_insert = bits(va, 9,9);
1093 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1094 PageTableEntry::sun4u);
1095 tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1096 pte, entry_insert);
1097 break;
1098 case ASI_DTLB_DATA_ACCESS_REG:
1099 entry_insert = bits(va, 8,3);
1100 case ASI_DTLB_DATA_IN_REG:
1101 assert(entry_insert != -1 || mbits(va,10,9) == va);
1102 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
1103 va_insert = mbits(ta_insert, 63,13);
1104 ct_insert = mbits(ta_insert, 12,0);
1105 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1106 real_insert = bits(va, 9,9);
1107 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1108 PageTableEntry::sun4u);
1109 insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
1110 break;
1111 case ASI_IMMU_DEMAP:
1112 ignore = false;
1113 ctx_id = -1;
1114 part_id = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1115 switch (bits(va,5,4)) {
1116 case 0:
1117 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
1118 break;
1119 case 1:
1120 ignore = true;
1121 break;
1122 case 3:
1123 ctx_id = 0;
1124 break;
1125 default:
1126 ignore = true;
1127 }
1128
1129 switch(bits(va,7,6)) {
1130 case 0: // demap page
1131 if (!ignore)
1132 tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1133 bits(va,9,9), ctx_id);
1134 break;
1135 case 1: //demap context
1136 if (!ignore)
1137 tc->getITBPtr()->demapContext(part_id, ctx_id);
1138 break;
1139 case 2:
1140 tc->getITBPtr()->demapAll(part_id);
1141 break;
1142 default:
1143 panic("Invalid type for IMMU demap\n");
1144 }
1145 break;
1146 case ASI_DMMU:
1147 switch (va) {
1148 case 0x30:
1149 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data);
1150 break;
1151 case 0x80:
1152 tc->setMiscRegWithEffect(MISCREG_MMU_PART_ID, data);
1153 break;
1154 default:
1155 goto doMmuWriteError;
1156 }
1157 break;
1158 case ASI_DMMU_DEMAP:
1159 ignore = false;
1160 ctx_id = -1;
1161 part_id = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1162 switch (bits(va,5,4)) {
1163 case 0:
1164 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
1165 break;
1166 case 1:
1167 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT);
1168 break;
1169 case 3:
1170 ctx_id = 0;
1171 break;
1172 default:
1173 ignore = true;
1174 }
1175
1176 switch(bits(va,7,6)) {
1177 case 0: // demap page
1178 if (!ignore)
1179 demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1180 break;
1181 case 1: //demap context
1182 if (!ignore)
1183 demapContext(part_id, ctx_id);
1184 break;
1185 case 2:
1186 demapAll(part_id);
1187 break;
1188 default:
1189 panic("Invalid type for IMMU demap\n");
1190 }
1191 break;
1192 default:
1193doMmuWriteError:
1194 panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1195 (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1196 }
1197 pkt->result = Packet::Success;
1198 return tc->getCpuPtr()->cycles(1);
1199}
1200
1201void
1202TLB::serialize(std::ostream &os)
1203{
1204 panic("Need to implement serialize tlb for SPARC\n");
1205}
1206
1207void
1208TLB::unserialize(Checkpoint *cp, const std::string &section)
1209{
1210 panic("Need to implement unserialize tlb for SPARC\n");
1211}
1212
1213
1214DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
1215
1216BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
1217
1218 Param<int> size;
1219
1220END_DECLARE_SIM_OBJECT_PARAMS(ITB)
1221
1222BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
1223
1224 INIT_PARAM_DFLT(size, "TLB size", 48)
1225
1226END_INIT_SIM_OBJECT_PARAMS(ITB)
1227
1228
1229CREATE_SIM_OBJECT(ITB)
1230{
1231 return new ITB(getInstanceName(), size);
1232}
1233
1234REGISTER_SIM_OBJECT("SparcITB", ITB)
1235
1236BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
1237
1238 Param<int> size;
1239
1240END_DECLARE_SIM_OBJECT_PARAMS(DTB)
1241
1242BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
1243
1244 INIT_PARAM_DFLT(size, "TLB size", 64)
1245
1246END_INIT_SIM_OBJECT_PARAMS(DTB)
1247
1248
1249CREATE_SIM_OBJECT(DTB)
1250{
1251 return new DTB(getInstanceName(), size);
1252}
1253
1254REGISTER_SIM_OBJECT("SparcDTB", DTB)
1255}