tlb.cc revision 5894:8091ac99341a
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: Nathan Binkert
29 *          Steve Reinhardt
30 *          Andrew Schultz
31 */
32
33#include <string>
34#include <vector>
35
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
45using namespace std;
46
47namespace AlphaISA {
48
49///////////////////////////////////////////////////////////////////////
50//
51//  Alpha TLB
52//
53
54#ifdef DEBUG
55bool uncacheBit39 = false;
56bool uncacheBit40 = false;
57#endif
58
59#define MODE2MASK(X) (1 << (X))
60
61TLB::TLB(const Params *p)
62    : BaseTLB(p), size(p->size), nlu(0)
63{
64    table = new TlbEntry[size];
65    memset(table, 0, sizeof(TlbEntry[size]));
66    flushCache();
67}
68
69TLB::~TLB()
70{
71    if (table)
72        delete [] table;
73}
74
75// look up an entry in the TLB
76TlbEntry *
77TLB::lookup(Addr vpn, uint8_t asn)
78{
79    // assume not found...
80    TlbEntry *retval = NULL;
81
82    if (EntryCache[0]) {
83        if (vpn == EntryCache[0]->tag &&
84            (EntryCache[0]->asma || EntryCache[0]->asn == asn))
85            retval = EntryCache[0];
86        else if (EntryCache[1]) {
87            if (vpn == EntryCache[1]->tag &&
88                (EntryCache[1]->asma || EntryCache[1]->asn == asn))
89                retval = EntryCache[1];
90            else if (EntryCache[2] && vpn == EntryCache[2]->tag &&
91                     (EntryCache[2]->asma || EntryCache[2]->asn == asn))
92                retval = EntryCache[2];
93        }
94    }
95
96    if (retval == NULL) {
97        PageTable::const_iterator i = lookupTable.find(vpn);
98        if (i != lookupTable.end()) {
99            while (i->first == vpn) {
100                int index = i->second;
101                TlbEntry *entry = &table[index];
102                assert(entry->valid);
103                if (vpn == entry->tag && (entry->asma || entry->asn == asn)) {
104                    retval = updateCache(entry);
105                    break;
106                }
107
108                ++i;
109            }
110        }
111    }
112
113    DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn,
114            retval ? "hit" : "miss", retval ? retval->ppn : 0);
115    return retval;
116}
117
118Fault
119TLB::checkCacheability(RequestPtr &req, bool itb)
120{
121    // in Alpha, cacheability is controlled by upper-level bits of the
122    // physical address
123
124    /*
125     * We support having the uncacheable bit in either bit 39 or bit
126     * 40.  The Turbolaser platform (and EV5) support having the bit
127     * in 39, but Tsunami (which Linux assumes uses an EV6) generates
128     * accesses with the bit in 40.  So we must check for both, but we
129     * have debug flags to catch a weird case where both are used,
130     * which shouldn't happen.
131     */
132
133
134#if ALPHA_TLASER
135    if (req->getPaddr() & PAddrUncachedBit39)
136#else
137    if (req->getPaddr() & PAddrUncachedBit43)
138#endif
139    {
140        // IPR memory space not implemented
141        if (PAddrIprSpace(req->getPaddr())) {
142            return new UnimpFault("IPR memory space not implemented!");
143        } else {
144            // mark request as uncacheable
145            req->setFlags(Request::UNCACHEABLE);
146
147#if !ALPHA_TLASER
148            // Clear bits 42:35 of the physical address (10-2 in
149            // Tsunami manual)
150            req->setPaddr(req->getPaddr() & PAddrUncachedMask);
151#endif
152        }
153        // We shouldn't be able to read from an uncachable address in Alpha as
154        // we don't have a ROM and we don't want to try to fetch from a device
155        // register as we destroy any data that is clear-on-read.
156        if (req->isUncacheable() && itb)
157            return new UnimpFault("CPU trying to fetch from uncached I/O");
158
159    }
160    return NoFault;
161}
162
163
164// insert a new TLB entry
165void
166TLB::insert(Addr addr, TlbEntry &entry)
167{
168    flushCache();
169    VAddr vaddr = addr;
170    if (table[nlu].valid) {
171        Addr oldvpn = table[nlu].tag;
172        PageTable::iterator i = lookupTable.find(oldvpn);
173
174        if (i == lookupTable.end())
175            panic("TLB entry not found in lookupTable");
176
177        int index;
178        while ((index = i->second) != nlu) {
179            if (table[index].tag != oldvpn)
180                panic("TLB entry not found in lookupTable");
181
182            ++i;
183        }
184
185        DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn);
186
187        lookupTable.erase(i);
188    }
189
190    DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), entry.ppn);
191
192    table[nlu] = entry;
193    table[nlu].tag = vaddr.vpn();
194    table[nlu].valid = true;
195
196    lookupTable.insert(make_pair(vaddr.vpn(), nlu));
197    nextnlu();
198}
199
200void
201TLB::flushAll()
202{
203    DPRINTF(TLB, "flushAll\n");
204    memset(table, 0, sizeof(TlbEntry[size]));
205    flushCache();
206    lookupTable.clear();
207    nlu = 0;
208}
209
210void
211TLB::flushProcesses()
212{
213    flushCache();
214    PageTable::iterator i = lookupTable.begin();
215    PageTable::iterator end = lookupTable.end();
216    while (i != end) {
217        int index = i->second;
218        TlbEntry *entry = &table[index];
219        assert(entry->valid);
220
221        // we can't increment i after we erase it, so save a copy and
222        // increment it to get the next entry now
223        PageTable::iterator cur = i;
224        ++i;
225
226        if (!entry->asma) {
227            DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index,
228                    entry->tag, entry->ppn);
229            entry->valid = false;
230            lookupTable.erase(cur);
231        }
232    }
233}
234
235void
236TLB::flushAddr(Addr addr, uint8_t asn)
237{
238    flushCache();
239    VAddr vaddr = addr;
240
241    PageTable::iterator i = lookupTable.find(vaddr.vpn());
242    if (i == lookupTable.end())
243        return;
244
245    while (i != lookupTable.end() && i->first == vaddr.vpn()) {
246        int index = i->second;
247        TlbEntry *entry = &table[index];
248        assert(entry->valid);
249
250        if (vaddr.vpn() == entry->tag && (entry->asma || entry->asn == asn)) {
251            DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vaddr.vpn(),
252                    entry->ppn);
253
254            // invalidate this entry
255            entry->valid = false;
256
257            lookupTable.erase(i++);
258        } else {
259            ++i;
260        }
261    }
262}
263
264
265void
266TLB::serialize(ostream &os)
267{
268    SERIALIZE_SCALAR(size);
269    SERIALIZE_SCALAR(nlu);
270
271    for (int i = 0; i < size; i++) {
272        nameOut(os, csprintf("%s.Entry%d", name(), i));
273        table[i].serialize(os);
274    }
275}
276
277void
278TLB::unserialize(Checkpoint *cp, const string &section)
279{
280    UNSERIALIZE_SCALAR(size);
281    UNSERIALIZE_SCALAR(nlu);
282
283    for (int i = 0; i < size; i++) {
284        table[i].unserialize(cp, csprintf("%s.Entry%d", section, i));
285        if (table[i].valid) {
286            lookupTable.insert(make_pair(table[i].tag, i));
287        }
288    }
289}
290
291///////////////////////////////////////////////////////////////////////
292//
293//  Alpha ITB
294//
295ITB::ITB(const Params *p)
296    : TLB(p)
297{}
298
299
300void
301ITB::regStats()
302{
303    hits
304        .name(name() + ".hits")
305        .desc("ITB hits");
306    misses
307        .name(name() + ".misses")
308        .desc("ITB misses");
309    acv
310        .name(name() + ".acv")
311        .desc("ITB acv");
312    accesses
313        .name(name() + ".accesses")
314        .desc("ITB accesses");
315
316    accesses = hits + misses;
317}
318
319Fault
320ITB::translateAtomic(RequestPtr req, ThreadContext *tc)
321{
322    //If this is a pal pc, then set PHYSICAL
323    if (FULL_SYSTEM && PcPAL(req->getPC()))
324        req->setFlags(Request::PHYSICAL);
325
326    if (PcPAL(req->getPC())) {
327        // strip off PAL PC marker (lsb is 1)
328        req->setPaddr((req->getVaddr() & ~3) & PAddrImplMask);
329        hits++;
330        return NoFault;
331    }
332
333    if (req->getFlags() & Request::PHYSICAL) {
334        req->setPaddr(req->getVaddr());
335    } else {
336        // verify that this is a good virtual address
337        if (!validVirtualAddress(req->getVaddr())) {
338            acv++;
339            return new ItbAcvFault(req->getVaddr());
340        }
341
342
343        // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5
344        // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6
345#if ALPHA_TLASER
346        if ((MCSR_SP(tc->readMiscRegNoEffect(IPR_MCSR)) & 2) &&
347            VAddrSpaceEV5(req->getVaddr()) == 2)
348#else
349        if (VAddrSpaceEV6(req->getVaddr()) == 0x7e)
350#endif
351        {
352            // only valid in kernel mode
353            if (ICM_CM(tc->readMiscRegNoEffect(IPR_ICM)) !=
354                mode_kernel) {
355                acv++;
356                return new ItbAcvFault(req->getVaddr());
357            }
358
359            req->setPaddr(req->getVaddr() & PAddrImplMask);
360
361#if !ALPHA_TLASER
362            // sign extend the physical address properly
363            if (req->getPaddr() & PAddrUncachedBit40)
364                req->setPaddr(req->getPaddr() | ULL(0xf0000000000));
365            else
366                req->setPaddr(req->getPaddr() & ULL(0xffffffffff));
367#endif
368
369        } else {
370            // not a physical address: need to look up pte
371            int asn = DTB_ASN_ASN(tc->readMiscRegNoEffect(IPR_DTB_ASN));
372            TlbEntry *entry = lookup(VAddr(req->getVaddr()).vpn(),
373                              asn);
374
375            if (!entry) {
376                misses++;
377                return new ItbPageFault(req->getVaddr());
378            }
379
380            req->setPaddr((entry->ppn << PageShift) +
381                          (VAddr(req->getVaddr()).offset()
382                           & ~3));
383
384            // check permissions for this access
385            if (!(entry->xre &
386                  (1 << ICM_CM(tc->readMiscRegNoEffect(IPR_ICM))))) {
387                // instruction access fault
388                acv++;
389                return new ItbAcvFault(req->getVaddr());
390            }
391
392            hits++;
393        }
394    }
395
396    // check that the physical address is ok (catch bad physical addresses)
397    if (req->getPaddr() & ~PAddrImplMask)
398        return genMachineCheckFault();
399
400    return checkCacheability(req, true);
401
402}
403
404void
405ITB::translateTiming(RequestPtr req, ThreadContext *tc,
406        Translation *translation)
407{
408    assert(translation);
409    translation->finish(translateAtomic(req, tc), req, tc, false);
410}
411
412///////////////////////////////////////////////////////////////////////
413//
414//  Alpha DTB
415//
416DTB::DTB(const Params *p)
417     : TLB(p)
418{}
419
420void
421DTB::regStats()
422{
423    read_hits
424        .name(name() + ".read_hits")
425        .desc("DTB read hits")
426        ;
427
428    read_misses
429        .name(name() + ".read_misses")
430        .desc("DTB read misses")
431        ;
432
433    read_acv
434        .name(name() + ".read_acv")
435        .desc("DTB read access violations")
436        ;
437
438    read_accesses
439        .name(name() + ".read_accesses")
440        .desc("DTB read accesses")
441        ;
442
443    write_hits
444        .name(name() + ".write_hits")
445        .desc("DTB write hits")
446        ;
447
448    write_misses
449        .name(name() + ".write_misses")
450        .desc("DTB write misses")
451        ;
452
453    write_acv
454        .name(name() + ".write_acv")
455        .desc("DTB write access violations")
456        ;
457
458    write_accesses
459        .name(name() + ".write_accesses")
460        .desc("DTB write accesses")
461        ;
462
463    hits
464        .name(name() + ".hits")
465        .desc("DTB hits")
466        ;
467
468    misses
469        .name(name() + ".misses")
470        .desc("DTB misses")
471        ;
472
473    acv
474        .name(name() + ".acv")
475        .desc("DTB access violations")
476        ;
477
478    accesses
479        .name(name() + ".accesses")
480        .desc("DTB accesses")
481        ;
482
483    hits = read_hits + write_hits;
484    misses = read_misses + write_misses;
485    acv = read_acv + write_acv;
486    accesses = read_accesses + write_accesses;
487}
488
489Fault
490DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write)
491{
492    Addr pc = tc->readPC();
493
494    mode_type mode =
495        (mode_type)DTB_CM_CM(tc->readMiscRegNoEffect(IPR_DTB_CM));
496
497    /**
498     * Check for alignment faults
499     */
500    if (req->getVaddr() & (req->getSize() - 1)) {
501        DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(),
502                req->getSize());
503        uint64_t flags = write ? MM_STAT_WR_MASK : 0;
504        return new DtbAlignmentFault(req->getVaddr(), req->getFlags(), flags);
505    }
506
507    if (PcPAL(pc)) {
508        mode = (req->getFlags() & Request::ALTMODE) ?
509            (mode_type)ALT_MODE_AM(
510                tc->readMiscRegNoEffect(IPR_ALT_MODE))
511            : mode_kernel;
512    }
513
514    if (req->getFlags() & Request::PHYSICAL) {
515        req->setPaddr(req->getVaddr());
516    } else {
517        // verify that this is a good virtual address
518        if (!validVirtualAddress(req->getVaddr())) {
519            if (write) { write_acv++; } else { read_acv++; }
520            uint64_t flags = (write ? MM_STAT_WR_MASK : 0) |
521                MM_STAT_BAD_VA_MASK |
522                MM_STAT_ACV_MASK;
523            return new DtbPageFault(req->getVaddr(), req->getFlags(), flags);
524        }
525
526        // Check for "superpage" mapping
527#if ALPHA_TLASER
528        if ((MCSR_SP(tc->readMiscRegNoEffect(IPR_MCSR)) & 2) &&
529            VAddrSpaceEV5(req->getVaddr()) == 2)
530#else
531        if (VAddrSpaceEV6(req->getVaddr()) == 0x7e)
532#endif
533        {
534            // only valid in kernel mode
535            if (DTB_CM_CM(tc->readMiscRegNoEffect(IPR_DTB_CM)) !=
536                mode_kernel) {
537                if (write) { write_acv++; } else { read_acv++; }
538                uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) |
539                                  MM_STAT_ACV_MASK);
540
541                return new DtbAcvFault(req->getVaddr(), req->getFlags(),
542                                       flags);
543            }
544
545            req->setPaddr(req->getVaddr() & PAddrImplMask);
546
547#if !ALPHA_TLASER
548            // sign extend the physical address properly
549            if (req->getPaddr() & PAddrUncachedBit40)
550                req->setPaddr(req->getPaddr() | ULL(0xf0000000000));
551            else
552                req->setPaddr(req->getPaddr() & ULL(0xffffffffff));
553#endif
554
555        } else {
556            if (write)
557                write_accesses++;
558            else
559                read_accesses++;
560
561            int asn = DTB_ASN_ASN(tc->readMiscRegNoEffect(IPR_DTB_ASN));
562
563            // not a physical address: need to look up pte
564            TlbEntry *entry = lookup(VAddr(req->getVaddr()).vpn(), asn);
565
566            if (!entry) {
567                // page fault
568                if (write) { write_misses++; } else { read_misses++; }
569                uint64_t flags = (write ? MM_STAT_WR_MASK : 0) |
570                    MM_STAT_DTB_MISS_MASK;
571                return (req->getFlags() & Request::VPTE) ?
572                    (Fault)(new PDtbMissFault(req->getVaddr(), req->getFlags(),
573                                              flags)) :
574                    (Fault)(new NDtbMissFault(req->getVaddr(), req->getFlags(),
575                                              flags));
576            }
577
578            req->setPaddr((entry->ppn << PageShift) +
579                          VAddr(req->getVaddr()).offset());
580
581            if (write) {
582                if (!(entry->xwe & MODE2MASK(mode))) {
583                    // declare the instruction access fault
584                    write_acv++;
585                    uint64_t flags = MM_STAT_WR_MASK |
586                        MM_STAT_ACV_MASK |
587                        (entry->fonw ? MM_STAT_FONW_MASK : 0);
588                    return new DtbPageFault(req->getVaddr(), req->getFlags(),
589                                            flags);
590                }
591                if (entry->fonw) {
592                    write_acv++;
593                    uint64_t flags = MM_STAT_WR_MASK | MM_STAT_FONW_MASK;
594                    return new DtbPageFault(req->getVaddr(), req->getFlags(),
595                                            flags);
596                }
597            } else {
598                if (!(entry->xre & MODE2MASK(mode))) {
599                    read_acv++;
600                    uint64_t flags = MM_STAT_ACV_MASK |
601                        (entry->fonr ? MM_STAT_FONR_MASK : 0);
602                    return new DtbAcvFault(req->getVaddr(), req->getFlags(),
603                                           flags);
604                }
605                if (entry->fonr) {
606                    read_acv++;
607                    uint64_t flags = MM_STAT_FONR_MASK;
608                    return new DtbPageFault(req->getVaddr(), req->getFlags(),
609                                            flags);
610                }
611            }
612        }
613
614        if (write)
615            write_hits++;
616        else
617            read_hits++;
618    }
619
620    // check that the physical address is ok (catch bad physical addresses)
621    if (req->getPaddr() & ~PAddrImplMask)
622        return genMachineCheckFault();
623
624    return checkCacheability(req);
625}
626
627void
628DTB::translateTiming(RequestPtr req, ThreadContext *tc,
629        Translation *translation, bool write)
630{
631    assert(translation);
632    translation->finish(translateAtomic(req, tc, write), req, tc, write);
633}
634
635TlbEntry &
636TLB::index(bool advance)
637{
638    TlbEntry *entry = &table[nlu];
639
640    if (advance)
641        nextnlu();
642
643    return *entry;
644}
645
646/* end namespace AlphaISA */ }
647
648AlphaISA::ITB *
649AlphaITBParams::create()
650{
651    return new AlphaISA::ITB(this);
652}
653
654AlphaISA::DTB *
655AlphaDTBParams::create()
656{
657    return new AlphaISA::DTB(this);
658}
659