tlb.cc (5243:4228b7b5704b) tlb.cc (5245:d94bb8af9f76)
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 *

--- 55 unchanged lines hidden (view full) ---

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"
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 *

--- 55 unchanged lines hidden (view full) ---

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#include "sim/system.hh"
73
72
74namespace X86ISA {
75
76#if FULL_SYSTEM
73#if FULL_SYSTEM
77TLB::TLB(const Params *p) : MemObject(p), walker(name(), this), size(p->size)
78#else
79TLB::TLB(const Params *p) : MemObject(p), size(p->size)
74#include "arch/x86/pagetable_walker.hh"
80#endif
75#endif
76
77namespace X86ISA {
78
79TLB::TLB(const Params *p) : SimObject(p), size(p->size)
81{
82 tlb = new TlbEntry[size];
83 std::memset(tlb, 0, sizeof(TlbEntry) * size);
84
85 for (int x = 0; x < size; x++)
86 freeList.push_back(&tlb[x]);
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]);
87}
88
89#if FULL_SYSTEM
86
87#if FULL_SYSTEM
90
91// Unfortunately, the placement of the base field in a page table entry is
92// very erratic and would make a mess here. It might be moved here at some
93// point in the future.
94BitUnion64(PageTableEntry)
95 Bitfield<63> nx;
96 Bitfield<11, 9> avl;
97 Bitfield<8> g;
98 Bitfield<7> ps;
99 Bitfield<6> d;
100 Bitfield<5> a;
101 Bitfield<4> pcd;
102 Bitfield<3> pwt;
103 Bitfield<2> u;
104 Bitfield<1> w;
105 Bitfield<0> p;
106EndBitUnion(PageTableEntry)
107
108void
109TLB::Walker::doNext(PacketPtr &read, PacketPtr &write)
110{
111 assert(state != Ready && state != Waiting);
112 write = NULL;
113 PageTableEntry pte;
114 if (size == 8)
115 pte = read->get<uint64_t>();
116 else
117 pte = read->get<uint32_t>();
118 VAddr vaddr = entry.vaddr;
119 bool uncacheable = pte.pcd;
120 Addr nextRead = 0;
121 bool doWrite = false;
122 bool badNX = pte.nx && (!tlb->allowNX || !enableNX);
123 switch(state) {
124 case LongPML4:
125 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * size;
126 doWrite = !pte.a;
127 pte.a = 1;
128 entry.writable = pte.w;
129 entry.user = pte.u;
130 if (badNX)
131 panic("NX violation!\n");
132 entry.noExec = pte.nx;
133 if (!pte.p)
134 panic("Page not present!\n");
135 nextState = LongPDP;
136 break;
137 case LongPDP:
138 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size;
139 doWrite = !pte.a;
140 pte.a = 1;
141 entry.writable = entry.writable && pte.w;
142 entry.user = entry.user && pte.u;
143 if (badNX)
144 panic("NX violation!\n");
145 if (!pte.p)
146 panic("Page not present!\n");
147 nextState = LongPD;
148 break;
149 case LongPD:
150 doWrite = !pte.a;
151 pte.a = 1;
152 entry.writable = entry.writable && pte.w;
153 entry.user = entry.user && pte.u;
154 if (badNX)
155 panic("NX violation!\n");
156 if (!pte.p)
157 panic("Page not present!\n");
158 if (!pte.ps) {
159 // 4 KB page
160 entry.size = 4 * (1 << 10);
161 nextRead =
162 ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * size;
163 nextState = LongPTE;
164 break;
165 } else {
166 // 2 MB page
167 entry.size = 2 * (1 << 20);
168 entry.paddr = (uint64_t)pte & (mask(31) << 21);
169 entry.uncacheable = uncacheable;
170 entry.global = pte.g;
171 entry.patBit = bits(pte, 12);
172 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
173 tlb->insert(entry.vaddr, entry);
174 nextState = Ready;
175 delete read->req;
176 delete read;
177 read = NULL;
178 return;
179 }
180 case LongPTE:
181 doWrite = !pte.a;
182 pte.a = 1;
183 entry.writable = entry.writable && pte.w;
184 entry.user = entry.user && pte.u;
185 if (badNX)
186 panic("NX violation!\n");
187 if (!pte.p)
188 panic("Page not present!\n");
189 entry.paddr = (uint64_t)pte & (mask(40) << 12);
190 entry.uncacheable = uncacheable;
191 entry.global = pte.g;
192 entry.patBit = bits(pte, 12);
193 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
194 tlb->insert(entry.vaddr, entry);
195 nextState = Ready;
196 delete read->req;
197 delete read;
198 read = NULL;
199 return;
200 case PAEPDP:
201 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size;
202 if (!pte.p)
203 panic("Page not present!\n");
204 nextState = PAEPD;
205 break;
206 case PAEPD:
207 doWrite = !pte.a;
208 pte.a = 1;
209 entry.writable = pte.w;
210 entry.user = pte.u;
211 if (badNX)
212 panic("NX violation!\n");
213 if (!pte.p)
214 panic("Page not present!\n");
215 if (!pte.ps) {
216 // 4 KB page
217 entry.size = 4 * (1 << 10);
218 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * size;
219 nextState = PAEPTE;
220 break;
221 } else {
222 // 2 MB page
223 entry.size = 2 * (1 << 20);
224 entry.paddr = (uint64_t)pte & (mask(31) << 21);
225 entry.uncacheable = uncacheable;
226 entry.global = pte.g;
227 entry.patBit = bits(pte, 12);
228 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
229 tlb->insert(entry.vaddr, entry);
230 nextState = Ready;
231 delete read->req;
232 delete read;
233 read = NULL;
234 return;
235 }
236 case PAEPTE:
237 doWrite = !pte.a;
238 pte.a = 1;
239 entry.writable = entry.writable && pte.w;
240 entry.user = entry.user && pte.u;
241 if (badNX)
242 panic("NX violation!\n");
243 if (!pte.p)
244 panic("Page not present!\n");
245 entry.paddr = (uint64_t)pte & (mask(40) << 12);
246 entry.uncacheable = uncacheable;
247 entry.global = pte.g;
248 entry.patBit = bits(pte, 7);
249 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
250 tlb->insert(entry.vaddr, entry);
251 nextState = Ready;
252 delete read->req;
253 delete read;
254 read = NULL;
255 return;
256 case PSEPD:
257 doWrite = !pte.a;
258 pte.a = 1;
259 entry.writable = pte.w;
260 entry.user = pte.u;
261 if (!pte.p)
262 panic("Page not present!\n");
263 if (!pte.ps) {
264 // 4 KB page
265 entry.size = 4 * (1 << 10);
266 nextRead =
267 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
268 nextState = PTE;
269 break;
270 } else {
271 // 4 MB page
272 entry.size = 4 * (1 << 20);
273 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22;
274 entry.uncacheable = uncacheable;
275 entry.global = pte.g;
276 entry.patBit = bits(pte, 12);
277 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1);
278 tlb->insert(entry.vaddr, entry);
279 nextState = Ready;
280 delete read->req;
281 delete read;
282 read = NULL;
283 return;
284 }
285 case PD:
286 doWrite = !pte.a;
287 pte.a = 1;
288 entry.writable = pte.w;
289 entry.user = pte.u;
290 if (!pte.p)
291 panic("Page not present!\n");
292 // 4 KB page
293 entry.size = 4 * (1 << 10);
294 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
295 nextState = PTE;
296 break;
297 nextState = PTE;
298 break;
299 case PTE:
300 doWrite = !pte.a;
301 pte.a = 1;
302 entry.writable = pte.w;
303 entry.user = pte.u;
304 if (!pte.p)
305 panic("Page not present!\n");
306 entry.paddr = (uint64_t)pte & (mask(20) << 12);
307 entry.uncacheable = uncacheable;
308 entry.global = pte.g;
309 entry.patBit = bits(pte, 7);
310 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
311 tlb->insert(entry.vaddr, entry);
312 nextState = Ready;
313 delete read->req;
314 delete read;
315 read = NULL;
316 return;
317 default:
318 panic("Unknown page table walker state %d!\n");
319 }
320 PacketPtr oldRead = read;
321 //If we didn't return, we're setting up another read.
322 uint32_t flags = oldRead->req->getFlags();
323 if (uncacheable)
324 flags |= UNCACHEABLE;
325 else
326 flags &= ~UNCACHEABLE;
327 RequestPtr request =
328 new Request(nextRead, oldRead->getSize(), flags);
329 read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
330 read->allocate();
331 //If we need to write, adjust the read packet to write the modified value
332 //back to memory.
333 if (doWrite) {
334 write = oldRead;
335 write->set<uint64_t>(pte);
336 write->cmd = MemCmd::WriteReq;
337 write->setDest(Packet::Broadcast);
338 } else {
339 write = NULL;
340 delete oldRead->req;
341 delete oldRead;
342 }
88 walker = p->walker;
89 walker->setTLB(this);
90#endif
343}
344
345void
91}
92
93void
346TLB::Walker::start(ThreadContext * _tc, Addr vaddr)
347{
348 assert(state == Ready);
349 assert(!tc);
350 tc = _tc;
351
352 VAddr addr = vaddr;
353
354 //Figure out what we're doing.
355 CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3);
356 Addr top = 0;
357 // Check if we're in long mode or not
358 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
359 size = 8;
360 if (efer.lma) {
361 // Do long mode.
362 state = LongPML4;
363 top = (cr3.longPdtb << 12) + addr.longl4 * size;
364 } else {
365 // We're in some flavor of legacy mode.
366 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
367 if (cr4.pae) {
368 // Do legacy PAE.
369 state = PAEPDP;
370 top = (cr3.paePdtb << 5) + addr.pael3 * size;
371 } else {
372 size = 4;
373 top = (cr3.pdtb << 12) + addr.norml2 * size;
374 if (cr4.pse) {
375 // Do legacy PSE.
376 state = PSEPD;
377 } else {
378 // Do legacy non PSE.
379 state = PD;
380 }
381 }
382 }
383
384 nextState = Ready;
385 entry.vaddr = vaddr;
386
387 enableNX = efer.nxe;
388
389 RequestPtr request =
390 new Request(top, size, PHYSICAL | cr3.pcd ? UNCACHEABLE : 0);
391 read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
392 read->allocate();
393 Enums::MemoryMode memMode = tlb->sys->getMemoryMode();
394 if (memMode == Enums::timing) {
395 tc->suspend();
396 port.sendTiming(read);
397 } else if (memMode == Enums::atomic) {
398 do {
399 port.sendAtomic(read);
400 PacketPtr write = NULL;
401 doNext(read, write);
402 state = nextState;
403 nextState = Ready;
404 if (write)
405 port.sendAtomic(write);
406 } while(read);
407 tc = NULL;
408 state = Ready;
409 nextState = Waiting;
410 } else {
411 panic("Unrecognized memory system mode.\n");
412 }
413}
414
415bool
416TLB::Walker::WalkerPort::recvTiming(PacketPtr pkt)
417{
418 return walker->recvTiming(pkt);
419}
420
421bool
422TLB::Walker::recvTiming(PacketPtr pkt)
423{
424 inflight--;
425 if (pkt->isResponse() && !pkt->wasNacked()) {
426 if (pkt->isRead()) {
427 assert(inflight);
428 assert(state == Waiting);
429 assert(!read);
430 state = nextState;
431 nextState = Ready;
432 PacketPtr write = NULL;
433 doNext(pkt, write);
434 state = Waiting;
435 read = pkt;
436 if (write) {
437 writes.push_back(write);
438 }
439 sendPackets();
440 } else {
441 sendPackets();
442 }
443 if (inflight == 0 && read == NULL && writes.size() == 0) {
444 tc->activate(0);
445 tc = NULL;
446 state = Ready;
447 nextState = Waiting;
448 }
449 } else if (pkt->wasNacked()) {
450 pkt->reinitNacked();
451 if (!port.sendTiming(pkt)) {
452 retrying = true;
453 if (pkt->isWrite()) {
454 writes.push_back(pkt);
455 } else {
456 assert(!read);
457 read = pkt;
458 }
459 } else {
460 inflight++;
461 }
462 }
463 return true;
464}
465
466Tick
467TLB::Walker::WalkerPort::recvAtomic(PacketPtr pkt)
468{
469 return 0;
470}
471
472void
473TLB::Walker::WalkerPort::recvFunctional(PacketPtr pkt)
474{
475 return;
476}
477
478void
479TLB::Walker::WalkerPort::recvStatusChange(Status status)
480{
481 if (status == RangeChange) {
482 if (!snoopRangeSent) {
483 snoopRangeSent = true;
484 sendStatusChange(Port::RangeChange);
485 }
486 return;
487 }
488
489 panic("Unexpected recvStatusChange.\n");
490}
491
492void
493TLB::Walker::WalkerPort::recvRetry()
494{
495 walker->recvRetry();
496}
497
498void
499TLB::Walker::recvRetry()
500{
501 retrying = false;
502 sendPackets();
503}
504
505void
506TLB::Walker::sendPackets()
507{
508 //If we're already waiting for the port to become available, just return.
509 if (retrying)
510 return;
511
512 //Reads always have priority
513 if (read) {
514 if (!port.sendTiming(read)) {
515 retrying = true;
516 return;
517 } else {
518 inflight++;
519 delete read->req;
520 delete read;
521 read = NULL;
522 }
523 }
524 //Send off as many of the writes as we can.
525 while (writes.size()) {
526 PacketPtr write = writes.back();
527 if (!port.sendTiming(write)) {
528 retrying = true;
529 return;
530 } else {
531 inflight++;
532 delete write->req;
533 delete write;
534 writes.pop_back();
535 }
536 }
537}
538
539Port *
540TLB::getPort(const std::string &if_name, int idx)
541{
542 if (if_name == "walker_port")
543 return &walker.port;
544 else
545 panic("No tlb port named %s!\n", if_name);
546}
547
548#else
549
550Port *
551TLB::getPort(const std::string &if_name, int idx)
552{
553 panic("No tlb ports in se!\n", if_name);
554}
555
556#endif
557
558void
559TLB::insert(Addr vpn, TlbEntry &entry)
560{
561 //TODO Deal with conflicting entries
562
563 TlbEntry *newEntry = NULL;
564 if (!freeList.empty()) {
565 newEntry = freeList.front();
566 freeList.pop_front();

--- 21 unchanged lines hidden (view full) ---

588 entryList.push_front(e);
589 }
590 return e;
591 }
592 }
593 return NULL;
594}
595
94TLB::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();

--- 21 unchanged lines hidden (view full) ---

123 entryList.push_front(e);
124 }
125 return e;
126 }
127 }
128 return NULL;
129}
130
131#if FULL_SYSTEM
596void
132void
133TLB::walk(ThreadContext * _tc, Addr vaddr)
134{
135 walker->start(_tc, vaddr);
136}
137#endif
138
139void
597TLB::invalidateAll()
598{
599 DPRINTF(TLB, "Invalidating all entries.\n");
600 while (!entryList.empty()) {
601 TlbEntry *entry = entryList.front();
602 entryList.pop_front();
603 freeList.push_back(entry);
604 }

--- 466 unchanged lines hidden ---
140TLB::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 }

--- 466 unchanged lines hidden ---