tlb.cc revision 5736:426510e758ad
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::translate(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
404///////////////////////////////////////////////////////////////////////
405//
406//  Alpha DTB
407//
408DTB::DTB(const Params *p)
409     : TLB(p)
410{}
411
412void
413DTB::regStats()
414{
415    read_hits
416        .name(name() + ".read_hits")
417        .desc("DTB read hits")
418        ;
419
420    read_misses
421        .name(name() + ".read_misses")
422        .desc("DTB read misses")
423        ;
424
425    read_acv
426        .name(name() + ".read_acv")
427        .desc("DTB read access violations")
428        ;
429
430    read_accesses
431        .name(name() + ".read_accesses")
432        .desc("DTB read accesses")
433        ;
434
435    write_hits
436        .name(name() + ".write_hits")
437        .desc("DTB write hits")
438        ;
439
440    write_misses
441        .name(name() + ".write_misses")
442        .desc("DTB write misses")
443        ;
444
445    write_acv
446        .name(name() + ".write_acv")
447        .desc("DTB write access violations")
448        ;
449
450    write_accesses
451        .name(name() + ".write_accesses")
452        .desc("DTB write accesses")
453        ;
454
455    hits
456        .name(name() + ".hits")
457        .desc("DTB hits")
458        ;
459
460    misses
461        .name(name() + ".misses")
462        .desc("DTB misses")
463        ;
464
465    acv
466        .name(name() + ".acv")
467        .desc("DTB access violations")
468        ;
469
470    accesses
471        .name(name() + ".accesses")
472        .desc("DTB accesses")
473        ;
474
475    hits = read_hits + write_hits;
476    misses = read_misses + write_misses;
477    acv = read_acv + write_acv;
478    accesses = read_accesses + write_accesses;
479}
480
481Fault
482DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
483{
484    Addr pc = tc->readPC();
485
486    mode_type mode =
487        (mode_type)DTB_CM_CM(tc->readMiscRegNoEffect(IPR_DTB_CM));
488
489    /**
490     * Check for alignment faults
491     */
492    if (req->getVaddr() & (req->getSize() - 1)) {
493        DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(),
494                req->getSize());
495        uint64_t flags = write ? MM_STAT_WR_MASK : 0;
496        return new DtbAlignmentFault(req->getVaddr(), req->getFlags(), flags);
497    }
498
499    if (PcPAL(pc)) {
500        mode = (req->getFlags() & Request::ALTMODE) ?
501            (mode_type)ALT_MODE_AM(
502                tc->readMiscRegNoEffect(IPR_ALT_MODE))
503            : mode_kernel;
504    }
505
506    if (req->getFlags() & Request::PHYSICAL) {
507        req->setPaddr(req->getVaddr());
508    } else {
509        // verify that this is a good virtual address
510        if (!validVirtualAddress(req->getVaddr())) {
511            if (write) { write_acv++; } else { read_acv++; }
512            uint64_t flags = (write ? MM_STAT_WR_MASK : 0) |
513                MM_STAT_BAD_VA_MASK |
514                MM_STAT_ACV_MASK;
515            return new DtbPageFault(req->getVaddr(), req->getFlags(), flags);
516        }
517
518        // Check for "superpage" mapping
519#if ALPHA_TLASER
520        if ((MCSR_SP(tc->readMiscRegNoEffect(IPR_MCSR)) & 2) &&
521            VAddrSpaceEV5(req->getVaddr()) == 2)
522#else
523        if (VAddrSpaceEV6(req->getVaddr()) == 0x7e)
524#endif
525        {
526            // only valid in kernel mode
527            if (DTB_CM_CM(tc->readMiscRegNoEffect(IPR_DTB_CM)) !=
528                mode_kernel) {
529                if (write) { write_acv++; } else { read_acv++; }
530                uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) |
531                                  MM_STAT_ACV_MASK);
532
533                return new DtbAcvFault(req->getVaddr(), req->getFlags(),
534                                       flags);
535            }
536
537            req->setPaddr(req->getVaddr() & PAddrImplMask);
538
539#if !ALPHA_TLASER
540            // sign extend the physical address properly
541            if (req->getPaddr() & PAddrUncachedBit40)
542                req->setPaddr(req->getPaddr() | ULL(0xf0000000000));
543            else
544                req->setPaddr(req->getPaddr() & ULL(0xffffffffff));
545#endif
546
547        } else {
548            if (write)
549                write_accesses++;
550            else
551                read_accesses++;
552
553            int asn = DTB_ASN_ASN(tc->readMiscRegNoEffect(IPR_DTB_ASN));
554
555            // not a physical address: need to look up pte
556            TlbEntry *entry = lookup(VAddr(req->getVaddr()).vpn(), asn);
557
558            if (!entry) {
559                // page fault
560                if (write) { write_misses++; } else { read_misses++; }
561                uint64_t flags = (write ? MM_STAT_WR_MASK : 0) |
562                    MM_STAT_DTB_MISS_MASK;
563                return (req->getFlags() & Request::VPTE) ?
564                    (Fault)(new PDtbMissFault(req->getVaddr(), req->getFlags(),
565                                              flags)) :
566                    (Fault)(new NDtbMissFault(req->getVaddr(), req->getFlags(),
567                                              flags));
568            }
569
570            req->setPaddr((entry->ppn << PageShift) +
571                          VAddr(req->getVaddr()).offset());
572
573            if (write) {
574                if (!(entry->xwe & MODE2MASK(mode))) {
575                    // declare the instruction access fault
576                    write_acv++;
577                    uint64_t flags = MM_STAT_WR_MASK |
578                        MM_STAT_ACV_MASK |
579                        (entry->fonw ? MM_STAT_FONW_MASK : 0);
580                    return new DtbPageFault(req->getVaddr(), req->getFlags(),
581                                            flags);
582                }
583                if (entry->fonw) {
584                    write_acv++;
585                    uint64_t flags = MM_STAT_WR_MASK | MM_STAT_FONW_MASK;
586                    return new DtbPageFault(req->getVaddr(), req->getFlags(),
587                                            flags);
588                }
589            } else {
590                if (!(entry->xre & MODE2MASK(mode))) {
591                    read_acv++;
592                    uint64_t flags = MM_STAT_ACV_MASK |
593                        (entry->fonr ? MM_STAT_FONR_MASK : 0);
594                    return new DtbAcvFault(req->getVaddr(), req->getFlags(),
595                                           flags);
596                }
597                if (entry->fonr) {
598                    read_acv++;
599                    uint64_t flags = MM_STAT_FONR_MASK;
600                    return new DtbPageFault(req->getVaddr(), req->getFlags(),
601                                            flags);
602                }
603            }
604        }
605
606        if (write)
607            write_hits++;
608        else
609            read_hits++;
610    }
611
612    // check that the physical address is ok (catch bad physical addresses)
613    if (req->getPaddr() & ~PAddrImplMask)
614        return genMachineCheckFault();
615
616    return checkCacheability(req);
617}
618
619TlbEntry &
620TLB::index(bool advance)
621{
622    TlbEntry *entry = &table[nlu];
623
624    if (advance)
625        nextnlu();
626
627    return *entry;
628}
629
630/* end namespace AlphaISA */ }
631
632AlphaISA::ITB *
633AlphaITBParams::create()
634{
635    return new AlphaISA::ITB(this);
636}
637
638AlphaISA::DTB *
639AlphaDTBParams::create()
640{
641    return new AlphaISA::DTB(this);
642}
643