2 * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
5 * Redistribution and use of this software in source and binary forms,
6 * with or without modification, are permitted provided that the
7 * following conditions are met:
9 * The software must be used only for Non-Commercial Use which means any
10 * use which is NOT directed to receiving any direct monetary
11 * compensation for, or commercial advantage from such use. Illustrative
12 * examples of non-commercial use are academic research, personal study,
13 * teaching, education and corporate research & development.
14 * Illustrative examples of commercial use are distributing products for
15 * commercial advantage and providing services using the software for
16 * commercial advantage.
18 * If you wish to use this software or functionality therein that may be
19 * covered by patents for commercial use, please contact:
20 * Director of Intellectual Property Licensing
21 * Office of Strategy and Technology
22 * Hewlett-Packard Company
24 * Palo Alto, California 94304
26 * Redistributions of source code must retain the above copyright notice,
27 * this list of conditions and the following disclaimer. Redistributions
28 * in binary form must reproduce the above copyright notice, this list of
29 * conditions and the following disclaimer in the documentation and/or
30 * other materials provided with the distribution. Neither the name of
31 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
32 * contributors may be used to endorse or promote products derived from
33 * this software without specific prior written permission. No right of
34 * sublicense is granted herewith. Derivatives of the software and
35 * output created using the software may be prepared, but only for
36 * Non-Commercial Uses. Derivatives of the software may be shared with
37 * others provided: (i) the others agree to abide by the list of
38 * conditions herein which includes the Non-Commercial Use restrictions;
39 * and (ii) such Derivatives of the software include the above copyright
40 * notice to acknowledge the contribution from this software where
41 * applicable, this list of conditions and the disclaimer below.
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 #include "config/full_system.hh"
62 #include "arch/x86/pagetable.hh"
63 #include "arch/x86/tlb.hh"
64 #include "arch/x86/x86_traits.hh"
65 #include "base/bitfield.hh"
66 #include "base/trace.hh"
67 #include "config/full_system.hh"
68 #include "cpu/thread_context.hh"
69 #include "cpu/base.hh"
70 #include "mem/packet_access.hh"
71 #include "mem/request.hh"
74 #include "arch/x86/pagetable_walker.hh"
79 TLB::TLB(const Params
*p
) : BaseTLB(p
), configAddress(0), size(p
->size
)
81 tlb
= new TlbEntry
[size
];
82 std::memset(tlb
, 0, sizeof(TlbEntry
) * size
);
84 for (int x
= 0; x
< size
; x
++)
85 freeList
.push_back(&tlb
[x
]);
94 TLB::insert(Addr vpn
, TlbEntry
&entry
)
96 //TODO Deal with conflicting entries
98 TlbEntry
*newEntry
= NULL
;
99 if (!freeList
.empty()) {
100 newEntry
= freeList
.front();
101 freeList
.pop_front();
103 newEntry
= entryList
.back();
104 entryList
.pop_back();
107 newEntry
->vaddr
= vpn
;
108 entryList
.push_front(newEntry
);
111 TLB::EntryList::iterator
112 TLB::lookupIt(Addr va
, bool update_lru
)
114 //TODO make this smarter at some point
115 EntryList::iterator entry
;
116 for (entry
= entryList
.begin(); entry
!= entryList
.end(); entry
++) {
117 if ((*entry
)->vaddr
<= va
&& (*entry
)->vaddr
+ (*entry
)->size
> va
) {
118 DPRINTF(TLB
, "Matched vaddr %#x to entry starting at %#x "
119 "with size %#x.\n", va
, (*entry
)->vaddr
, (*entry
)->size
);
121 entryList
.push_front(*entry
);
122 entryList
.erase(entry
);
123 entry
= entryList
.begin();
132 TLB::lookup(Addr va
, bool update_lru
)
134 EntryList::iterator entry
= lookupIt(va
, update_lru
);
135 if (entry
== entryList
.end())
143 TLB::walk(ThreadContext
* _tc
, Addr vaddr
)
145 walker
->start(_tc
, vaddr
);
152 DPRINTF(TLB
, "Invalidating all entries.\n");
153 while (!entryList
.empty()) {
154 TlbEntry
*entry
= entryList
.front();
155 entryList
.pop_front();
156 freeList
.push_back(entry
);
161 TLB::setConfigAddress(uint32_t addr
)
163 configAddress
= addr
;
167 TLB::invalidateNonGlobal()
169 DPRINTF(TLB
, "Invalidating all non global entries.\n");
170 EntryList::iterator entryIt
;
171 for (entryIt
= entryList
.begin(); entryIt
!= entryList
.end();) {
172 if (!(*entryIt
)->global
) {
173 freeList
.push_back(*entryIt
);
174 entryList
.erase(entryIt
++);
182 TLB::demapPage(Addr va
, uint64_t asn
)
184 EntryList::iterator entry
= lookupIt(va
, false);
185 if (entry
!= entryList
.end()) {
186 freeList
.push_back(*entry
);
187 entryList
.erase(entry
);
191 template<class TlbFault
>
193 TLB::translate(RequestPtr
&req
, ThreadContext
*tc
, bool write
, bool execute
)
195 Addr vaddr
= req
->getVaddr();
196 DPRINTF(TLB
, "Translating vaddr %#x.\n", vaddr
);
197 uint32_t flags
= req
->getFlags();
198 bool storeCheck
= flags
& StoreCheck
;
200 int seg
= flags
& mask(4);
202 //XXX Junk code to surpress the warning
205 // If this is true, we're dealing with a request to read an internal
207 if (seg
== SEGMENT_REG_MS
) {
208 DPRINTF(TLB
, "Addresses references internal memory.\n");
209 Addr prefix
= vaddr
& IntAddrPrefixMask
;
210 if (prefix
== IntAddrPrefixCPUID
) {
211 panic("CPUID memory space not yet implemented!\n");
212 } else if (prefix
== IntAddrPrefixMSR
) {
213 req
->setMmapedIpr(true);
215 switch (vaddr
& ~IntAddrPrefixMask
) {
217 regNum
= MISCREG_TSC
;
220 regNum
= MISCREG_APIC_BASE
;
223 regNum
= MISCREG_MTRRCAP
;
226 regNum
= MISCREG_SYSENTER_CS
;
229 regNum
= MISCREG_SYSENTER_ESP
;
232 regNum
= MISCREG_SYSENTER_EIP
;
235 regNum
= MISCREG_MCG_CAP
;
238 regNum
= MISCREG_MCG_STATUS
;
241 regNum
= MISCREG_MCG_CTL
;
244 regNum
= MISCREG_DEBUG_CTL_MSR
;
247 regNum
= MISCREG_LAST_BRANCH_FROM_IP
;
250 regNum
= MISCREG_LAST_BRANCH_TO_IP
;
253 regNum
= MISCREG_LAST_EXCEPTION_FROM_IP
;
256 regNum
= MISCREG_LAST_EXCEPTION_TO_IP
;
259 regNum
= MISCREG_MTRR_PHYS_BASE_0
;
262 regNum
= MISCREG_MTRR_PHYS_MASK_0
;
265 regNum
= MISCREG_MTRR_PHYS_BASE_1
;
268 regNum
= MISCREG_MTRR_PHYS_MASK_1
;
271 regNum
= MISCREG_MTRR_PHYS_BASE_2
;
274 regNum
= MISCREG_MTRR_PHYS_MASK_2
;
277 regNum
= MISCREG_MTRR_PHYS_BASE_3
;
280 regNum
= MISCREG_MTRR_PHYS_MASK_3
;
283 regNum
= MISCREG_MTRR_PHYS_BASE_4
;
286 regNum
= MISCREG_MTRR_PHYS_MASK_4
;
289 regNum
= MISCREG_MTRR_PHYS_BASE_5
;
292 regNum
= MISCREG_MTRR_PHYS_MASK_5
;
295 regNum
= MISCREG_MTRR_PHYS_BASE_6
;
298 regNum
= MISCREG_MTRR_PHYS_MASK_6
;
301 regNum
= MISCREG_MTRR_PHYS_BASE_7
;
304 regNum
= MISCREG_MTRR_PHYS_MASK_7
;
307 regNum
= MISCREG_MTRR_FIX_64K_00000
;
310 regNum
= MISCREG_MTRR_FIX_16K_80000
;
313 regNum
= MISCREG_MTRR_FIX_16K_A0000
;
316 regNum
= MISCREG_MTRR_FIX_4K_C0000
;
319 regNum
= MISCREG_MTRR_FIX_4K_C8000
;
322 regNum
= MISCREG_MTRR_FIX_4K_D0000
;
325 regNum
= MISCREG_MTRR_FIX_4K_D8000
;
328 regNum
= MISCREG_MTRR_FIX_4K_E0000
;
331 regNum
= MISCREG_MTRR_FIX_4K_E8000
;
334 regNum
= MISCREG_MTRR_FIX_4K_F0000
;
337 regNum
= MISCREG_MTRR_FIX_4K_F8000
;
340 regNum
= MISCREG_PAT
;
343 regNum
= MISCREG_DEF_TYPE
;
346 regNum
= MISCREG_MC0_CTL
;
349 regNum
= MISCREG_MC1_CTL
;
352 regNum
= MISCREG_MC2_CTL
;
355 regNum
= MISCREG_MC3_CTL
;
358 regNum
= MISCREG_MC4_CTL
;
361 regNum
= MISCREG_MC0_STATUS
;
364 regNum
= MISCREG_MC1_STATUS
;
367 regNum
= MISCREG_MC2_STATUS
;
370 regNum
= MISCREG_MC3_STATUS
;
373 regNum
= MISCREG_MC4_STATUS
;
376 regNum
= MISCREG_MC0_ADDR
;
379 regNum
= MISCREG_MC1_ADDR
;
382 regNum
= MISCREG_MC2_ADDR
;
385 regNum
= MISCREG_MC3_ADDR
;
388 regNum
= MISCREG_MC4_ADDR
;
391 regNum
= MISCREG_MC0_MISC
;
394 regNum
= MISCREG_MC1_MISC
;
397 regNum
= MISCREG_MC2_MISC
;
400 regNum
= MISCREG_MC3_MISC
;
403 regNum
= MISCREG_MC4_MISC
;
406 regNum
= MISCREG_EFER
;
409 regNum
= MISCREG_STAR
;
412 regNum
= MISCREG_LSTAR
;
415 regNum
= MISCREG_CSTAR
;
418 regNum
= MISCREG_SF_MASK
;
421 regNum
= MISCREG_FS_BASE
;
424 regNum
= MISCREG_GS_BASE
;
427 regNum
= MISCREG_KERNEL_GS_BASE
;
430 regNum
= MISCREG_TSC_AUX
;
433 regNum
= MISCREG_PERF_EVT_SEL0
;
436 regNum
= MISCREG_PERF_EVT_SEL1
;
439 regNum
= MISCREG_PERF_EVT_SEL2
;
442 regNum
= MISCREG_PERF_EVT_SEL3
;
445 regNum
= MISCREG_PERF_EVT_CTR0
;
448 regNum
= MISCREG_PERF_EVT_CTR1
;
451 regNum
= MISCREG_PERF_EVT_CTR2
;
454 regNum
= MISCREG_PERF_EVT_CTR3
;
457 regNum
= MISCREG_SYSCFG
;
460 regNum
= MISCREG_IORR_BASE0
;
463 regNum
= MISCREG_IORR_BASE1
;
466 regNum
= MISCREG_IORR_MASK0
;
469 regNum
= MISCREG_IORR_MASK1
;
472 regNum
= MISCREG_TOP_MEM
;
475 regNum
= MISCREG_TOP_MEM2
;
478 regNum
= MISCREG_VM_CR
;
481 regNum
= MISCREG_IGNNE
;
484 regNum
= MISCREG_SMM_CTL
;
487 regNum
= MISCREG_VM_HSAVE_PA
;
490 return new GeneralProtection(0);
492 //The index is multiplied by the size of a MiscReg so that
493 //any memory dependence calculations will not see these as
495 req
->setPaddr(regNum
* sizeof(MiscReg
));
497 } else if (prefix
== IntAddrPrefixIO
) {
498 // TODO If CPL > IOPL or in virtual mode, check the I/O permission
499 // bitmap in the TSS.
501 Addr IOPort
= vaddr
& ~IntAddrPrefixMask
;
502 // Make sure the address fits in the expected 16 bit IO address
504 assert(!(IOPort
& ~0xFFFF));
505 if (IOPort
== 0xCF8 && req
->getSize() == 4) {
506 req
->setMmapedIpr(true);
507 req
->setPaddr(MISCREG_PCI_CONFIG_ADDRESS
* sizeof(MiscReg
));
508 } else if ((IOPort
& ~mask(2)) == 0xCFC) {
510 tc
->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS
);
511 if (bits(configAddress
, 31, 31)) {
512 req
->setPaddr(PhysAddrPrefixPciConfig
|
513 bits(configAddress
, 30, 0));
516 req
->setPaddr(PhysAddrPrefixIO
| IOPort
);
520 panic("Access to unrecognized internal address space %#x.\n",
525 // Get cr0. This will tell us how to do translation. We'll assume it was
526 // verified to be correct and consistent when set.
527 CR0 cr0
= tc
->readMiscRegNoEffect(MISCREG_CR0
);
529 // If protected mode has been enabled...
531 DPRINTF(TLB
, "In protected mode.\n");
532 Efer efer
= tc
->readMiscRegNoEffect(MISCREG_EFER
);
533 SegAttr csAttr
= tc
->readMiscRegNoEffect(MISCREG_CS_ATTR
);
534 // If we're not in 64-bit mode, do protection/limit checks
535 if (!efer
.lma
|| !csAttr
.longMode
) {
536 DPRINTF(TLB
, "Not in long mode. Checking segment protection.\n");
537 SegAttr attr
= tc
->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg
));
538 if (!attr
.writable
&& write
)
539 return new GeneralProtection(0);
540 if (!attr
.readable
&& !write
&& !execute
)
541 return new GeneralProtection(0);
542 Addr base
= tc
->readMiscRegNoEffect(MISCREG_SEG_BASE(seg
));
543 Addr limit
= tc
->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg
));
544 if (!attr
.expandDown
) {
545 DPRINTF(TLB
, "Checking an expand down segment.\n");
546 // We don't have to worry about the access going around the
547 // end of memory because accesses will be broken up into
548 // pieces at boundaries aligned on sizes smaller than an
549 // entire address space. We do have to worry about the limit
550 // being less than the base.
552 if (limit
< vaddr
+ req
->getSize() && vaddr
< base
)
553 return new GeneralProtection(0);
555 if (limit
< vaddr
+ req
->getSize())
556 return new GeneralProtection(0);
560 if (vaddr
<= limit
|| vaddr
+ req
->getSize() >= base
)
561 return new GeneralProtection(0);
563 if (vaddr
<= limit
&& vaddr
+ req
->getSize() >= base
)
564 return new GeneralProtection(0);
568 // If paging is enabled, do the translation.
570 DPRINTF(TLB
, "Paging enabled.\n");
571 // The vaddr already has the segment base applied.
572 TlbEntry
*entry
= lookup(vaddr
);
574 return new TlbFault(vaddr
);
576 // Do paging protection checks.
577 DPRINTF(TLB
, "Entry found with paddr %#x, doing protection checks.\n", entry
->paddr
);
578 Addr paddr
= entry
->paddr
| (vaddr
& (entry
->size
-1));
579 DPRINTF(TLB
, "Translated %#x -> %#x.\n", vaddr
, paddr
);
580 req
->setPaddr(paddr
);
583 //Use the address which already has segmentation applied.
584 DPRINTF(TLB
, "Paging disabled.\n");
585 DPRINTF(TLB
, "Translated %#x -> %#x.\n", vaddr
, vaddr
);
586 req
->setPaddr(vaddr
);
590 DPRINTF(TLB
, "In real mode.\n");
591 DPRINTF(TLB
, "Translated %#x -> %#x.\n", vaddr
, vaddr
);
592 req
->setPaddr(vaddr
);
594 // Check for an access to the local APIC
596 LocalApicBase localApicBase
= tc
->readMiscRegNoEffect(MISCREG_APIC_BASE
);
597 Addr baseAddr
= localApicBase
.base
<< 12;
598 Addr paddr
= req
->getPaddr();
599 if (baseAddr
<= paddr
&& baseAddr
+ (1 << 12) > paddr
) {
600 req
->setMmapedIpr(true);
601 // The Intel developer's manuals say the below restrictions apply,
602 // but the linux kernel, because of a compiler optimization, breaks
606 if (paddr & ((32/8) - 1))
607 return new GeneralProtection(0);
609 if (req->getSize() != (32/8))
610 return new GeneralProtection(0);
613 //Make sure we're at least only accessing one register.
614 if ((paddr
& ~mask(3)) != ((paddr
+ req
->getSize()) & ~mask(3)))
615 panic("Accessed more than one register at a time in the APIC!\n");
617 Addr offset
= paddr
& mask(3);
619 switch (paddr
- baseAddr
)
622 regNum
= MISCREG_APIC_ID
;
625 regNum
= MISCREG_APIC_VERSION
;
628 regNum
= MISCREG_APIC_TASK_PRIORITY
;
631 regNum
= MISCREG_APIC_ARBITRATION_PRIORITY
;
634 regNum
= MISCREG_APIC_PROCESSOR_PRIORITY
;
637 regNum
= MISCREG_APIC_EOI
;
640 regNum
= MISCREG_APIC_LOGICAL_DESTINATION
;
643 regNum
= MISCREG_APIC_DESTINATION_FORMAT
;
646 regNum
= MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR
;
664 regNum
= MISCREG_APIC_IN_SERVICE(
665 (paddr
- baseAddr
- 0x100) / 0x8);
683 regNum
= MISCREG_APIC_TRIGGER_MODE(
684 (paddr
- baseAddr
- 0x180) / 0x8);
702 regNum
= MISCREG_APIC_INTERRUPT_REQUEST(
703 (paddr
- baseAddr
- 0x200) / 0x8);
706 regNum
= MISCREG_APIC_ERROR_STATUS
;
709 regNum
= MISCREG_APIC_INTERRUPT_COMMAND_LOW
;
712 regNum
= MISCREG_APIC_INTERRUPT_COMMAND_HIGH
;
715 regNum
= MISCREG_APIC_LVT_TIMER
;
718 regNum
= MISCREG_APIC_LVT_THERMAL_SENSOR
;
721 regNum
= MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS
;
724 regNum
= MISCREG_APIC_LVT_LINT0
;
727 regNum
= MISCREG_APIC_LVT_LINT1
;
730 regNum
= MISCREG_APIC_LVT_ERROR
;
733 regNum
= MISCREG_APIC_INITIAL_COUNT
;
736 regNum
= MISCREG_APIC_CURRENT_COUNT
;
739 regNum
= MISCREG_APIC_DIVIDE_COUNT
;
742 // A reserved register field.
743 return new GeneralProtection(0);
746 req
->setPaddr(regNum
* sizeof(MiscReg
) + offset
);
753 DTB::translate(RequestPtr
&req
, ThreadContext
*tc
, bool write
)
755 return TLB::translate
<FakeDTLBFault
>(req
, tc
, write
, false);
759 ITB::translate(RequestPtr
&req
, ThreadContext
*tc
)
761 return TLB::translate
<FakeITLBFault
>(req
, tc
, false, true);
767 DTB::doMmuRegRead(ThreadContext
*tc
, Packet
*pkt
)
769 return tc
->getCpuPtr()->ticks(1);
773 DTB::doMmuRegWrite(ThreadContext
*tc
, Packet
*pkt
)
775 return tc
->getCpuPtr()->ticks(1);
781 TLB::serialize(std::ostream
&os
)
786 TLB::unserialize(Checkpoint
*cp
, const std::string
§ion
)
791 DTB::serialize(std::ostream
&os
)
797 DTB::unserialize(Checkpoint
*cp
, const std::string
§ion
)
799 TLB::unserialize(cp
, section
);
802 /* end namespace X86ISA */ }
805 X86ITBParams::create()
807 return new X86ISA::ITB(this);
811 X86DTBParams::create()
813 return new X86ISA::DTB(this);