2 * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 #include "config/full_system.hh"
44 #include "arch/x86/faults.hh"
45 #include "arch/x86/insts/microldstop.hh"
46 #include "arch/x86/pagetable.hh"
47 #include "arch/x86/regs/misc.hh"
48 #include "arch/x86/tlb.hh"
49 #include "arch/x86/x86_traits.hh"
50 #include "base/bitfield.hh"
51 #include "base/trace.hh"
52 #include "config/full_system.hh"
53 #include "cpu/thread_context.hh"
54 #include "cpu/base.hh"
55 #include "mem/packet_access.hh"
56 #include "mem/request.hh"
59 #include "arch/x86/pagetable_walker.hh"
61 #include "mem/page_table.hh"
62 #include "sim/process.hh"
67 TLB::TLB(const Params
*p
) : BaseTLB(p
), configAddress(0), size(p
->size
)
69 tlb
= new TlbEntry
[size
];
70 std::memset(tlb
, 0, sizeof(TlbEntry
) * size
);
72 for (int x
= 0; x
< size
; x
++)
73 freeList
.push_back(&tlb
[x
]);
82 TLB::insert(Addr vpn
, TlbEntry
&entry
)
84 //TODO Deal with conflicting entries
86 TlbEntry
*newEntry
= NULL
;
87 if (!freeList
.empty()) {
88 newEntry
= freeList
.front();
91 newEntry
= entryList
.back();
95 newEntry
->vaddr
= vpn
;
96 entryList
.push_front(newEntry
);
100 TLB::EntryList::iterator
101 TLB::lookupIt(Addr va
, bool update_lru
)
103 //TODO make this smarter at some point
104 EntryList::iterator entry
;
105 for (entry
= entryList
.begin(); entry
!= entryList
.end(); entry
++) {
106 if ((*entry
)->vaddr
<= va
&& (*entry
)->vaddr
+ (*entry
)->size
> va
) {
107 DPRINTF(TLB
, "Matched vaddr %#x to entry starting at %#x "
108 "with size %#x.\n", va
, (*entry
)->vaddr
, (*entry
)->size
);
110 entryList
.push_front(*entry
);
111 entryList
.erase(entry
);
112 entry
= entryList
.begin();
121 TLB::lookup(Addr va
, bool update_lru
)
123 EntryList::iterator entry
= lookupIt(va
, update_lru
);
124 if (entry
== entryList
.end())
133 DPRINTF(TLB
, "Invalidating all entries.\n");
134 while (!entryList
.empty()) {
135 TlbEntry
*entry
= entryList
.front();
136 entryList
.pop_front();
137 freeList
.push_back(entry
);
142 TLB::setConfigAddress(uint32_t addr
)
144 configAddress
= addr
;
148 TLB::invalidateNonGlobal()
150 DPRINTF(TLB
, "Invalidating all non global entries.\n");
151 EntryList::iterator entryIt
;
152 for (entryIt
= entryList
.begin(); entryIt
!= entryList
.end();) {
153 if (!(*entryIt
)->global
) {
154 freeList
.push_back(*entryIt
);
155 entryList
.erase(entryIt
++);
163 TLB::demapPage(Addr va
, uint64_t asn
)
165 EntryList::iterator entry
= lookupIt(va
, false);
166 if (entry
!= entryList
.end()) {
167 freeList
.push_back(*entry
);
168 entryList
.erase(entry
);
173 TLB::translateInt(RequestPtr req
, ThreadContext
*tc
)
175 DPRINTF(TLB
, "Addresses references internal memory.\n");
176 Addr vaddr
= req
->getVaddr();
177 Addr prefix
= (vaddr
>> 3) & IntAddrPrefixMask
;
178 if (prefix
== IntAddrPrefixCPUID
) {
179 panic("CPUID memory space not yet implemented!\n");
180 } else if (prefix
== IntAddrPrefixMSR
) {
182 req
->setFlags(Request::MMAPED_IPR
);
184 switch (vaddr
& ~IntAddrPrefixMask
) {
186 regNum
= MISCREG_TSC
;
189 regNum
= MISCREG_APIC_BASE
;
192 regNum
= MISCREG_MTRRCAP
;
195 regNum
= MISCREG_SYSENTER_CS
;
198 regNum
= MISCREG_SYSENTER_ESP
;
201 regNum
= MISCREG_SYSENTER_EIP
;
204 regNum
= MISCREG_MCG_CAP
;
207 regNum
= MISCREG_MCG_STATUS
;
210 regNum
= MISCREG_MCG_CTL
;
213 regNum
= MISCREG_DEBUG_CTL_MSR
;
216 regNum
= MISCREG_LAST_BRANCH_FROM_IP
;
219 regNum
= MISCREG_LAST_BRANCH_TO_IP
;
222 regNum
= MISCREG_LAST_EXCEPTION_FROM_IP
;
225 regNum
= MISCREG_LAST_EXCEPTION_TO_IP
;
228 regNum
= MISCREG_MTRR_PHYS_BASE_0
;
231 regNum
= MISCREG_MTRR_PHYS_MASK_0
;
234 regNum
= MISCREG_MTRR_PHYS_BASE_1
;
237 regNum
= MISCREG_MTRR_PHYS_MASK_1
;
240 regNum
= MISCREG_MTRR_PHYS_BASE_2
;
243 regNum
= MISCREG_MTRR_PHYS_MASK_2
;
246 regNum
= MISCREG_MTRR_PHYS_BASE_3
;
249 regNum
= MISCREG_MTRR_PHYS_MASK_3
;
252 regNum
= MISCREG_MTRR_PHYS_BASE_4
;
255 regNum
= MISCREG_MTRR_PHYS_MASK_4
;
258 regNum
= MISCREG_MTRR_PHYS_BASE_5
;
261 regNum
= MISCREG_MTRR_PHYS_MASK_5
;
264 regNum
= MISCREG_MTRR_PHYS_BASE_6
;
267 regNum
= MISCREG_MTRR_PHYS_MASK_6
;
270 regNum
= MISCREG_MTRR_PHYS_BASE_7
;
273 regNum
= MISCREG_MTRR_PHYS_MASK_7
;
276 regNum
= MISCREG_MTRR_FIX_64K_00000
;
279 regNum
= MISCREG_MTRR_FIX_16K_80000
;
282 regNum
= MISCREG_MTRR_FIX_16K_A0000
;
285 regNum
= MISCREG_MTRR_FIX_4K_C0000
;
288 regNum
= MISCREG_MTRR_FIX_4K_C8000
;
291 regNum
= MISCREG_MTRR_FIX_4K_D0000
;
294 regNum
= MISCREG_MTRR_FIX_4K_D8000
;
297 regNum
= MISCREG_MTRR_FIX_4K_E0000
;
300 regNum
= MISCREG_MTRR_FIX_4K_E8000
;
303 regNum
= MISCREG_MTRR_FIX_4K_F0000
;
306 regNum
= MISCREG_MTRR_FIX_4K_F8000
;
309 regNum
= MISCREG_PAT
;
312 regNum
= MISCREG_DEF_TYPE
;
315 regNum
= MISCREG_MC0_CTL
;
318 regNum
= MISCREG_MC1_CTL
;
321 regNum
= MISCREG_MC2_CTL
;
324 regNum
= MISCREG_MC3_CTL
;
327 regNum
= MISCREG_MC4_CTL
;
330 regNum
= MISCREG_MC5_CTL
;
333 regNum
= MISCREG_MC6_CTL
;
336 regNum
= MISCREG_MC7_CTL
;
339 regNum
= MISCREG_MC0_STATUS
;
342 regNum
= MISCREG_MC1_STATUS
;
345 regNum
= MISCREG_MC2_STATUS
;
348 regNum
= MISCREG_MC3_STATUS
;
351 regNum
= MISCREG_MC4_STATUS
;
354 regNum
= MISCREG_MC5_STATUS
;
357 regNum
= MISCREG_MC6_STATUS
;
360 regNum
= MISCREG_MC7_STATUS
;
363 regNum
= MISCREG_MC0_ADDR
;
366 regNum
= MISCREG_MC1_ADDR
;
369 regNum
= MISCREG_MC2_ADDR
;
372 regNum
= MISCREG_MC3_ADDR
;
375 regNum
= MISCREG_MC4_ADDR
;
378 regNum
= MISCREG_MC5_ADDR
;
381 regNum
= MISCREG_MC6_ADDR
;
384 regNum
= MISCREG_MC7_ADDR
;
387 regNum
= MISCREG_MC0_MISC
;
390 regNum
= MISCREG_MC1_MISC
;
393 regNum
= MISCREG_MC2_MISC
;
396 regNum
= MISCREG_MC3_MISC
;
399 regNum
= MISCREG_MC4_MISC
;
402 regNum
= MISCREG_MC5_MISC
;
405 regNum
= MISCREG_MC6_MISC
;
408 regNum
= MISCREG_MC7_MISC
;
411 regNum
= MISCREG_EFER
;
414 regNum
= MISCREG_STAR
;
417 regNum
= MISCREG_LSTAR
;
420 regNum
= MISCREG_CSTAR
;
423 regNum
= MISCREG_SF_MASK
;
426 regNum
= MISCREG_FS_BASE
;
429 regNum
= MISCREG_GS_BASE
;
432 regNum
= MISCREG_KERNEL_GS_BASE
;
435 regNum
= MISCREG_TSC_AUX
;
438 regNum
= MISCREG_PERF_EVT_SEL0
;
441 regNum
= MISCREG_PERF_EVT_SEL1
;
444 regNum
= MISCREG_PERF_EVT_SEL2
;
447 regNum
= MISCREG_PERF_EVT_SEL3
;
450 regNum
= MISCREG_PERF_EVT_CTR0
;
453 regNum
= MISCREG_PERF_EVT_CTR1
;
456 regNum
= MISCREG_PERF_EVT_CTR2
;
459 regNum
= MISCREG_PERF_EVT_CTR3
;
462 regNum
= MISCREG_SYSCFG
;
465 regNum
= MISCREG_IORR_BASE0
;
468 regNum
= MISCREG_IORR_BASE1
;
471 regNum
= MISCREG_IORR_MASK0
;
474 regNum
= MISCREG_IORR_MASK1
;
477 regNum
= MISCREG_TOP_MEM
;
480 regNum
= MISCREG_TOP_MEM2
;
483 regNum
= MISCREG_VM_CR
;
486 regNum
= MISCREG_IGNNE
;
489 regNum
= MISCREG_SMM_CTL
;
492 regNum
= MISCREG_VM_HSAVE_PA
;
495 return new GeneralProtection(0);
497 //The index is multiplied by the size of a MiscReg so that
498 //any memory dependence calculations will not see these as
500 req
->setPaddr(regNum
* sizeof(MiscReg
));
502 } else if (prefix
== IntAddrPrefixIO
) {
503 // TODO If CPL > IOPL or in virtual mode, check the I/O permission
504 // bitmap in the TSS.
506 Addr IOPort
= vaddr
& ~IntAddrPrefixMask
;
507 // Make sure the address fits in the expected 16 bit IO address
509 assert(!(IOPort
& ~0xFFFF));
510 if (IOPort
== 0xCF8 && req
->getSize() == 4) {
511 req
->setFlags(Request::MMAPED_IPR
);
512 req
->setPaddr(MISCREG_PCI_CONFIG_ADDRESS
* sizeof(MiscReg
));
513 } else if ((IOPort
& ~mask(2)) == 0xCFC) {
515 tc
->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS
);
516 if (bits(configAddress
, 31, 31)) {
517 req
->setPaddr(PhysAddrPrefixPciConfig
|
518 mbits(configAddress
, 30, 2) |
522 req
->setPaddr(PhysAddrPrefixIO
| IOPort
);
526 panic("Access to unrecognized internal address space %#x.\n",
532 TLB::translate(RequestPtr req
, ThreadContext
*tc
, Translation
*translation
,
533 Mode mode
, bool &delayedResponse
, bool timing
)
535 uint32_t flags
= req
->getFlags();
536 int seg
= flags
& SegmentFlagMask
;
537 bool storeCheck
= flags
& (StoreCheck
<< FlagShift
);
539 // If this is true, we're dealing with a request to a non-memory address
541 if (seg
== SEGMENT_REG_MS
) {
542 return translateInt(req
, tc
);
545 delayedResponse
= false;
546 Addr vaddr
= req
->getVaddr();
547 DPRINTF(TLB
, "Translating vaddr %#x.\n", vaddr
);
549 HandyM5Reg m5Reg
= tc
->readMiscRegNoEffect(MISCREG_M5_REG
);
551 // If protected mode has been enabled...
553 DPRINTF(TLB
, "In protected mode.\n");
554 // If we're not in 64-bit mode, do protection/limit checks
555 if (m5Reg
.mode
!= LongMode
) {
556 DPRINTF(TLB
, "Not in long mode. Checking segment protection.\n");
557 // Check for a NULL segment selector.
558 if (!(seg
== SEGMENT_REG_TSG
|| seg
== SYS_SEGMENT_REG_IDTR
||
559 seg
== SEGMENT_REG_HS
|| seg
== SEGMENT_REG_LS
)
560 && !tc
->readMiscRegNoEffect(MISCREG_SEG_SEL(seg
)))
561 return new GeneralProtection(0);
562 bool expandDown
= false;
563 SegAttr attr
= tc
->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg
));
564 if (seg
>= SEGMENT_REG_ES
&& seg
<= SEGMENT_REG_HS
) {
565 if (!attr
.writable
&& (mode
== Write
|| storeCheck
))
566 return new GeneralProtection(0);
567 if (!attr
.readable
&& mode
== Read
)
568 return new GeneralProtection(0);
569 expandDown
= attr
.expandDown
;
572 Addr base
= tc
->readMiscRegNoEffect(MISCREG_SEG_BASE(seg
));
573 Addr limit
= tc
->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg
));
574 // This assumes we're not in 64 bit mode. If we were, the default
575 // address size is 64 bits, overridable to 32.
577 bool sizeOverride
= (flags
& (AddrSizeFlagBit
<< FlagShift
));
578 SegAttr csAttr
= tc
->readMiscRegNoEffect(MISCREG_CS_ATTR
);
579 if ((csAttr
.defaultSize
&& sizeOverride
) ||
580 (!csAttr
.defaultSize
&& !sizeOverride
))
582 Addr offset
= bits(vaddr
- base
, size
-1, 0);
583 Addr endOffset
= offset
+ req
->getSize() - 1;
585 DPRINTF(TLB
, "Checking an expand down segment.\n");
586 warn_once("Expand down segments are untested.\n");
587 if (offset
<= limit
|| endOffset
<= limit
)
588 return new GeneralProtection(0);
590 if (offset
> limit
|| endOffset
> limit
)
591 return new GeneralProtection(0);
594 // If paging is enabled, do the translation.
596 DPRINTF(TLB
, "Paging enabled.\n");
597 // The vaddr already has the segment base applied.
598 TlbEntry
*entry
= lookup(vaddr
);
601 Fault fault
= walker
->start(tc
, translation
, req
, mode
);
602 if (timing
|| fault
!= NoFault
) {
603 // This gets ignored in atomic mode.
604 delayedResponse
= true;
607 entry
= lookup(vaddr
);
610 DPRINTF(TLB
, "Handling a TLB miss for "
611 "address %#x at pc %#x.\n",
612 vaddr
, tc
->instAddr());
614 Process
*p
= tc
->getProcessPtr();
616 bool success
= p
->pTable
->lookup(vaddr
, newEntry
);
617 if (!success
&& mode
!= Execute
) {
618 p
->checkAndAllocNextPage(vaddr
);
619 success
= p
->pTable
->lookup(vaddr
, newEntry
);
622 return new PageFault(vaddr
, true, mode
, true, false);
624 Addr alignedVaddr
= p
->pTable
->pageAlign(vaddr
);
625 DPRINTF(TLB
, "Mapping %#x to %#x\n", alignedVaddr
,
626 newEntry
.pageStart());
627 entry
= insert(alignedVaddr
, newEntry
);
629 DPRINTF(TLB
, "Miss was serviced.\n");
632 // Do paging protection checks.
633 bool inUser
= (m5Reg
.cpl
== 3 &&
634 !(flags
& (CPL0FlagBit
<< FlagShift
)));
635 if ((inUser
&& !entry
->user
) ||
636 (mode
== Write
&& !entry
->writable
)) {
637 // The page must have been present to get into the TLB in
638 // the first place. We'll assume the reserved bits are
639 // fine even though we're not checking them.
640 return new PageFault(vaddr
, true, mode
, inUser
, false);
642 if (storeCheck
&& !entry
->writable
) {
643 // This would fault if this were a write, so return a page
644 // fault that reflects that happening.
645 return new PageFault(vaddr
, true, Write
, inUser
, false);
649 DPRINTF(TLB
, "Entry found with paddr %#x, "
650 "doing protection checks.\n", entry
->paddr
);
651 Addr paddr
= entry
->paddr
| (vaddr
& (entry
->size
-1));
652 DPRINTF(TLB
, "Translated %#x -> %#x.\n", vaddr
, paddr
);
653 req
->setPaddr(paddr
);
655 //Use the address which already has segmentation applied.
656 DPRINTF(TLB
, "Paging disabled.\n");
657 DPRINTF(TLB
, "Translated %#x -> %#x.\n", vaddr
, vaddr
);
658 req
->setPaddr(vaddr
);
662 DPRINTF(TLB
, "In real mode.\n");
663 DPRINTF(TLB
, "Translated %#x -> %#x.\n", vaddr
, vaddr
);
664 req
->setPaddr(vaddr
);
666 // Check for an access to the local APIC
668 LocalApicBase localApicBase
= tc
->readMiscRegNoEffect(MISCREG_APIC_BASE
);
669 Addr baseAddr
= localApicBase
.base
* PageBytes
;
670 Addr paddr
= req
->getPaddr();
671 if (baseAddr
<= paddr
&& baseAddr
+ PageBytes
> paddr
) {
672 // The Intel developer's manuals say the below restrictions apply,
673 // but the linux kernel, because of a compiler optimization, breaks
677 if (paddr & ((32/8) - 1))
678 return new GeneralProtection(0);
680 if (req->getSize() != (32/8))
681 return new GeneralProtection(0);
683 // Force the access to be uncacheable.
684 req
->setFlags(Request::UNCACHEABLE
);
685 req
->setPaddr(x86LocalAPICAddress(tc
->contextId(), paddr
- baseAddr
));
692 TLB::translateAtomic(RequestPtr req
, ThreadContext
*tc
, Mode mode
)
694 bool delayedResponse
;
695 return TLB::translate(req
, tc
, NULL
, mode
, delayedResponse
, false);
699 TLB::translateTiming(RequestPtr req
, ThreadContext
*tc
,
700 Translation
*translation
, Mode mode
)
702 bool delayedResponse
;
705 TLB::translate(req
, tc
, translation
, mode
, delayedResponse
, true);
706 if (!delayedResponse
)
707 translation
->finish(fault
, req
, tc
, mode
);
713 TLB::doMmuRegRead(ThreadContext
*tc
, Packet
*pkt
)
715 return tc
->getCpuPtr()->ticks(1);
719 TLB::doMmuRegWrite(ThreadContext
*tc
, Packet
*pkt
)
721 return tc
->getCpuPtr()->ticks(1);
727 TLB::serialize(std::ostream
&os
)
732 TLB::unserialize(Checkpoint
*cp
, const std::string
§ion
)
736 /* end namespace X86ISA */ }
739 X86TLBParams::create()
741 return new X86ISA::TLB(this);