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