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