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