X86: Reorganize segmentation and implement segment selector movs.
[gem5.git] / src / arch / x86 / tlb.cc
1 /*
2 * Copyright (c) 2007 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
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:
8 *
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.
17 *
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
23 * 1501 Page Mill Road
24 * Palo Alto, California 94304
25 *
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.
42 *
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.
54 *
55 * Authors: Gabe Black
56 */
57
58 #include <cstring>
59
60 #include "config/full_system.hh"
61
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"
72
73 #if FULL_SYSTEM
74 #include "arch/x86/pagetable_walker.hh"
75 #endif
76
77 namespace X86ISA {
78
79 TLB::TLB(const Params *p) : SimObject(p), size(p->size)
80 {
81 tlb = new TlbEntry[size];
82 std::memset(tlb, 0, sizeof(TlbEntry) * size);
83
84 for (int x = 0; x < size; x++)
85 freeList.push_back(&tlb[x]);
86
87 #if FULL_SYSTEM
88 walker = p->walker;
89 walker->setTLB(this);
90 #endif
91 }
92
93 void
94 TLB::insert(Addr vpn, TlbEntry &entry)
95 {
96 //TODO Deal with conflicting entries
97
98 TlbEntry *newEntry = NULL;
99 if (!freeList.empty()) {
100 newEntry = freeList.front();
101 freeList.pop_front();
102 } else {
103 newEntry = entryList.back();
104 entryList.pop_back();
105 }
106 *newEntry = entry;
107 newEntry->vaddr = vpn;
108 entryList.push_front(newEntry);
109 }
110
111 TlbEntry *
112 TLB::lookup(Addr va, bool update_lru)
113 {
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);
120 TlbEntry *e = *entry;
121 if (update_lru) {
122 entryList.erase(entry);
123 entryList.push_front(e);
124 }
125 return e;
126 }
127 }
128 return NULL;
129 }
130
131 #if FULL_SYSTEM
132 void
133 TLB::walk(ThreadContext * _tc, Addr vaddr)
134 {
135 walker->start(_tc, vaddr);
136 }
137 #endif
138
139 void
140 TLB::invalidateAll()
141 {
142 DPRINTF(TLB, "Invalidating all entries.\n");
143 while (!entryList.empty()) {
144 TlbEntry *entry = entryList.front();
145 entryList.pop_front();
146 freeList.push_back(entry);
147 }
148 }
149
150 void
151 TLB::invalidateNonGlobal()
152 {
153 DPRINTF(TLB, "Invalidating all non global entries.\n");
154 EntryList::iterator entryIt;
155 for (entryIt = entryList.begin(); entryIt != entryList.end();) {
156 if (!(*entryIt)->global) {
157 freeList.push_back(*entryIt);
158 entryList.erase(entryIt++);
159 } else {
160 entryIt++;
161 }
162 }
163 }
164
165 void
166 TLB::demapPage(Addr va)
167 {
168 }
169
170 template<class TlbFault>
171 Fault
172 TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
173 {
174 Addr vaddr = req->getVaddr();
175 DPRINTF(TLB, "Translating vaddr %#x.\n", vaddr);
176 uint32_t flags = req->getFlags();
177 bool storeCheck = flags & StoreCheck;
178
179 int seg = flags & mask(4);
180
181 //XXX Junk code to surpress the warning
182 if (storeCheck);
183
184 // If this is true, we're dealing with a request to read an internal
185 // value.
186 if (seg == SEGMENT_REG_MS) {
187 DPRINTF(TLB, "Addresses references internal memory.\n");
188 Addr prefix = vaddr & IntAddrPrefixMask;
189 if (prefix == IntAddrPrefixCPUID) {
190 panic("CPUID memory space not yet implemented!\n");
191 } else if (prefix == IntAddrPrefixMSR) {
192 req->setMmapedIpr(true);
193 Addr regNum = 0;
194 switch (vaddr & ~IntAddrPrefixMask) {
195 case 0x10:
196 regNum = MISCREG_TSC;
197 break;
198 case 0xFE:
199 regNum = MISCREG_MTRRCAP;
200 break;
201 case 0x174:
202 regNum = MISCREG_SYSENTER_CS;
203 break;
204 case 0x175:
205 regNum = MISCREG_SYSENTER_ESP;
206 break;
207 case 0x176:
208 regNum = MISCREG_SYSENTER_EIP;
209 break;
210 case 0x179:
211 regNum = MISCREG_MCG_CAP;
212 break;
213 case 0x17A:
214 regNum = MISCREG_MCG_STATUS;
215 break;
216 case 0x17B:
217 regNum = MISCREG_MCG_CTL;
218 break;
219 case 0x1D9:
220 regNum = MISCREG_DEBUG_CTL_MSR;
221 break;
222 case 0x1DB:
223 regNum = MISCREG_LAST_BRANCH_FROM_IP;
224 break;
225 case 0x1DC:
226 regNum = MISCREG_LAST_BRANCH_TO_IP;
227 break;
228 case 0x1DD:
229 regNum = MISCREG_LAST_EXCEPTION_FROM_IP;
230 break;
231 case 0x1DE:
232 regNum = MISCREG_LAST_EXCEPTION_TO_IP;
233 break;
234 case 0x200:
235 regNum = MISCREG_MTRR_PHYS_BASE_0;
236 break;
237 case 0x201:
238 regNum = MISCREG_MTRR_PHYS_MASK_0;
239 break;
240 case 0x202:
241 regNum = MISCREG_MTRR_PHYS_BASE_1;
242 break;
243 case 0x203:
244 regNum = MISCREG_MTRR_PHYS_MASK_1;
245 break;
246 case 0x204:
247 regNum = MISCREG_MTRR_PHYS_BASE_2;
248 break;
249 case 0x205:
250 regNum = MISCREG_MTRR_PHYS_MASK_2;
251 break;
252 case 0x206:
253 regNum = MISCREG_MTRR_PHYS_BASE_3;
254 break;
255 case 0x207:
256 regNum = MISCREG_MTRR_PHYS_MASK_3;
257 break;
258 case 0x208:
259 regNum = MISCREG_MTRR_PHYS_BASE_4;
260 break;
261 case 0x209:
262 regNum = MISCREG_MTRR_PHYS_MASK_4;
263 break;
264 case 0x20A:
265 regNum = MISCREG_MTRR_PHYS_BASE_5;
266 break;
267 case 0x20B:
268 regNum = MISCREG_MTRR_PHYS_MASK_5;
269 break;
270 case 0x20C:
271 regNum = MISCREG_MTRR_PHYS_BASE_6;
272 break;
273 case 0x20D:
274 regNum = MISCREG_MTRR_PHYS_MASK_6;
275 break;
276 case 0x20E:
277 regNum = MISCREG_MTRR_PHYS_BASE_7;
278 break;
279 case 0x20F:
280 regNum = MISCREG_MTRR_PHYS_MASK_7;
281 break;
282 case 0x250:
283 regNum = MISCREG_MTRR_FIX_64K_00000;
284 break;
285 case 0x258:
286 regNum = MISCREG_MTRR_FIX_16K_80000;
287 break;
288 case 0x259:
289 regNum = MISCREG_MTRR_FIX_16K_A0000;
290 break;
291 case 0x268:
292 regNum = MISCREG_MTRR_FIX_4K_C0000;
293 break;
294 case 0x269:
295 regNum = MISCREG_MTRR_FIX_4K_C8000;
296 break;
297 case 0x26A:
298 regNum = MISCREG_MTRR_FIX_4K_D0000;
299 break;
300 case 0x26B:
301 regNum = MISCREG_MTRR_FIX_4K_D8000;
302 break;
303 case 0x26C:
304 regNum = MISCREG_MTRR_FIX_4K_E0000;
305 break;
306 case 0x26D:
307 regNum = MISCREG_MTRR_FIX_4K_E8000;
308 break;
309 case 0x26E:
310 regNum = MISCREG_MTRR_FIX_4K_F0000;
311 break;
312 case 0x26F:
313 regNum = MISCREG_MTRR_FIX_4K_F8000;
314 break;
315 case 0x277:
316 regNum = MISCREG_PAT;
317 break;
318 case 0x2FF:
319 regNum = MISCREG_DEF_TYPE;
320 break;
321 case 0x400:
322 regNum = MISCREG_MC0_CTL;
323 break;
324 case 0x404:
325 regNum = MISCREG_MC1_CTL;
326 break;
327 case 0x408:
328 regNum = MISCREG_MC2_CTL;
329 break;
330 case 0x40C:
331 regNum = MISCREG_MC3_CTL;
332 break;
333 case 0x410:
334 regNum = MISCREG_MC4_CTL;
335 break;
336 case 0x401:
337 regNum = MISCREG_MC0_STATUS;
338 break;
339 case 0x405:
340 regNum = MISCREG_MC1_STATUS;
341 break;
342 case 0x409:
343 regNum = MISCREG_MC2_STATUS;
344 break;
345 case 0x40D:
346 regNum = MISCREG_MC3_STATUS;
347 break;
348 case 0x411:
349 regNum = MISCREG_MC4_STATUS;
350 break;
351 case 0x402:
352 regNum = MISCREG_MC0_ADDR;
353 break;
354 case 0x406:
355 regNum = MISCREG_MC1_ADDR;
356 break;
357 case 0x40A:
358 regNum = MISCREG_MC2_ADDR;
359 break;
360 case 0x40E:
361 regNum = MISCREG_MC3_ADDR;
362 break;
363 case 0x412:
364 regNum = MISCREG_MC4_ADDR;
365 break;
366 case 0x403:
367 regNum = MISCREG_MC0_MISC;
368 break;
369 case 0x407:
370 regNum = MISCREG_MC1_MISC;
371 break;
372 case 0x40B:
373 regNum = MISCREG_MC2_MISC;
374 break;
375 case 0x40F:
376 regNum = MISCREG_MC3_MISC;
377 break;
378 case 0x413:
379 regNum = MISCREG_MC4_MISC;
380 break;
381 case 0xC0000080:
382 regNum = MISCREG_EFER;
383 break;
384 case 0xC0000081:
385 regNum = MISCREG_STAR;
386 break;
387 case 0xC0000082:
388 regNum = MISCREG_LSTAR;
389 break;
390 case 0xC0000083:
391 regNum = MISCREG_CSTAR;
392 break;
393 case 0xC0000084:
394 regNum = MISCREG_SF_MASK;
395 break;
396 case 0xC0000100:
397 regNum = MISCREG_FS_BASE;
398 break;
399 case 0xC0000101:
400 regNum = MISCREG_GS_BASE;
401 break;
402 case 0xC0000102:
403 regNum = MISCREG_KERNEL_GS_BASE;
404 break;
405 case 0xC0000103:
406 regNum = MISCREG_TSC_AUX;
407 break;
408 case 0xC0010000:
409 regNum = MISCREG_PERF_EVT_SEL0;
410 break;
411 case 0xC0010001:
412 regNum = MISCREG_PERF_EVT_SEL1;
413 break;
414 case 0xC0010002:
415 regNum = MISCREG_PERF_EVT_SEL2;
416 break;
417 case 0xC0010003:
418 regNum = MISCREG_PERF_EVT_SEL3;
419 break;
420 case 0xC0010004:
421 regNum = MISCREG_PERF_EVT_CTR0;
422 break;
423 case 0xC0010005:
424 regNum = MISCREG_PERF_EVT_CTR1;
425 break;
426 case 0xC0010006:
427 regNum = MISCREG_PERF_EVT_CTR2;
428 break;
429 case 0xC0010007:
430 regNum = MISCREG_PERF_EVT_CTR3;
431 break;
432 case 0xC0010010:
433 regNum = MISCREG_SYSCFG;
434 break;
435 case 0xC0010016:
436 regNum = MISCREG_IORR_BASE0;
437 break;
438 case 0xC0010017:
439 regNum = MISCREG_IORR_BASE1;
440 break;
441 case 0xC0010018:
442 regNum = MISCREG_IORR_MASK0;
443 break;
444 case 0xC0010019:
445 regNum = MISCREG_IORR_MASK1;
446 break;
447 case 0xC001001A:
448 regNum = MISCREG_TOP_MEM;
449 break;
450 case 0xC001001D:
451 regNum = MISCREG_TOP_MEM2;
452 break;
453 case 0xC0010114:
454 regNum = MISCREG_VM_CR;
455 break;
456 case 0xC0010115:
457 regNum = MISCREG_IGNNE;
458 break;
459 case 0xC0010116:
460 regNum = MISCREG_SMM_CTL;
461 break;
462 case 0xC0010117:
463 regNum = MISCREG_VM_HSAVE_PA;
464 break;
465 default:
466 return new GeneralProtection(0);
467 }
468 //The index is multiplied by the size of a MiscReg so that
469 //any memory dependence calculations will not see these as
470 //overlapping.
471 req->setPaddr(regNum * sizeof(MiscReg));
472 return NoFault;
473 } else {
474 panic("Access to unrecognized internal address space %#x.\n",
475 prefix);
476 }
477 }
478
479 // Get cr0. This will tell us how to do translation. We'll assume it was
480 // verified to be correct and consistent when set.
481 CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0);
482
483 // If protected mode has been enabled...
484 if (cr0.pe) {
485 DPRINTF(TLB, "In protected mode.\n");
486 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
487 SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR);
488 // If we're not in 64-bit mode, do protection/limit checks
489 if (!efer.lma || !csAttr.longMode) {
490 DPRINTF(TLB, "Not in long mode. Checking segment protection.\n");
491 SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg));
492 if (!attr.writable && write)
493 return new GeneralProtection(0);
494 if (!attr.readable && !write && !execute)
495 return new GeneralProtection(0);
496 Addr base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(seg));
497 Addr limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg));
498 if (!attr.expandDown) {
499 DPRINTF(TLB, "Checking an expand down segment.\n");
500 // We don't have to worry about the access going around the
501 // end of memory because accesses will be broken up into
502 // pieces at boundaries aligned on sizes smaller than an
503 // entire address space. We do have to worry about the limit
504 // being less than the base.
505 if (limit < base) {
506 if (limit < vaddr + req->getSize() && vaddr < base)
507 return new GeneralProtection(0);
508 } else {
509 if (limit < vaddr + req->getSize())
510 return new GeneralProtection(0);
511 }
512 } else {
513 if (limit < base) {
514 if (vaddr <= limit || vaddr + req->getSize() >= base)
515 return new GeneralProtection(0);
516 } else {
517 if (vaddr <= limit && vaddr + req->getSize() >= base)
518 return new GeneralProtection(0);
519 }
520 }
521 }
522 // If paging is enabled, do the translation.
523 if (cr0.pg) {
524 DPRINTF(TLB, "Paging enabled.\n");
525 // The vaddr already has the segment base applied.
526 TlbEntry *entry = lookup(vaddr);
527 if (!entry) {
528 return new TlbFault(vaddr);
529 } else {
530 // Do paging protection checks.
531 DPRINTF(TLB, "Entry found with paddr %#x, doing protection checks.\n", entry->paddr);
532 Addr paddr = entry->paddr | (vaddr & (entry->size-1));
533 DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr);
534 req->setPaddr(paddr);
535 }
536 } else {
537 //Use the address which already has segmentation applied.
538 DPRINTF(TLB, "Paging disabled.\n");
539 DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, vaddr);
540 req->setPaddr(vaddr);
541 }
542 } else {
543 // Real mode
544 DPRINTF(TLB, "In real mode.\n");
545 DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, vaddr);
546 req->setPaddr(vaddr);
547 }
548 return NoFault;
549 };
550
551 Fault
552 DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
553 {
554 return TLB::translate<FakeDTLBFault>(req, tc, write, false);
555 }
556
557 Fault
558 ITB::translate(RequestPtr &req, ThreadContext *tc)
559 {
560 return TLB::translate<FakeITLBFault>(req, tc, false, true);
561 }
562
563 #if FULL_SYSTEM
564
565 Tick
566 DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
567 {
568 return tc->getCpuPtr()->ticks(1);
569 }
570
571 Tick
572 DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
573 {
574 return tc->getCpuPtr()->ticks(1);
575 }
576
577 #endif
578
579 void
580 TLB::serialize(std::ostream &os)
581 {
582 }
583
584 void
585 TLB::unserialize(Checkpoint *cp, const std::string &section)
586 {
587 }
588
589 void
590 DTB::serialize(std::ostream &os)
591 {
592 TLB::serialize(os);
593 }
594
595 void
596 DTB::unserialize(Checkpoint *cp, const std::string &section)
597 {
598 TLB::unserialize(cp, section);
599 }
600
601 /* end namespace X86ISA */ }
602
603 X86ISA::ITB *
604 X86ITBParams::create()
605 {
606 return new X86ISA::ITB(this);
607 }
608
609 X86ISA::DTB *
610 X86DTBParams::create()
611 {
612 return new X86ISA::DTB(this);
613 }