943295a5fa29a30909d0d16079c204af5d80f795
[gem5.git] / src / arch / x86 / pagetable_walker.cc
1 /*
2 * Copyright (c) 2012 ARM Limited
3 * All rights reserved.
4 *
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.
13 *
14 * Copyright (c) 2007 The Hewlett-Packard Development Company
15 * All rights reserved.
16 *
17 * The license below extends only to copyright in the software and shall
18 * not be construed as granting a license to any other intellectual
19 * property including but not limited to intellectual property relating
20 * to a hardware implementation of the functionality of the software
21 * licensed hereunder. You may use the software subject to the license
22 * terms below provided that you ensure that this notice is replicated
23 * unmodified and in its entirety in all distributions of the software,
24 * modified or unmodified, in source code or in binary form.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions are
28 * met: redistributions of source code must retain the above copyright
29 * notice, this list of conditions and the following disclaimer;
30 * redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution;
33 * neither the name of the copyright holders nor the names of its
34 * contributors may be used to endorse or promote products derived from
35 * this software without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
40 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
41 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 */
49
50 #include "arch/x86/pagetable_walker.hh"
51
52 #include <memory>
53
54 #include "arch/x86/faults.hh"
55 #include "arch/x86/pagetable.hh"
56 #include "arch/x86/tlb.hh"
57 #include "base/bitfield.hh"
58 #include "base/trie.hh"
59 #include "cpu/base.hh"
60 #include "cpu/thread_context.hh"
61 #include "debug/PageTableWalker.hh"
62 #include "mem/packet_access.hh"
63 #include "mem/request.hh"
64
65 namespace X86ISA {
66
67 Fault
68 Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation,
69 const RequestPtr &_req, BaseTLB::Mode _mode)
70 {
71 // TODO: in timing mode, instead of blocking when there are other
72 // outstanding requests, see if this request can be coalesced with
73 // another one (i.e. either coalesce or start walk)
74 WalkerState * newState = new WalkerState(this, _translation, _req);
75 newState->initState(_tc, _mode, sys->isTimingMode());
76 if (currStates.size()) {
77 assert(newState->isTiming());
78 DPRINTF(PageTableWalker, "Walks in progress: %d\n", currStates.size());
79 currStates.push_back(newState);
80 return NoFault;
81 } else {
82 currStates.push_back(newState);
83 Fault fault = newState->startWalk();
84 if (!newState->isTiming()) {
85 currStates.pop_front();
86 delete newState;
87 }
88 return fault;
89 }
90 }
91
92 Fault
93 Walker::startFunctional(ThreadContext * _tc, Addr &addr, unsigned &logBytes,
94 BaseTLB::Mode _mode)
95 {
96 funcState.initState(_tc, _mode);
97 return funcState.startFunctional(addr, logBytes);
98 }
99
100 bool
101 Walker::WalkerPort::recvTimingResp(PacketPtr pkt)
102 {
103 return walker->recvTimingResp(pkt);
104 }
105
106 bool
107 Walker::recvTimingResp(PacketPtr pkt)
108 {
109 WalkerSenderState * senderState =
110 dynamic_cast<WalkerSenderState *>(pkt->popSenderState());
111 WalkerState * senderWalk = senderState->senderWalk;
112 bool walkComplete = senderWalk->recvPacket(pkt);
113 delete senderState;
114 if (walkComplete) {
115 std::list<WalkerState *>::iterator iter;
116 for (iter = currStates.begin(); iter != currStates.end(); iter++) {
117 WalkerState * walkerState = *(iter);
118 if (walkerState == senderWalk) {
119 iter = currStates.erase(iter);
120 break;
121 }
122 }
123 delete senderWalk;
124 // Since we block requests when another is outstanding, we
125 // need to check if there is a waiting request to be serviced
126 if (currStates.size() && !startWalkWrapperEvent.scheduled())
127 // delay sending any new requests until we are finished
128 // with the responses
129 schedule(startWalkWrapperEvent, clockEdge());
130 }
131 return true;
132 }
133
134 void
135 Walker::WalkerPort::recvReqRetry()
136 {
137 walker->recvReqRetry();
138 }
139
140 void
141 Walker::recvReqRetry()
142 {
143 std::list<WalkerState *>::iterator iter;
144 for (iter = currStates.begin(); iter != currStates.end(); iter++) {
145 WalkerState * walkerState = *(iter);
146 if (walkerState->isRetrying()) {
147 walkerState->retry();
148 }
149 }
150 }
151
152 bool Walker::sendTiming(WalkerState* sendingState, PacketPtr pkt)
153 {
154 WalkerSenderState* walker_state = new WalkerSenderState(sendingState);
155 pkt->pushSenderState(walker_state);
156 if (port.sendTimingReq(pkt)) {
157 return true;
158 } else {
159 // undo the adding of the sender state and delete it, as we
160 // will do it again the next time we attempt to send it
161 pkt->popSenderState();
162 delete walker_state;
163 return false;
164 }
165
166 }
167
168 Port &
169 Walker::getPort(const std::string &if_name, PortID idx)
170 {
171 if (if_name == "port")
172 return port;
173 else
174 return ClockedObject::getPort(if_name, idx);
175 }
176
177 void
178 Walker::WalkerState::initState(ThreadContext * _tc,
179 BaseTLB::Mode _mode, bool _isTiming)
180 {
181 assert(state == Ready);
182 started = false;
183 tc = _tc;
184 mode = _mode;
185 timing = _isTiming;
186 }
187
188 void
189 Walker::startWalkWrapper()
190 {
191 unsigned num_squashed = 0;
192 WalkerState *currState = currStates.front();
193 while ((num_squashed < numSquashable) && currState &&
194 currState->translation->squashed()) {
195 currStates.pop_front();
196 num_squashed++;
197
198 DPRINTF(PageTableWalker, "Squashing table walk for address %#x\n",
199 currState->req->getVaddr());
200
201 // finish the translation which will delete the translation object
202 currState->translation->finish(
203 std::make_shared<UnimpFault>("Squashed Inst"),
204 currState->req, currState->tc, currState->mode);
205
206 // delete the current request if there are no inflight packets.
207 // if there is something in flight, delete when the packets are
208 // received and inflight is zero.
209 if (currState->numInflight() == 0) {
210 delete currState;
211 } else {
212 currState->squash();
213 }
214
215 // check the next translation request, if it exists
216 if (currStates.size())
217 currState = currStates.front();
218 else
219 currState = NULL;
220 }
221 if (currState && !currState->wasStarted())
222 currState->startWalk();
223 }
224
225 Fault
226 Walker::WalkerState::startWalk()
227 {
228 Fault fault = NoFault;
229 assert(!started);
230 started = true;
231 setupWalk(req->getVaddr());
232 if (timing) {
233 nextState = state;
234 state = Waiting;
235 timingFault = NoFault;
236 sendPackets();
237 } else {
238 do {
239 walker->port.sendAtomic(read);
240 PacketPtr write = NULL;
241 fault = stepWalk(write);
242 assert(fault == NoFault || read == NULL);
243 state = nextState;
244 nextState = Ready;
245 if (write)
246 walker->port.sendAtomic(write);
247 } while (read);
248 state = Ready;
249 nextState = Waiting;
250 }
251 return fault;
252 }
253
254 Fault
255 Walker::WalkerState::startFunctional(Addr &addr, unsigned &logBytes)
256 {
257 Fault fault = NoFault;
258 assert(!started);
259 started = true;
260 setupWalk(addr);
261
262 do {
263 walker->port.sendFunctional(read);
264 // On a functional access (page table lookup), writes should
265 // not happen so this pointer is ignored after stepWalk
266 PacketPtr write = NULL;
267 fault = stepWalk(write);
268 assert(fault == NoFault || read == NULL);
269 state = nextState;
270 nextState = Ready;
271 } while (read);
272 logBytes = entry.logBytes;
273 addr = entry.paddr;
274
275 return fault;
276 }
277
278 Fault
279 Walker::WalkerState::stepWalk(PacketPtr &write)
280 {
281 assert(state != Ready && state != Waiting);
282 Fault fault = NoFault;
283 write = NULL;
284 PageTableEntry pte;
285 if (dataSize == 8)
286 pte = read->getLE<uint64_t>();
287 else
288 pte = read->getLE<uint32_t>();
289 VAddr vaddr = entry.vaddr;
290 bool uncacheable = pte.pcd;
291 Addr nextRead = 0;
292 bool doWrite = false;
293 bool doTLBInsert = false;
294 bool doEndWalk = false;
295 bool badNX = pte.nx && mode == BaseTLB::Execute && enableNX;
296 switch(state) {
297 case LongPML4:
298 DPRINTF(PageTableWalker,
299 "Got long mode PML4 entry %#016x.\n", (uint64_t)pte);
300 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * dataSize;
301 doWrite = !pte.a;
302 pte.a = 1;
303 entry.writable = pte.w;
304 entry.user = pte.u;
305 if (badNX || !pte.p) {
306 doEndWalk = true;
307 fault = pageFault(pte.p);
308 break;
309 }
310 entry.noExec = pte.nx;
311 nextState = LongPDP;
312 break;
313 case LongPDP:
314 DPRINTF(PageTableWalker,
315 "Got long mode PDP entry %#016x.\n", (uint64_t)pte);
316 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * dataSize;
317 doWrite = !pte.a;
318 pte.a = 1;
319 entry.writable = entry.writable && pte.w;
320 entry.user = entry.user && pte.u;
321 if (badNX || !pte.p) {
322 doEndWalk = true;
323 fault = pageFault(pte.p);
324 break;
325 }
326 nextState = LongPD;
327 break;
328 case LongPD:
329 DPRINTF(PageTableWalker,
330 "Got long mode PD entry %#016x.\n", (uint64_t)pte);
331 doWrite = !pte.a;
332 pte.a = 1;
333 entry.writable = entry.writable && pte.w;
334 entry.user = entry.user && pte.u;
335 if (badNX || !pte.p) {
336 doEndWalk = true;
337 fault = pageFault(pte.p);
338 break;
339 }
340 if (!pte.ps) {
341 // 4 KB page
342 entry.logBytes = 12;
343 nextRead =
344 ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * dataSize;
345 nextState = LongPTE;
346 break;
347 } else {
348 // 2 MB page
349 entry.logBytes = 21;
350 entry.paddr = (uint64_t)pte & (mask(31) << 21);
351 entry.uncacheable = uncacheable;
352 entry.global = pte.g;
353 entry.patBit = bits(pte, 12);
354 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
355 doTLBInsert = true;
356 doEndWalk = true;
357 break;
358 }
359 case LongPTE:
360 DPRINTF(PageTableWalker,
361 "Got long mode PTE entry %#016x.\n", (uint64_t)pte);
362 doWrite = !pte.a;
363 pte.a = 1;
364 entry.writable = entry.writable && pte.w;
365 entry.user = entry.user && pte.u;
366 if (badNX || !pte.p) {
367 doEndWalk = true;
368 fault = pageFault(pte.p);
369 break;
370 }
371 entry.paddr = (uint64_t)pte & (mask(40) << 12);
372 entry.uncacheable = uncacheable;
373 entry.global = pte.g;
374 entry.patBit = bits(pte, 12);
375 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
376 doTLBInsert = true;
377 doEndWalk = true;
378 break;
379 case PAEPDP:
380 DPRINTF(PageTableWalker,
381 "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte);
382 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * dataSize;
383 if (!pte.p) {
384 doEndWalk = true;
385 fault = pageFault(pte.p);
386 break;
387 }
388 nextState = PAEPD;
389 break;
390 case PAEPD:
391 DPRINTF(PageTableWalker,
392 "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte);
393 doWrite = !pte.a;
394 pte.a = 1;
395 entry.writable = pte.w;
396 entry.user = pte.u;
397 if (badNX || !pte.p) {
398 doEndWalk = true;
399 fault = pageFault(pte.p);
400 break;
401 }
402 if (!pte.ps) {
403 // 4 KB page
404 entry.logBytes = 12;
405 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * dataSize;
406 nextState = PAEPTE;
407 break;
408 } else {
409 // 2 MB page
410 entry.logBytes = 21;
411 entry.paddr = (uint64_t)pte & (mask(31) << 21);
412 entry.uncacheable = uncacheable;
413 entry.global = pte.g;
414 entry.patBit = bits(pte, 12);
415 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
416 doTLBInsert = true;
417 doEndWalk = true;
418 break;
419 }
420 case PAEPTE:
421 DPRINTF(PageTableWalker,
422 "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte);
423 doWrite = !pte.a;
424 pte.a = 1;
425 entry.writable = entry.writable && pte.w;
426 entry.user = entry.user && pte.u;
427 if (badNX || !pte.p) {
428 doEndWalk = true;
429 fault = pageFault(pte.p);
430 break;
431 }
432 entry.paddr = (uint64_t)pte & (mask(40) << 12);
433 entry.uncacheable = uncacheable;
434 entry.global = pte.g;
435 entry.patBit = bits(pte, 7);
436 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
437 doTLBInsert = true;
438 doEndWalk = true;
439 break;
440 case PSEPD:
441 DPRINTF(PageTableWalker,
442 "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte);
443 doWrite = !pte.a;
444 pte.a = 1;
445 entry.writable = pte.w;
446 entry.user = pte.u;
447 if (!pte.p) {
448 doEndWalk = true;
449 fault = pageFault(pte.p);
450 break;
451 }
452 if (!pte.ps) {
453 // 4 KB page
454 entry.logBytes = 12;
455 nextRead =
456 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize;
457 nextState = PTE;
458 break;
459 } else {
460 // 4 MB page
461 entry.logBytes = 21;
462 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22;
463 entry.uncacheable = uncacheable;
464 entry.global = pte.g;
465 entry.patBit = bits(pte, 12);
466 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1);
467 doTLBInsert = true;
468 doEndWalk = true;
469 break;
470 }
471 case PD:
472 DPRINTF(PageTableWalker,
473 "Got legacy mode PD entry %#08x.\n", (uint32_t)pte);
474 doWrite = !pte.a;
475 pte.a = 1;
476 entry.writable = pte.w;
477 entry.user = pte.u;
478 if (!pte.p) {
479 doEndWalk = true;
480 fault = pageFault(pte.p);
481 break;
482 }
483 // 4 KB page
484 entry.logBytes = 12;
485 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize;
486 nextState = PTE;
487 break;
488 case PTE:
489 DPRINTF(PageTableWalker,
490 "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte);
491 doWrite = !pte.a;
492 pte.a = 1;
493 entry.writable = pte.w;
494 entry.user = pte.u;
495 if (!pte.p) {
496 doEndWalk = true;
497 fault = pageFault(pte.p);
498 break;
499 }
500 entry.paddr = (uint64_t)pte & (mask(20) << 12);
501 entry.uncacheable = uncacheable;
502 entry.global = pte.g;
503 entry.patBit = bits(pte, 7);
504 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
505 doTLBInsert = true;
506 doEndWalk = true;
507 break;
508 default:
509 panic("Unknown page table walker state %d!\n");
510 }
511 if (doEndWalk) {
512 if (doTLBInsert)
513 if (!functional)
514 walker->tlb->insert(entry.vaddr, entry);
515 endWalk();
516 } else {
517 PacketPtr oldRead = read;
518 //If we didn't return, we're setting up another read.
519 Request::Flags flags = oldRead->req->getFlags();
520 flags.set(Request::UNCACHEABLE, uncacheable);
521 RequestPtr request = std::make_shared<Request>(
522 nextRead, oldRead->getSize(), flags, walker->requestorId);
523 read = new Packet(request, MemCmd::ReadReq);
524 read->allocate();
525 // If we need to write, adjust the read packet to write the modified
526 // value back to memory.
527 if (doWrite) {
528 write = oldRead;
529 write->setLE<uint64_t>(pte);
530 write->cmd = MemCmd::WriteReq;
531 } else {
532 write = NULL;
533 delete oldRead;
534 }
535 }
536 return fault;
537 }
538
539 void
540 Walker::WalkerState::endWalk()
541 {
542 nextState = Ready;
543 delete read;
544 read = NULL;
545 }
546
547 void
548 Walker::WalkerState::setupWalk(Addr vaddr)
549 {
550 VAddr addr = vaddr;
551 CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3);
552 // Check if we're in long mode or not
553 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
554 dataSize = 8;
555 Addr topAddr;
556 if (efer.lma) {
557 // Do long mode.
558 state = LongPML4;
559 topAddr = (cr3.longPdtb << 12) + addr.longl4 * dataSize;
560 enableNX = efer.nxe;
561 } else {
562 // We're in some flavor of legacy mode.
563 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
564 if (cr4.pae) {
565 // Do legacy PAE.
566 state = PAEPDP;
567 topAddr = (cr3.paePdtb << 5) + addr.pael3 * dataSize;
568 enableNX = efer.nxe;
569 } else {
570 dataSize = 4;
571 topAddr = (cr3.pdtb << 12) + addr.norml2 * dataSize;
572 if (cr4.pse) {
573 // Do legacy PSE.
574 state = PSEPD;
575 } else {
576 // Do legacy non PSE.
577 state = PD;
578 }
579 enableNX = false;
580 }
581 }
582
583 nextState = Ready;
584 entry.vaddr = vaddr;
585
586 Request::Flags flags = Request::PHYSICAL;
587 if (cr3.pcd)
588 flags.set(Request::UNCACHEABLE);
589
590 RequestPtr request = std::make_shared<Request>(
591 topAddr, dataSize, flags, walker->requestorId);
592
593 read = new Packet(request, MemCmd::ReadReq);
594 read->allocate();
595 }
596
597 bool
598 Walker::WalkerState::recvPacket(PacketPtr pkt)
599 {
600 assert(pkt->isResponse());
601 assert(inflight);
602 assert(state == Waiting);
603 inflight--;
604 if (squashed) {
605 // if were were squashed, return true once inflight is zero and
606 // this WalkerState will be freed there.
607 return (inflight == 0);
608 }
609 if (pkt->isRead()) {
610 // should not have a pending read it we also had one outstanding
611 assert(!read);
612
613 // @todo someone should pay for this
614 pkt->headerDelay = pkt->payloadDelay = 0;
615
616 state = nextState;
617 nextState = Ready;
618 PacketPtr write = NULL;
619 read = pkt;
620 timingFault = stepWalk(write);
621 state = Waiting;
622 assert(timingFault == NoFault || read == NULL);
623 if (write) {
624 writes.push_back(write);
625 }
626 sendPackets();
627 } else {
628 sendPackets();
629 }
630 if (inflight == 0 && read == NULL && writes.size() == 0) {
631 state = Ready;
632 nextState = Waiting;
633 if (timingFault == NoFault) {
634 /*
635 * Finish the translation. Now that we know the right entry is
636 * in the TLB, this should work with no memory accesses.
637 * There could be new faults unrelated to the table walk like
638 * permissions violations, so we'll need the return value as
639 * well.
640 */
641 bool delayedResponse;
642 Fault fault = walker->tlb->translate(req, tc, NULL, mode,
643 delayedResponse, true);
644 assert(!delayedResponse);
645 // Let the CPU continue.
646 translation->finish(fault, req, tc, mode);
647 } else {
648 // There was a fault during the walk. Let the CPU know.
649 translation->finish(timingFault, req, tc, mode);
650 }
651 return true;
652 }
653
654 return false;
655 }
656
657 void
658 Walker::WalkerState::sendPackets()
659 {
660 //If we're already waiting for the port to become available, just return.
661 if (retrying)
662 return;
663
664 //Reads always have priority
665 if (read) {
666 PacketPtr pkt = read;
667 read = NULL;
668 inflight++;
669 if (!walker->sendTiming(this, pkt)) {
670 retrying = true;
671 read = pkt;
672 inflight--;
673 return;
674 }
675 }
676 //Send off as many of the writes as we can.
677 while (writes.size()) {
678 PacketPtr write = writes.back();
679 writes.pop_back();
680 inflight++;
681 if (!walker->sendTiming(this, write)) {
682 retrying = true;
683 writes.push_back(write);
684 inflight--;
685 return;
686 }
687 }
688 }
689
690 unsigned
691 Walker::WalkerState::numInflight() const
692 {
693 return inflight;
694 }
695
696 bool
697 Walker::WalkerState::isRetrying()
698 {
699 return retrying;
700 }
701
702 bool
703 Walker::WalkerState::isTiming()
704 {
705 return timing;
706 }
707
708 bool
709 Walker::WalkerState::wasStarted()
710 {
711 return started;
712 }
713
714 void
715 Walker::WalkerState::squash()
716 {
717 squashed = true;
718 }
719
720 void
721 Walker::WalkerState::retry()
722 {
723 retrying = false;
724 sendPackets();
725 }
726
727 Fault
728 Walker::WalkerState::pageFault(bool present)
729 {
730 DPRINTF(PageTableWalker, "Raising page fault.\n");
731 HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
732 if (mode == BaseTLB::Execute && !enableNX)
733 mode = BaseTLB::Read;
734 return std::make_shared<PageFault>(entry.vaddr, present, mode,
735 m5reg.cpl == 3, false);
736 }
737
738 /* end namespace X86ISA */ }
739
740 X86ISA::Walker *
741 X86PagetableWalkerParams::create() const
742 {
743 return new X86ISA::Walker(*this);
744 }