bab44c434ac8eafa9ccc9a49f247653d0cdceca9
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
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.
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.
28 * Authors: Nathan Binkert
36 #include "arch/alpha/pagetable.hh"
37 #include "arch/alpha/tlb.hh"
38 #include "arch/alpha/faults.hh"
39 #include "base/inifile.hh"
40 #include "base/str.hh"
41 #include "base/trace.hh"
42 #include "config/alpha_tlaser.hh"
43 #include "cpu/thread_context.hh"
44 #include "sim/builder.hh"
49 ///////////////////////////////////////////////////////////////////////
54 bool uncacheBit39
= false;
55 bool uncacheBit40
= false;
58 #define MODE2MASK(X) (1 << (X))
60 AlphaTLB::AlphaTLB(const string
&name
, int s
)
61 : SimObject(name
), size(s
), nlu(0)
63 table
= new AlphaISA::PTE
[size
];
64 memset(table
, 0, sizeof(AlphaISA::PTE
[size
]));
73 // look up an entry in the TLB
75 AlphaTLB::lookup(Addr vpn
, uint8_t asn
) const
77 // assume not found...
78 AlphaISA::PTE
*retval
= NULL
;
80 PageTable::const_iterator i
= lookupTable
.find(vpn
);
81 if (i
!= lookupTable
.end()) {
82 while (i
->first
== vpn
) {
83 int index
= i
->second
;
84 AlphaISA::PTE
*pte
= &table
[index
];
86 if (vpn
== pte
->tag
&& (pte
->asma
|| pte
->asn
== asn
)) {
95 DPRINTF(TLB
, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn
, (int)asn
,
96 retval
? "hit" : "miss", retval
? retval
->ppn
: 0);
102 AlphaTLB::checkCacheability(RequestPtr
&req
)
104 // in Alpha, cacheability is controlled by upper-level bits of the
108 * We support having the uncacheable bit in either bit 39 or bit 40.
109 * The Turbolaser platform (and EV5) support having the bit in 39, but
110 * Tsunami (which Linux assumes uses an EV6) generates accesses with
111 * the bit in 40. So we must check for both, but we have debug flags
112 * to catch a weird case where both are used, which shouldn't happen.
117 if (req
->getPaddr() & PAddrUncachedBit39
) {
119 if (req
->getPaddr() & PAddrUncachedBit43
) {
121 // IPR memory space not implemented
122 if (PAddrIprSpace(req
->getPaddr())) {
123 return new UnimpFault("IPR memory space not implemented!");
125 // mark request as uncacheable
126 req
->setFlags(req
->getFlags() | UNCACHEABLE
);
129 // Clear bits 42:35 of the physical address (10-2 in Tsunami manual)
130 req
->setPaddr(req
->getPaddr() & PAddrUncachedMask
);
138 // insert a new TLB entry
140 AlphaTLB::insert(Addr addr
, AlphaISA::PTE
&pte
)
142 AlphaISA::VAddr vaddr
= addr
;
143 if (table
[nlu
].valid
) {
144 Addr oldvpn
= table
[nlu
].tag
;
145 PageTable::iterator i
= lookupTable
.find(oldvpn
);
147 if (i
== lookupTable
.end())
148 panic("TLB entry not found in lookupTable");
151 while ((index
= i
->second
) != nlu
) {
152 if (table
[index
].tag
!= oldvpn
)
153 panic("TLB entry not found in lookupTable");
158 DPRINTF(TLB
, "remove @%d: %#x -> %#x\n", nlu
, oldvpn
, table
[nlu
].ppn
);
160 lookupTable
.erase(i
);
163 DPRINTF(TLB
, "insert @%d: %#x -> %#x\n", nlu
, vaddr
.vpn(), pte
.ppn
);
166 table
[nlu
].tag
= vaddr
.vpn();
167 table
[nlu
].valid
= true;
169 lookupTable
.insert(make_pair(vaddr
.vpn(), nlu
));
176 DPRINTF(TLB
, "flushAll\n");
177 memset(table
, 0, sizeof(AlphaISA::PTE
[size
]));
183 AlphaTLB::flushProcesses()
185 PageTable::iterator i
= lookupTable
.begin();
186 PageTable::iterator end
= lookupTable
.end();
188 int index
= i
->second
;
189 AlphaISA::PTE
*pte
= &table
[index
];
192 // we can't increment i after we erase it, so save a copy and
193 // increment it to get the next entry now
194 PageTable::iterator cur
= i
;
198 DPRINTF(TLB
, "flush @%d: %#x -> %#x\n", index
, pte
->tag
, pte
->ppn
);
200 lookupTable
.erase(cur
);
206 AlphaTLB::flushAddr(Addr addr
, uint8_t asn
)
208 AlphaISA::VAddr vaddr
= addr
;
210 PageTable::iterator i
= lookupTable
.find(vaddr
.vpn());
211 if (i
== lookupTable
.end())
214 while (i
->first
== vaddr
.vpn()) {
215 int index
= i
->second
;
216 AlphaISA::PTE
*pte
= &table
[index
];
219 if (vaddr
.vpn() == pte
->tag
&& (pte
->asma
|| pte
->asn
== asn
)) {
220 DPRINTF(TLB
, "flushaddr @%d: %#x -> %#x\n", index
, vaddr
.vpn(),
223 // invalidate this entry
226 lookupTable
.erase(i
);
235 AlphaTLB::serialize(ostream
&os
)
237 SERIALIZE_SCALAR(size
);
238 SERIALIZE_SCALAR(nlu
);
240 for (int i
= 0; i
< size
; i
++) {
241 nameOut(os
, csprintf("%s.PTE%d", name(), i
));
242 table
[i
].serialize(os
);
247 AlphaTLB::unserialize(Checkpoint
*cp
, const string
§ion
)
249 UNSERIALIZE_SCALAR(size
);
250 UNSERIALIZE_SCALAR(nlu
);
252 for (int i
= 0; i
< size
; i
++) {
253 table
[i
].unserialize(cp
, csprintf("%s.PTE%d", section
, i
));
254 if (table
[i
].valid
) {
255 lookupTable
.insert(make_pair(table
[i
].tag
, i
));
261 ///////////////////////////////////////////////////////////////////////
265 AlphaITB::AlphaITB(const std::string
&name
, int size
)
266 : AlphaTLB(name
, size
)
274 .name(name() + ".hits")
277 .name(name() + ".misses")
280 .name(name() + ".acv")
283 .name(name() + ".accesses")
284 .desc("ITB accesses");
286 accesses
= hits
+ misses
;
291 AlphaITB::translate(RequestPtr
&req
, ThreadContext
*tc
) const
293 if (AlphaISA::PcPAL(req
->getVaddr())) {
294 // strip off PAL PC marker (lsb is 1)
295 req
->setPaddr((req
->getVaddr() & ~3) & PAddrImplMask
);
300 if (req
->getFlags() & PHYSICAL
) {
301 req
->setPaddr(req
->getVaddr());
303 // verify that this is a good virtual address
304 if (!validVirtualAddress(req
->getVaddr())) {
306 return new ItbAcvFault(req
->getVaddr());
310 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5
311 // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6
313 if ((MCSR_SP(tc
->readMiscReg(AlphaISA::IPR_MCSR
)) & 2) &&
314 VAddrSpaceEV5(req
->getVaddr()) == 2) {
316 if (VAddrSpaceEV6(req
->getVaddr()) == 0x7e) {
318 // only valid in kernel mode
319 if (ICM_CM(tc
->readMiscReg(AlphaISA::IPR_ICM
)) !=
320 AlphaISA::mode_kernel
) {
322 return new ItbAcvFault(req
->getVaddr());
325 req
->setPaddr(req
->getVaddr() & PAddrImplMask
);
328 // sign extend the physical address properly
329 if (req
->getPaddr() & PAddrUncachedBit40
)
330 req
->setPaddr(req
->getPaddr() | ULL(0xf0000000000));
332 req
->setPaddr(req
->getPaddr() & ULL(0xffffffffff));
336 // not a physical address: need to look up pte
337 int asn
= DTB_ASN_ASN(tc
->readMiscReg(AlphaISA::IPR_DTB_ASN
));
338 AlphaISA::PTE
*pte
= lookup(AlphaISA::VAddr(req
->getVaddr()).vpn(),
343 return new ItbPageFault(req
->getVaddr());
346 req
->setPaddr((pte
->ppn
<< AlphaISA::PageShift
) +
347 (AlphaISA::VAddr(req
->getVaddr()).offset()
350 // check permissions for this access
352 (1 << ICM_CM(tc
->readMiscReg(AlphaISA::IPR_ICM
))))) {
353 // instruction access fault
355 return new ItbAcvFault(req
->getVaddr());
362 // check that the physical address is ok (catch bad physical addresses)
363 if (req
->getPaddr() & ~PAddrImplMask
)
364 return genMachineCheckFault();
366 return checkCacheability(req
);
370 ///////////////////////////////////////////////////////////////////////
374 AlphaDTB::AlphaDTB(const std::string
&name
, int size
)
375 : AlphaTLB(name
, size
)
382 .name(name() + ".read_hits")
383 .desc("DTB read hits")
387 .name(name() + ".read_misses")
388 .desc("DTB read misses")
392 .name(name() + ".read_acv")
393 .desc("DTB read access violations")
397 .name(name() + ".read_accesses")
398 .desc("DTB read accesses")
402 .name(name() + ".write_hits")
403 .desc("DTB write hits")
407 .name(name() + ".write_misses")
408 .desc("DTB write misses")
412 .name(name() + ".write_acv")
413 .desc("DTB write access violations")
417 .name(name() + ".write_accesses")
418 .desc("DTB write accesses")
422 .name(name() + ".hits")
427 .name(name() + ".misses")
432 .name(name() + ".acv")
433 .desc("DTB access violations")
437 .name(name() + ".accesses")
438 .desc("DTB accesses")
441 hits
= read_hits
+ write_hits
;
442 misses
= read_misses
+ write_misses
;
443 acv
= read_acv
+ write_acv
;
444 accesses
= read_accesses
+ write_accesses
;
448 AlphaDTB::translate(RequestPtr
&req
, ThreadContext
*tc
, bool write
) const
450 Addr pc
= tc
->readPC();
452 AlphaISA::mode_type mode
=
453 (AlphaISA::mode_type
)DTB_CM_CM(tc
->readMiscReg(AlphaISA::IPR_DTB_CM
));
457 * Check for alignment faults
459 if (req
->getVaddr() & (req
->getSize() - 1)) {
460 DPRINTF(TLB
, "Alignment Fault on %#x, size = %d", req
->getVaddr(),
462 uint64_t flags
= write
? MM_STAT_WR_MASK
: 0;
463 return new DtbAlignmentFault(req
->getVaddr(), req
->getFlags(), flags
);
467 mode
= (req
->getFlags() & ALTMODE
) ?
468 (AlphaISA::mode_type
)ALT_MODE_AM(
469 tc
->readMiscReg(AlphaISA::IPR_ALT_MODE
))
470 : AlphaISA::mode_kernel
;
473 if (req
->getFlags() & PHYSICAL
) {
474 req
->setPaddr(req
->getVaddr());
476 // verify that this is a good virtual address
477 if (!validVirtualAddress(req
->getVaddr())) {
478 if (write
) { write_acv
++; } else { read_acv
++; }
479 uint64_t flags
= (write
? MM_STAT_WR_MASK
: 0) |
480 MM_STAT_BAD_VA_MASK
|
482 return new DtbPageFault(req
->getVaddr(), req
->getFlags(), flags
);
485 // Check for "superpage" mapping
487 if ((MCSR_SP(tc
->readMiscReg(AlphaISA::IPR_MCSR
)) & 2) &&
488 VAddrSpaceEV5(req
->getVaddr()) == 2) {
490 if (VAddrSpaceEV6(req
->getVaddr()) == 0x7e) {
493 // only valid in kernel mode
494 if (DTB_CM_CM(tc
->readMiscReg(AlphaISA::IPR_DTB_CM
)) !=
495 AlphaISA::mode_kernel
) {
496 if (write
) { write_acv
++; } else { read_acv
++; }
497 uint64_t flags
= ((write
? MM_STAT_WR_MASK
: 0) |
499 return new DtbAcvFault(req
->getVaddr(), req
->getFlags(), flags
);
502 req
->setPaddr(req
->getVaddr() & PAddrImplMask
);
505 // sign extend the physical address properly
506 if (req
->getPaddr() & PAddrUncachedBit40
)
507 req
->setPaddr(req
->getPaddr() | ULL(0xf0000000000));
509 req
->setPaddr(req
->getPaddr() & ULL(0xffffffffff));
518 int asn
= DTB_ASN_ASN(tc
->readMiscReg(AlphaISA::IPR_DTB_ASN
));
520 // not a physical address: need to look up pte
521 AlphaISA::PTE
*pte
= lookup(AlphaISA::VAddr(req
->getVaddr()).vpn(),
526 if (write
) { write_misses
++; } else { read_misses
++; }
527 uint64_t flags
= (write
? MM_STAT_WR_MASK
: 0) |
528 MM_STAT_DTB_MISS_MASK
;
529 return (req
->getFlags() & VPTE
) ?
530 (Fault
)(new PDtbMissFault(req
->getVaddr(), req
->getFlags(),
532 (Fault
)(new NDtbMissFault(req
->getVaddr(), req
->getFlags(),
536 req
->setPaddr((pte
->ppn
<< AlphaISA::PageShift
) +
537 AlphaISA::VAddr(req
->getVaddr()).offset());
540 if (!(pte
->xwe
& MODE2MASK(mode
))) {
541 // declare the instruction access fault
543 uint64_t flags
= MM_STAT_WR_MASK
|
545 (pte
->fonw
? MM_STAT_FONW_MASK
: 0);
546 return new DtbPageFault(req
->getVaddr(), req
->getFlags(), flags
);
550 uint64_t flags
= MM_STAT_WR_MASK
|
552 return new DtbPageFault(req
->getVaddr(), req
->getFlags(), flags
);
555 if (!(pte
->xre
& MODE2MASK(mode
))) {
557 uint64_t flags
= MM_STAT_ACV_MASK
|
558 (pte
->fonr
? MM_STAT_FONR_MASK
: 0);
559 return new DtbAcvFault(req
->getVaddr(), req
->getFlags(), flags
);
563 uint64_t flags
= MM_STAT_FONR_MASK
;
564 return new DtbPageFault(req
->getVaddr(), req
->getFlags(), flags
);
575 // check that the physical address is ok (catch bad physical addresses)
576 if (req
->getPaddr() & ~PAddrImplMask
)
577 return genMachineCheckFault();
579 return checkCacheability(req
);
583 AlphaTLB::index(bool advance
)
585 AlphaISA::PTE
*pte
= &table
[nlu
];
593 DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB
)
595 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB
)
599 END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB
)
601 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB
)
603 INIT_PARAM_DFLT(size
, "TLB size", 48)
605 END_INIT_SIM_OBJECT_PARAMS(AlphaITB
)
608 CREATE_SIM_OBJECT(AlphaITB
)
610 return new AlphaITB(getInstanceName(), size
);
613 REGISTER_SIM_OBJECT("AlphaITB", AlphaITB
)
615 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB
)
619 END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB
)
621 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB
)
623 INIT_PARAM_DFLT(size
, "TLB size", 64)
625 END_INIT_SIM_OBJECT_PARAMS(AlphaDTB
)
628 CREATE_SIM_OBJECT(AlphaDTB
)
630 return new AlphaDTB(getInstanceName(), size
);
633 REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB
)