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.
33 #include "arch/alpha/tlb.hh"
34 #include "base/inifile.hh"
35 #include "base/str.hh"
36 #include "base/trace.hh"
37 #include "config/alpha_tlaser.hh"
38 #include "cpu/exec_context.hh"
39 #include "sim/builder.hh"
44 ///////////////////////////////////////////////////////////////////////
49 bool uncacheBit39
= false;
50 bool uncacheBit40
= false;
53 #define MODE2MASK(X) (1 << (X))
55 AlphaTLB::AlphaTLB(const string
&name
, int s
)
56 : SimObject(name
), size(s
), nlu(0)
58 table
= new AlphaISA::PTE
[size
];
59 memset(table
, 0, sizeof(AlphaISA::PTE
[size
]));
68 // look up an entry in the TLB
70 AlphaTLB::lookup(Addr vpn
, uint8_t asn
) const
72 // assume not found...
73 AlphaISA::PTE
*retval
= NULL
;
75 PageTable::const_iterator i
= lookupTable
.find(vpn
);
76 if (i
!= lookupTable
.end()) {
77 while (i
->first
== vpn
) {
78 int index
= i
->second
;
79 AlphaISA::PTE
*pte
= &table
[index
];
81 if (vpn
== pte
->tag
&& (pte
->asma
|| pte
->asn
== asn
)) {
90 DPRINTF(TLB
, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn
, (int)asn
,
91 retval
? "hit" : "miss", retval
? retval
->ppn
: 0);
97 AlphaTLB::checkCacheability(MemReqPtr
&req
)
99 // in Alpha, cacheability is controlled by upper-level bits of the
103 * We support having the uncacheable bit in either bit 39 or bit 40.
104 * The Turbolaser platform (and EV5) support having the bit in 39, but
105 * Tsunami (which Linux assumes uses an EV6) generates accesses with
106 * the bit in 40. So we must check for both, but we have debug flags
107 * to catch a weird case where both are used, which shouldn't happen.
112 if (req
->paddr
& PAddrUncachedBit39
) {
114 if (req
->paddr
& PAddrUncachedBit43
) {
116 // IPR memory space not implemented
117 if (PAddrIprSpace(req
->paddr
)) {
118 if (!req
->xc
->misspeculating()) {
119 switch (req
->paddr
) {
120 case ULL(0xFFFFF00188):
125 panic("IPR memory space not implemented! PA=%x\n",
130 // mark request as uncacheable
131 req
->flags
|= UNCACHEABLE
;
134 // Clear bits 42:35 of the physical address (10-2 in Tsunami manual)
135 req
->paddr
&= PAddrUncachedMask
;
142 // insert a new TLB entry
144 AlphaTLB::insert(Addr addr
, AlphaISA::PTE
&pte
)
146 AlphaISA::VAddr vaddr
= addr
;
147 if (table
[nlu
].valid
) {
148 Addr oldvpn
= table
[nlu
].tag
;
149 PageTable::iterator i
= lookupTable
.find(oldvpn
);
151 if (i
== lookupTable
.end())
152 panic("TLB entry not found in lookupTable");
155 while ((index
= i
->second
) != nlu
) {
156 if (table
[index
].tag
!= oldvpn
)
157 panic("TLB entry not found in lookupTable");
162 DPRINTF(TLB
, "remove @%d: %#x -> %#x\n", nlu
, oldvpn
, table
[nlu
].ppn
);
164 lookupTable
.erase(i
);
167 DPRINTF(TLB
, "insert @%d: %#x -> %#x\n", nlu
, vaddr
.vpn(), pte
.ppn
);
170 table
[nlu
].tag
= vaddr
.vpn();
171 table
[nlu
].valid
= true;
173 lookupTable
.insert(make_pair(vaddr
.vpn(), nlu
));
180 DPRINTF(TLB
, "flushAll\n");
181 memset(table
, 0, sizeof(AlphaISA::PTE
[size
]));
187 AlphaTLB::flushProcesses()
189 PageTable::iterator i
= lookupTable
.begin();
190 PageTable::iterator end
= lookupTable
.end();
192 int index
= i
->second
;
193 AlphaISA::PTE
*pte
= &table
[index
];
196 // we can't increment i after we erase it, so save a copy and
197 // increment it to get the next entry now
198 PageTable::iterator cur
= i
;
202 DPRINTF(TLB
, "flush @%d: %#x -> %#x\n", index
, pte
->tag
, pte
->ppn
);
204 lookupTable
.erase(cur
);
210 AlphaTLB::flushAddr(Addr addr
, uint8_t asn
)
212 AlphaISA::VAddr vaddr
= addr
;
214 PageTable::iterator i
= lookupTable
.find(vaddr
.vpn());
215 if (i
== lookupTable
.end())
218 while (i
->first
== vaddr
.vpn()) {
219 int index
= i
->second
;
220 AlphaISA::PTE
*pte
= &table
[index
];
223 if (vaddr
.vpn() == pte
->tag
&& (pte
->asma
|| pte
->asn
== asn
)) {
224 DPRINTF(TLB
, "flushaddr @%d: %#x -> %#x\n", index
, vaddr
.vpn(),
227 // invalidate this entry
230 lookupTable
.erase(i
);
239 AlphaTLB::serialize(ostream
&os
)
241 SERIALIZE_SCALAR(size
);
242 SERIALIZE_SCALAR(nlu
);
244 for (int i
= 0; i
< size
; i
++) {
245 nameOut(os
, csprintf("%s.PTE%d", name(), i
));
246 table
[i
].serialize(os
);
251 AlphaTLB::unserialize(Checkpoint
*cp
, const string
§ion
)
253 UNSERIALIZE_SCALAR(size
);
254 UNSERIALIZE_SCALAR(nlu
);
256 for (int i
= 0; i
< size
; i
++) {
257 table
[i
].unserialize(cp
, csprintf("%s.PTE%d", section
, i
));
258 if (table
[i
].valid
) {
259 lookupTable
.insert(make_pair(table
[i
].tag
, i
));
265 ///////////////////////////////////////////////////////////////////////
269 AlphaITB::AlphaITB(const std::string
&name
, int size
)
270 : AlphaTLB(name
, size
)
278 .name(name() + ".hits")
281 .name(name() + ".misses")
284 .name(name() + ".acv")
287 .name(name() + ".accesses")
288 .desc("ITB accesses");
290 accesses
= hits
+ misses
;
295 AlphaITB::translate(MemReqPtr
&req
) const
297 ExecContext
*xc
= req
->xc
;
299 if (AlphaISA::PcPAL(req
->vaddr
)) {
300 // strip off PAL PC marker (lsb is 1)
301 req
->paddr
= (req
->vaddr
& ~3) & PAddrImplMask
;
306 if (req
->flags
& PHYSICAL
) {
307 req
->paddr
= req
->vaddr
;
309 // verify that this is a good virtual address
310 if (!validVirtualAddress(req
->vaddr
)) {
312 return new ItbAcvFault(req
->vaddr
);
316 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5
317 // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6
319 if ((MCSR_SP(xc
->readMiscReg(AlphaISA::IPR_MCSR
)) & 2) &&
320 VAddrSpaceEV5(req
->vaddr
) == 2) {
322 if (VAddrSpaceEV6(req
->vaddr
) == 0x7e) {
324 // only valid in kernel mode
325 if (ICM_CM(xc
->readMiscReg(AlphaISA::IPR_ICM
)) !=
326 AlphaISA::mode_kernel
) {
328 return new ItbAcvFault(req
->vaddr
);
331 req
->paddr
= req
->vaddr
& PAddrImplMask
;
334 // sign extend the physical address properly
335 if (req
->paddr
& PAddrUncachedBit40
)
336 req
->paddr
|= ULL(0xf0000000000);
338 req
->paddr
&= ULL(0xffffffffff);
342 // not a physical address: need to look up pte
343 int asn
= DTB_ASN_ASN(xc
->readMiscReg(AlphaISA::IPR_DTB_ASN
));
344 AlphaISA::PTE
*pte
= lookup(AlphaISA::VAddr(req
->vaddr
).vpn(),
349 return new ItbPageFault(req
->vaddr
);
352 req
->paddr
= (pte
->ppn
<< AlphaISA::PageShift
) +
353 (AlphaISA::VAddr(req
->vaddr
).offset() & ~3);
355 // check permissions for this access
357 (1 << ICM_CM(xc
->readMiscReg(AlphaISA::IPR_ICM
))))) {
358 // instruction access fault
360 return new ItbAcvFault(req
->vaddr
);
367 // check that the physical address is ok (catch bad physical addresses)
368 if (req
->paddr
& ~PAddrImplMask
)
369 return genMachineCheckFault();
371 checkCacheability(req
);
376 ///////////////////////////////////////////////////////////////////////
380 AlphaDTB::AlphaDTB(const std::string
&name
, int size
)
381 : AlphaTLB(name
, size
)
388 .name(name() + ".read_hits")
389 .desc("DTB read hits")
393 .name(name() + ".read_misses")
394 .desc("DTB read misses")
398 .name(name() + ".read_acv")
399 .desc("DTB read access violations")
403 .name(name() + ".read_accesses")
404 .desc("DTB read accesses")
408 .name(name() + ".write_hits")
409 .desc("DTB write hits")
413 .name(name() + ".write_misses")
414 .desc("DTB write misses")
418 .name(name() + ".write_acv")
419 .desc("DTB write access violations")
423 .name(name() + ".write_accesses")
424 .desc("DTB write accesses")
428 .name(name() + ".hits")
433 .name(name() + ".misses")
438 .name(name() + ".acv")
439 .desc("DTB access violations")
443 .name(name() + ".accesses")
444 .desc("DTB accesses")
447 hits
= read_hits
+ write_hits
;
448 misses
= read_misses
+ write_misses
;
449 acv
= read_acv
+ write_acv
;
450 accesses
= read_accesses
+ write_accesses
;
454 AlphaDTB::translate(MemReqPtr
&req
, bool write
) const
456 ExecContext
*xc
= req
->xc
;
457 Addr pc
= xc
->readPC();
459 AlphaISA::mode_type mode
=
460 (AlphaISA::mode_type
)DTB_CM_CM(xc
->readMiscReg(AlphaISA::IPR_DTB_CM
));
464 * Check for alignment faults
466 if (req
->vaddr
& (req
->size
- 1)) {
467 DPRINTF(TLB
, "Alignment Fault on %#x, size = %d", req
->vaddr
,
469 uint64_t flags
= write
? MM_STAT_WR_MASK
: 0;
470 return new DtbAlignmentFault(req
->vaddr
, req
->flags
, flags
);
474 mode
= (req
->flags
& ALTMODE
) ?
475 (AlphaISA::mode_type
)ALT_MODE_AM(
476 xc
->readMiscReg(AlphaISA::IPR_ALT_MODE
))
477 : AlphaISA::mode_kernel
;
480 if (req
->flags
& PHYSICAL
) {
481 req
->paddr
= req
->vaddr
;
483 // verify that this is a good virtual address
484 if (!validVirtualAddress(req
->vaddr
)) {
485 if (write
) { write_acv
++; } else { read_acv
++; }
486 uint64_t flags
= (write
? MM_STAT_WR_MASK
: 0) |
487 MM_STAT_BAD_VA_MASK
|
489 return new DtbPageFault(req
->vaddr
, req
->flags
, flags
);
492 // Check for "superpage" mapping
494 if ((MCSR_SP(xc
->readMiscReg(AlphaISA::IPR_MCSR
)) & 2) &&
495 VAddrSpaceEV5(req
->vaddr
) == 2) {
497 if (VAddrSpaceEV6(req
->vaddr
) == 0x7e) {
500 // only valid in kernel mode
501 if (DTB_CM_CM(xc
->readMiscReg(AlphaISA::IPR_DTB_CM
)) !=
502 AlphaISA::mode_kernel
) {
503 if (write
) { write_acv
++; } else { read_acv
++; }
504 uint64_t flags
= ((write
? MM_STAT_WR_MASK
: 0) |
506 return new DtbAcvFault(req
->vaddr
, req
->flags
, flags
);
509 req
->paddr
= req
->vaddr
& PAddrImplMask
;
512 // sign extend the physical address properly
513 if (req
->paddr
& PAddrUncachedBit40
)
514 req
->paddr
|= ULL(0xf0000000000);
516 req
->paddr
&= ULL(0xffffffffff);
525 int asn
= DTB_ASN_ASN(xc
->readMiscReg(AlphaISA::IPR_DTB_ASN
));
527 // not a physical address: need to look up pte
528 AlphaISA::PTE
*pte
= lookup(AlphaISA::VAddr(req
->vaddr
).vpn(),
533 if (write
) { write_misses
++; } else { read_misses
++; }
534 uint64_t flags
= (write
? MM_STAT_WR_MASK
: 0) |
535 MM_STAT_DTB_MISS_MASK
;
536 return (req
->flags
& VPTE
) ?
537 (Fault
)(new PDtbMissFault(req
->vaddr
, req
->flags
,
539 (Fault
)(new NDtbMissFault(req
->vaddr
, req
->flags
,
543 req
->paddr
= (pte
->ppn
<< AlphaISA::PageShift
) +
544 AlphaISA::VAddr(req
->vaddr
).offset();
547 if (!(pte
->xwe
& MODE2MASK(mode
))) {
548 // declare the instruction access fault
550 uint64_t flags
= MM_STAT_WR_MASK
|
552 (pte
->fonw
? MM_STAT_FONW_MASK
: 0);
553 return new DtbPageFault(req
->vaddr
, req
->flags
, flags
);
557 uint64_t flags
= MM_STAT_WR_MASK
|
559 return new DtbPageFault(req
->vaddr
, req
->flags
, flags
);
562 if (!(pte
->xre
& MODE2MASK(mode
))) {
564 uint64_t flags
= MM_STAT_ACV_MASK
|
565 (pte
->fonr
? MM_STAT_FONR_MASK
: 0);
566 return new DtbAcvFault(req
->vaddr
, req
->flags
, flags
);
570 uint64_t flags
= MM_STAT_FONR_MASK
;
571 return new DtbPageFault(req
->vaddr
, req
->flags
, flags
);
582 // check that the physical address is ok (catch bad physical addresses)
583 if (req
->paddr
& ~PAddrImplMask
)
584 return genMachineCheckFault();
586 checkCacheability(req
);
592 AlphaTLB::index(bool advance
)
594 AlphaISA::PTE
*pte
= &table
[nlu
];
602 DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB
)
604 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB
)
608 END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB
)
610 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB
)
612 INIT_PARAM_DFLT(size
, "TLB size", 48)
614 END_INIT_SIM_OBJECT_PARAMS(AlphaITB
)
617 CREATE_SIM_OBJECT(AlphaITB
)
619 return new AlphaITB(getInstanceName(), size
);
622 REGISTER_SIM_OBJECT("AlphaITB", AlphaITB
)
624 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB
)
628 END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB
)
630 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB
)
632 INIT_PARAM_DFLT(size
, "TLB size", 64)
634 END_INIT_SIM_OBJECT_PARAMS(AlphaDTB
)
637 CREATE_SIM_OBJECT(AlphaDTB
)
639 return new AlphaDTB(getInstanceName(), size
);
642 REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB
)