Merge zizzer.eecs.umich.edu:/bk/linux
[gem5.git] / arch / alpha / alpha_memory.cc
1 /*
2 * Copyright (c) 2003 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
29 #include <sstream>
30 #include <string>
31 #include <vector>
32
33 #include "base/inifile.hh"
34 #include "base/str.hh"
35 #include "base/trace.hh"
36 #include "cpu/exec_context.hh"
37 #include "sim/builder.hh"
38 #include "targetarch/alpha_memory.hh"
39 #include "targetarch/ev5.hh"
40
41 using namespace std;
42
43 ///////////////////////////////////////////////////////////////////////
44 //
45 // Alpha TLB
46 //
47 #ifdef DEBUG
48 bool uncacheBit39 = false;
49 bool uncacheBit40 = false;
50 #endif
51
52 AlphaTLB::AlphaTLB(const string &name, int s)
53 : SimObject(name), size(s), nlu(0)
54 {
55 table = new AlphaISA::PTE[size];
56 memset(table, 0, sizeof(AlphaISA::PTE[size]));
57 }
58
59 AlphaTLB::~AlphaTLB()
60 {
61 if (table)
62 delete [] table;
63 }
64
65 // look up an entry in the TLB
66 AlphaISA::PTE *
67 AlphaTLB::lookup(Addr vpn, uint8_t asn) const
68 {
69 DPRINTF(TLB, "lookup %#x\n", vpn);
70
71 PageTable::const_iterator i = lookupTable.find(vpn);
72 if (i == lookupTable.end())
73 return NULL;
74
75 while (i->first == vpn) {
76 int index = i->second;
77 AlphaISA::PTE *pte = &table[index];
78 assert(pte->valid);
79 if (vpn == pte->tag && (pte->asma || pte->asn == asn))
80 return pte;
81
82 ++i;
83 }
84
85 // not found...
86 return NULL;
87 }
88
89
90 void
91 AlphaTLB::checkCacheability(MemReqPtr &req)
92 {
93 // in Alpha, cacheability is controlled by upper-level bits of the
94 // physical address
95
96 /*
97 * We support having the uncacheable bit in either bit 39 or bit 40.
98 * The Turbolaser platform (and EV5) support having the bit in 39, but
99 * Tsunami (which Linux assumes uses an EV6) generates accesses with
100 * the bit in 40. So we must check for both, but we have debug flags
101 * to catch a weird case where both are used, which shouldn't happen.
102 */
103
104 if (req->paddr & PA_UNCACHED_BIT_40 ||
105 req->paddr & PA_UNCACHED_BIT_39) {
106
107 #ifdef DEBUG
108 if (req->paddr & PA_UNCACHED_BIT_40) {
109 if(uncacheBit39)
110 panic("Bit 40 access follows bit 39 access, PA=%x\n",
111 req->paddr);
112
113 uncacheBit40 = true;
114 } else if (req->paddr & PA_UNCACHED_BIT_39) {
115 if(uncacheBit40)
116 panic("Bit 39 acceess follows bit 40 access, PA=%x\n",
117 req->paddr);
118
119 uncacheBit39 = true;
120 }
121 #endif
122
123 // IPR memory space not implemented
124 if (PA_IPR_SPACE(req->paddr))
125 if (!req->xc->misspeculating())
126 panic("IPR memory space not implemented! PA=%x\n",
127 req->paddr);
128
129 // mark request as uncacheable
130 req->flags |= UNCACHEABLE;
131 }
132 }
133
134
135 // insert a new TLB entry
136 void
137 AlphaTLB::insert(Addr vaddr, AlphaISA::PTE &pte)
138 {
139 if (table[nlu].valid) {
140 Addr oldvpn = table[nlu].tag;
141 PageTable::iterator i = lookupTable.find(oldvpn);
142
143 if (i == lookupTable.end())
144 panic("TLB entry not found in lookupTable");
145
146 int index;
147 while ((index = i->second) != nlu) {
148 if (table[index].tag != oldvpn)
149 panic("TLB entry not found in lookupTable");
150
151 ++i;
152 }
153
154 DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn);
155
156 lookupTable.erase(i);
157 }
158
159 Addr vpn = VA_VPN(vaddr);
160 DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vpn, pte.ppn);
161
162 table[nlu] = pte;
163 table[nlu].tag = vpn;
164 table[nlu].valid = true;
165
166 lookupTable.insert(make_pair(vpn, nlu));
167 nextnlu();
168 }
169
170 void
171 AlphaTLB::flushAll()
172 {
173 memset(table, 0, sizeof(AlphaISA::PTE[size]));
174 lookupTable.clear();
175 nlu = 0;
176 }
177
178 void
179 AlphaTLB::flushProcesses()
180 {
181 PageTable::iterator i = lookupTable.begin();
182 PageTable::iterator end = lookupTable.end();
183 while (i != end) {
184 int index = i->second;
185 AlphaISA::PTE *pte = &table[index];
186 assert(pte->valid);
187
188 if (!pte->asma) {
189 DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn);
190 pte->valid = false;
191 lookupTable.erase(i);
192 }
193
194 ++i;
195 }
196 }
197
198 void
199 AlphaTLB::flushAddr(Addr vaddr, uint8_t asn)
200 {
201 Addr vpn = VA_VPN(vaddr);
202
203 PageTable::iterator i = lookupTable.find(vpn);
204 if (i == lookupTable.end())
205 return;
206
207 while (i->first == vpn) {
208 int index = i->second;
209 AlphaISA::PTE *pte = &table[index];
210 assert(pte->valid);
211
212 if (vpn == pte->tag && (pte->asma || pte->asn == asn)) {
213 DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vpn, pte->ppn);
214
215 // invalidate this entry
216 pte->valid = false;
217
218 lookupTable.erase(i);
219 }
220
221 ++i;
222 }
223 }
224
225
226 void
227 AlphaTLB::serialize(ostream &os)
228 {
229 SERIALIZE_SCALAR(size);
230 SERIALIZE_SCALAR(nlu);
231
232 for (int i = 0; i < size; i++) {
233 nameOut(os, csprintf("%s.PTE%d", name(), i));
234 table[i].serialize(os);
235 }
236 }
237
238 void
239 AlphaTLB::unserialize(Checkpoint *cp, const string &section)
240 {
241 UNSERIALIZE_SCALAR(size);
242 UNSERIALIZE_SCALAR(nlu);
243
244 for (int i = 0; i < size; i++) {
245 table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
246 if (table[i].valid) {
247 lookupTable.insert(make_pair(table[i].tag, i));
248 }
249 }
250 }
251
252
253 ///////////////////////////////////////////////////////////////////////
254 //
255 // Alpha ITB
256 //
257 AlphaITB::AlphaITB(const std::string &name, int size)
258 : AlphaTLB(name, size)
259 {}
260
261
262 void
263 AlphaITB::regStats()
264 {
265 hits
266 .name(name() + ".hits")
267 .desc("ITB hits");
268 misses
269 .name(name() + ".misses")
270 .desc("ITB misses");
271 acv
272 .name(name() + ".acv")
273 .desc("ITB acv");
274 accesses
275 .name(name() + ".accesses")
276 .desc("ITB accesses");
277
278 accesses = hits + misses;
279 }
280
281 void
282 AlphaITB::fault(Addr pc, ExecContext *xc) const
283 {
284 uint64_t *ipr = xc->regs.ipr;
285
286 if (!xc->misspeculating()) {
287 ipr[AlphaISA::IPR_ITB_TAG] = pc;
288 ipr[AlphaISA::IPR_IFAULT_VA_FORM] =
289 ipr[AlphaISA::IPR_IVPTBR] | (VA_VPN(pc) << 3);
290 }
291 }
292
293
294 Fault
295 AlphaITB::translate(MemReqPtr &req) const
296 {
297 InternalProcReg *ipr = req->xc->regs.ipr;
298
299 if (PC_PAL(req->vaddr)) {
300 // strip off PAL PC marker (lsb is 1)
301 req->paddr = (req->vaddr & ~3) & PA_IMPL_MASK;
302 hits++;
303 return No_Fault;
304 }
305
306 if (req->flags & PHYSICAL) {
307 req->paddr = req->vaddr;
308 } else {
309 // verify that this is a good virtual address
310 if (!validVirtualAddress(req->vaddr)) {
311 fault(req->vaddr, req->xc);
312 acv++;
313 return ITB_Acv_Fault;
314 }
315
316 // Check for "superpage" mapping: when SP<1> is set, and
317 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
318 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
319 VA_SPACE(req->vaddr) == 2) {
320
321 // only valid in kernel mode
322 if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) {
323 fault(req->vaddr, req->xc);
324 acv++;
325 return ITB_Acv_Fault;
326 }
327
328 req->paddr = req->vaddr & PA_IMPL_MASK;
329
330 // sign extend the physical address properly
331 if (req->paddr & PA_UNCACHED_BIT_39 ||
332 req->paddr & PA_UNCACHED_BIT_40)
333 req->paddr |= 0xf0000000000ULL;
334 else
335 req->paddr &= 0xffffffffffULL;
336
337 } else {
338 // not a physical address: need to look up pte
339 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
340 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
341
342 if (!pte) {
343 fault(req->vaddr, req->xc);
344 misses++;
345 return ITB_Fault_Fault;
346 }
347
348 req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3);
349
350 // check permissions for this access
351 if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) {
352 // instruction access fault
353 fault(req->vaddr, req->xc);
354 acv++;
355 return ITB_Acv_Fault;
356 }
357
358 hits++;
359 }
360 }
361
362 // check that the physical address is ok (catch bad physical addresses)
363 if (req->paddr & ~PA_IMPL_MASK)
364 return Machine_Check_Fault;
365
366 checkCacheability(req);
367
368 return No_Fault;
369 }
370
371 ///////////////////////////////////////////////////////////////////////
372 //
373 // Alpha DTB
374 //
375 AlphaDTB::AlphaDTB(const std::string &name, int size)
376 : AlphaTLB(name, size)
377 {}
378
379 void
380 AlphaDTB::regStats()
381 {
382 read_hits
383 .name(name() + ".read_hits")
384 .desc("DTB read hits")
385 ;
386
387 read_misses
388 .name(name() + ".read_misses")
389 .desc("DTB read misses")
390 ;
391
392 read_acv
393 .name(name() + ".read_acv")
394 .desc("DTB read access violations")
395 ;
396
397 read_accesses
398 .name(name() + ".read_accesses")
399 .desc("DTB read accesses")
400 ;
401
402 write_hits
403 .name(name() + ".write_hits")
404 .desc("DTB write hits")
405 ;
406
407 write_misses
408 .name(name() + ".write_misses")
409 .desc("DTB write misses")
410 ;
411
412 write_acv
413 .name(name() + ".write_acv")
414 .desc("DTB write access violations")
415 ;
416
417 write_accesses
418 .name(name() + ".write_accesses")
419 .desc("DTB write accesses")
420 ;
421
422 hits
423 .name(name() + ".hits")
424 .desc("DTB hits")
425 ;
426
427 misses
428 .name(name() + ".misses")
429 .desc("DTB misses")
430 ;
431
432 acv
433 .name(name() + ".acv")
434 .desc("DTB access violations")
435 ;
436
437 accesses
438 .name(name() + ".accesses")
439 .desc("DTB accesses")
440 ;
441
442 hits = read_hits + write_hits;
443 misses = read_misses + write_misses;
444 acv = read_acv + write_acv;
445 accesses = read_accesses + write_accesses;
446 }
447
448 void
449 AlphaDTB::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const
450 {
451 uint64_t *ipr = xc->regs.ipr;
452
453 // set fault address and flags
454 if (!xc->misspeculating() && !xc->regs.intrlock) {
455 // set VA register with faulting address
456 ipr[AlphaISA::IPR_VA] = vaddr;
457
458 // set MM_STAT register flags
459 ipr[AlphaISA::IPR_MM_STAT] = (((xc->regs.opcode & 0x3f) << 11)
460 | ((xc->regs.ra & 0x1f) << 6)
461 | (flags & 0x3f));
462
463 // set VA_FORM register with faulting formatted address
464 ipr[AlphaISA::IPR_VA_FORM] =
465 ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3);
466
467 // lock these registers until the VA register is read
468 xc->regs.intrlock = true;
469 }
470 }
471
472 Fault
473 AlphaDTB::translate(MemReqPtr &req, bool write) const
474 {
475 RegFile *regs = &req->xc->regs;
476 Addr pc = regs->pc;
477 InternalProcReg *ipr = regs->ipr;
478
479 AlphaISA::mode_type mode =
480 (AlphaISA::mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]);
481
482 if (PC_PAL(pc)) {
483 mode = (req->flags & ALTMODE) ?
484 (AlphaISA::mode_type)ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE])
485 : AlphaISA::mode_kernel;
486 }
487
488 if (req->flags & PHYSICAL) {
489 req->paddr = req->vaddr;
490 } else {
491 // verify that this is a good virtual address
492 if (!validVirtualAddress(req->vaddr)) {
493 fault(req->vaddr,
494 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK |
495 MM_STAT_ACV_MASK),
496 req->xc);
497
498 if (write) { write_acv++; } else { read_acv++; }
499 return DTB_Fault_Fault;
500 }
501
502 // Check for "superpage" mapping: when SP<1> is set, and
503 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
504 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
505 VA_SPACE(req->vaddr) == 2) {
506
507 // only valid in kernel mode
508 if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) !=
509 AlphaISA::mode_kernel) {
510 fault(req->vaddr,
511 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK),
512 req->xc);
513 if (write) { write_acv++; } else { read_acv++; }
514 return DTB_Acv_Fault;
515 }
516
517 req->paddr = req->vaddr & PA_IMPL_MASK;
518
519 // sign extend the physical address properly
520 if (req->paddr & PA_UNCACHED_BIT_39 ||
521 req->paddr & PA_UNCACHED_BIT_40)
522 req->paddr |= 0xf0000000000ULL;
523 else
524 req->paddr &= 0xffffffffffULL;
525
526 } else {
527 if (write)
528 write_accesses++;
529 else
530 read_accesses++;
531
532 // not a physical address: need to look up pte
533 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
534 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
535
536 if (!pte) {
537 // page fault
538 fault(req->vaddr,
539 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK),
540 req->xc);
541 if (write) { write_misses++; } else { read_misses++; }
542 return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault;
543 }
544
545 req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr);
546
547 if (write) {
548 if (!(pte->xwe & MODE2MASK(mode))) {
549 // declare the instruction access fault
550 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_ACV_MASK |
551 (pte->fonw ? MM_STAT_FONW_MASK : 0),
552 req->xc);
553 write_acv++;
554 return DTB_Fault_Fault;
555 }
556 if (pte->fonw) {
557 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_FONW_MASK,
558 req->xc);
559 write_acv++;
560 return DTB_Fault_Fault;
561 }
562 } else {
563 if (!(pte->xre & MODE2MASK(mode))) {
564 fault(req->vaddr,
565 MM_STAT_ACV_MASK |
566 (pte->fonr ? MM_STAT_FONR_MASK : 0),
567 req->xc);
568 read_acv++;
569 return DTB_Acv_Fault;
570 }
571 if (pte->fonr) {
572 fault(req->vaddr, MM_STAT_FONR_MASK, req->xc);
573 read_acv++;
574 return DTB_Fault_Fault;
575 }
576 }
577 }
578
579 if (write)
580 write_hits++;
581 else
582 read_hits++;
583 }
584
585 // check that the physical address is ok (catch bad physical addresses)
586 if (req->paddr & ~PA_IMPL_MASK)
587 return Machine_Check_Fault;
588
589 checkCacheability(req);
590
591 return No_Fault;
592 }
593
594 AlphaISA::PTE &
595 AlphaTLB::index(bool advance)
596 {
597 AlphaISA::PTE *pte = &table[nlu];
598
599 if (advance)
600 nextnlu();
601
602 return *pte;
603 }
604
605 DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB)
606
607 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB)
608
609 Param<int> size;
610
611 END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB)
612
613 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB)
614
615 INIT_PARAM_DFLT(size, "TLB size", 48)
616
617 END_INIT_SIM_OBJECT_PARAMS(AlphaITB)
618
619
620 CREATE_SIM_OBJECT(AlphaITB)
621 {
622 return new AlphaITB(getInstanceName(), size);
623 }
624
625 REGISTER_SIM_OBJECT("AlphaITB", AlphaITB)
626
627 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB)
628
629 Param<int> size;
630
631 END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB)
632
633 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB)
634
635 INIT_PARAM_DFLT(size, "TLB size", 64)
636
637 END_INIT_SIM_OBJECT_PARAMS(AlphaDTB)
638
639
640 CREATE_SIM_OBJECT(AlphaDTB)
641 {
642 return new AlphaDTB(getInstanceName(), size);
643 }
644
645 REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB)
646