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 "arch/x86/insts/microldstop.hh"
43 #include "arch/x86/regs/misc.hh"
44 #include "arch/x86/regs/msr.hh"
45 #include "arch/x86/faults.hh"
46 #include "arch/x86/pagetable.hh"
47 #include "arch/x86/pagetable_walker.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 "cpu/base.hh"
53 #include "cpu/thread_context.hh"
54 #include "debug/TLB.hh"
55 #include "mem/packet_access.hh"
56 #include "mem/page_table.hh"
57 #include "mem/request.hh"
58 #include "sim/full_system.hh"
59 #include "sim/process.hh"
63 TLB::TLB(const Params
*p
) : BaseTLB(p
), configAddress(0), size(p
->size
),
67 fatal("TLBs must have a non-zero size.\n");
68 tlb
= new TlbEntry
[size
];
69 std::memset(tlb
, 0, sizeof(TlbEntry
) * size
);
71 for (int x
= 0; x
< size
; x
++) {
72 tlb
[x
].trieHandle
= NULL
;
73 freeList
.push_back(&tlb
[x
]);
83 // Find the entry with the lowest (and hence least recently updated)
87 for (unsigned i
= 1; i
< size
; i
++) {
88 if (tlb
[i
].lruSeq
< tlb
[lru
].lruSeq
)
92 assert(tlb
[lru
].trieHandle
);
93 trie
.remove(tlb
[lru
].trieHandle
);
94 tlb
[lru
].trieHandle
= NULL
;
95 freeList
.push_back(&tlb
[lru
]);
99 TLB::insert(Addr vpn
, TlbEntry
&entry
)
101 // If somebody beat us to it, just use that existing entry.
102 TlbEntry
*newEntry
= trie
.lookup(vpn
);
104 assert(newEntry
->vaddr
= vpn
);
108 if (freeList
.empty())
111 newEntry
= freeList
.front();
112 freeList
.pop_front();
115 newEntry
->lruSeq
= nextSeq();
116 newEntry
->vaddr
= vpn
;
117 newEntry
->trieHandle
=
118 trie
.insert(vpn
, TlbEntryTrie::MaxBits
- entry
.logBytes
, newEntry
);
123 TLB::lookup(Addr va
, bool update_lru
)
125 TlbEntry
*entry
= trie
.lookup(va
);
126 if (entry
&& update_lru
)
127 entry
->lruSeq
= nextSeq();
134 DPRINTF(TLB
, "Invalidating all entries.\n");
135 for (unsigned i
= 0; i
< size
; i
++) {
136 if (tlb
[i
].trieHandle
) {
137 trie
.remove(tlb
[i
].trieHandle
);
138 tlb
[i
].trieHandle
= NULL
;
139 freeList
.push_back(&tlb
[i
]);
145 TLB::setConfigAddress(uint32_t addr
)
147 configAddress
= addr
;
151 TLB::invalidateNonGlobal()
153 DPRINTF(TLB
, "Invalidating all non global entries.\n");
154 for (unsigned i
= 0; i
< size
; i
++) {
155 if (tlb
[i
].trieHandle
&& !tlb
[i
].global
) {
156 trie
.remove(tlb
[i
].trieHandle
);
157 tlb
[i
].trieHandle
= NULL
;
158 freeList
.push_back(&tlb
[i
]);
164 TLB::demapPage(Addr va
, uint64_t asn
)
166 TlbEntry
*entry
= trie
.lookup(va
);
168 trie
.remove(entry
->trieHandle
);
169 entry
->trieHandle
= NULL
;
170 freeList
.push_back(entry
);
175 TLB::translateInt(RequestPtr req
, ThreadContext
*tc
)
177 DPRINTF(TLB
, "Addresses references internal memory.\n");
178 Addr vaddr
= req
->getVaddr();
179 Addr prefix
= (vaddr
>> 3) & IntAddrPrefixMask
;
180 if (prefix
== IntAddrPrefixCPUID
) {
181 panic("CPUID memory space not yet implemented!\n");
182 } else if (prefix
== IntAddrPrefixMSR
) {
183 vaddr
= (vaddr
>> 3) & ~IntAddrPrefixMask
;
184 req
->setFlags(Request::MMAPPED_IPR
);
187 if (!msrAddrToIndex(regNum
, vaddr
))
188 return new GeneralProtection(0);
190 //The index is multiplied by the size of a MiscReg so that
191 //any memory dependence calculations will not see these as
193 req
->setPaddr((Addr
)regNum
* sizeof(MiscReg
));
195 } else if (prefix
== IntAddrPrefixIO
) {
196 // TODO If CPL > IOPL or in virtual mode, check the I/O permission
197 // bitmap in the TSS.
199 Addr IOPort
= vaddr
& ~IntAddrPrefixMask
;
200 // Make sure the address fits in the expected 16 bit IO address
202 assert(!(IOPort
& ~0xFFFF));
203 if (IOPort
== 0xCF8 && req
->getSize() == 4) {
204 req
->setFlags(Request::MMAPPED_IPR
);
205 req
->setPaddr(MISCREG_PCI_CONFIG_ADDRESS
* sizeof(MiscReg
));
206 } else if ((IOPort
& ~mask(2)) == 0xCFC) {
207 req
->setFlags(Request::UNCACHEABLE
);
209 tc
->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS
);
210 if (bits(configAddress
, 31, 31)) {
211 req
->setPaddr(PhysAddrPrefixPciConfig
|
212 mbits(configAddress
, 30, 2) |
215 req
->setPaddr(PhysAddrPrefixIO
| IOPort
);
218 req
->setFlags(Request::UNCACHEABLE
);
219 req
->setPaddr(PhysAddrPrefixIO
| IOPort
);
223 panic("Access to unrecognized internal address space %#x.\n",
229 TLB::translate(RequestPtr req
, ThreadContext
*tc
, Translation
*translation
,
230 Mode mode
, bool &delayedResponse
, bool timing
)
232 uint32_t flags
= req
->getFlags();
233 int seg
= flags
& SegmentFlagMask
;
234 bool storeCheck
= flags
& (StoreCheck
<< FlagShift
);
236 delayedResponse
= false;
238 // If this is true, we're dealing with a request to a non-memory address
240 if (seg
== SEGMENT_REG_MS
) {
241 return translateInt(req
, tc
);
244 Addr vaddr
= req
->getVaddr();
245 DPRINTF(TLB
, "Translating vaddr %#x.\n", vaddr
);
247 HandyM5Reg m5Reg
= tc
->readMiscRegNoEffect(MISCREG_M5_REG
);
249 // If protected mode has been enabled...
251 DPRINTF(TLB
, "In protected mode.\n");
252 // If we're not in 64-bit mode, do protection/limit checks
253 if (m5Reg
.mode
!= LongMode
) {
254 DPRINTF(TLB
, "Not in long mode. Checking segment protection.\n");
255 // Check for a NULL segment selector.
256 if (!(seg
== SEGMENT_REG_TSG
|| seg
== SYS_SEGMENT_REG_IDTR
||
257 seg
== SEGMENT_REG_HS
|| seg
== SEGMENT_REG_LS
)
258 && !tc
->readMiscRegNoEffect(MISCREG_SEG_SEL(seg
)))
259 return new GeneralProtection(0);
260 bool expandDown
= false;
261 SegAttr attr
= tc
->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg
));
262 if (seg
>= SEGMENT_REG_ES
&& seg
<= SEGMENT_REG_HS
) {
263 if (!attr
.writable
&& (mode
== Write
|| storeCheck
))
264 return new GeneralProtection(0);
265 if (!attr
.readable
&& mode
== Read
)
266 return new GeneralProtection(0);
267 expandDown
= attr
.expandDown
;
270 Addr base
= tc
->readMiscRegNoEffect(MISCREG_SEG_BASE(seg
));
271 Addr limit
= tc
->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg
));
272 // This assumes we're not in 64 bit mode. If we were, the default
273 // address size is 64 bits, overridable to 32.
275 bool sizeOverride
= (flags
& (AddrSizeFlagBit
<< FlagShift
));
276 SegAttr csAttr
= tc
->readMiscRegNoEffect(MISCREG_CS_ATTR
);
277 if ((csAttr
.defaultSize
&& sizeOverride
) ||
278 (!csAttr
.defaultSize
&& !sizeOverride
))
280 Addr offset
= bits(vaddr
- base
, size
-1, 0);
281 Addr endOffset
= offset
+ req
->getSize() - 1;
283 DPRINTF(TLB
, "Checking an expand down segment.\n");
284 warn_once("Expand down segments are untested.\n");
285 if (offset
<= limit
|| endOffset
<= limit
)
286 return new GeneralProtection(0);
288 if (offset
> limit
|| endOffset
> limit
)
289 return new GeneralProtection(0);
292 if (m5Reg
.mode
!= LongMode
||
293 (flags
& (AddrSizeFlagBit
<< FlagShift
)))
295 // If paging is enabled, do the translation.
297 DPRINTF(TLB
, "Paging enabled.\n");
298 // The vaddr already has the segment base applied.
299 TlbEntry
*entry
= lookup(vaddr
);
302 Fault fault
= walker
->start(tc
, translation
, req
, mode
);
303 if (timing
|| fault
!= NoFault
) {
304 // This gets ignored in atomic mode.
305 delayedResponse
= true;
308 entry
= lookup(vaddr
);
311 DPRINTF(TLB
, "Handling a TLB miss for "
312 "address %#x at pc %#x.\n",
313 vaddr
, tc
->instAddr());
315 Process
*p
= tc
->getProcessPtr();
317 bool success
= p
->pTable
->lookup(vaddr
, newEntry
);
318 if (!success
&& mode
!= Execute
) {
319 // Check if we just need to grow the stack.
320 if (p
->fixupStackFault(vaddr
)) {
321 // If we did, lookup the entry for the new page.
322 success
= p
->pTable
->lookup(vaddr
, newEntry
);
326 return new PageFault(vaddr
, true, mode
, true, false);
328 Addr alignedVaddr
= p
->pTable
->pageAlign(vaddr
);
329 DPRINTF(TLB
, "Mapping %#x to %#x\n", alignedVaddr
,
330 newEntry
.pageStart());
331 entry
= insert(alignedVaddr
, newEntry
);
333 DPRINTF(TLB
, "Miss was serviced.\n");
337 DPRINTF(TLB
, "Entry found with paddr %#x, "
338 "doing protection checks.\n", entry
->paddr
);
339 // Do paging protection checks.
340 bool inUser
= (m5Reg
.cpl
== 3 &&
341 !(flags
& (CPL0FlagBit
<< FlagShift
)));
342 CR0 cr0
= tc
->readMiscRegNoEffect(MISCREG_CR0
);
343 bool badWrite
= (!entry
->writable
&& (inUser
|| cr0
.wp
));
344 if ((inUser
&& !entry
->user
) || (mode
== Write
&& badWrite
)) {
345 // The page must have been present to get into the TLB in
346 // the first place. We'll assume the reserved bits are
347 // fine even though we're not checking them.
348 return new PageFault(vaddr
, true, mode
, inUser
, false);
350 if (storeCheck
&& badWrite
) {
351 // This would fault if this were a write, so return a page
352 // fault that reflects that happening.
353 return new PageFault(vaddr
, true, Write
, inUser
, false);
356 Addr paddr
= entry
->paddr
| (vaddr
& mask(entry
->logBytes
));
357 DPRINTF(TLB
, "Translated %#x -> %#x.\n", vaddr
, paddr
);
358 req
->setPaddr(paddr
);
359 if (entry
->uncacheable
)
360 req
->setFlags(Request::UNCACHEABLE
);
362 //Use the address which already has segmentation applied.
363 DPRINTF(TLB
, "Paging disabled.\n");
364 DPRINTF(TLB
, "Translated %#x -> %#x.\n", vaddr
, vaddr
);
365 req
->setPaddr(vaddr
);
369 DPRINTF(TLB
, "In real mode.\n");
370 DPRINTF(TLB
, "Translated %#x -> %#x.\n", vaddr
, vaddr
);
371 req
->setPaddr(vaddr
);
373 // Check for an access to the local APIC
375 LocalApicBase localApicBase
=
376 tc
->readMiscRegNoEffect(MISCREG_APIC_BASE
);
377 Addr baseAddr
= localApicBase
.base
* PageBytes
;
378 Addr paddr
= req
->getPaddr();
379 if (baseAddr
<= paddr
&& baseAddr
+ PageBytes
> paddr
) {
380 // The Intel developer's manuals say the below restrictions apply,
381 // but the linux kernel, because of a compiler optimization, breaks
385 if (paddr & ((32/8) - 1))
386 return new GeneralProtection(0);
388 if (req->getSize() != (32/8))
389 return new GeneralProtection(0);
391 // Force the access to be uncacheable.
392 req
->setFlags(Request::UNCACHEABLE
);
393 req
->setPaddr(x86LocalAPICAddress(tc
->contextId(),
401 TLB::translateAtomic(RequestPtr req
, ThreadContext
*tc
, Mode mode
)
403 bool delayedResponse
;
404 return TLB::translate(req
, tc
, NULL
, mode
, delayedResponse
, false);
408 TLB::translateTiming(RequestPtr req
, ThreadContext
*tc
,
409 Translation
*translation
, Mode mode
)
411 bool delayedResponse
;
414 TLB::translate(req
, tc
, translation
, mode
, delayedResponse
, true);
415 if (!delayedResponse
)
416 translation
->finish(fault
, req
, tc
, mode
);
420 TLB::translateFunctional(RequestPtr req
, ThreadContext
*tc
, Mode mode
)
422 panic("Not implemented\n");
433 TLB::serialize(std::ostream
&os
)
438 TLB::unserialize(Checkpoint
*cp
, const std::string
§ion
)
445 return &walker
->getMasterPort("port");
448 } // namespace X86ISA
451 X86TLBParams::create()
453 return new X86ISA::TLB(this);