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