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