gem5 v25.0.0.1
Loading...
Searching...
No Matches
pagetable_walker.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012 ARM Limited
3 * Copyright (c) 2020 Barkhausen Institut
4 * All rights reserved.
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2007 The Hewlett-Packard Development Company
16 * All rights reserved.
17 *
18 * The license below extends only to copyright in the software and shall
19 * not be construed as granting a license to any other intellectual
20 * property including but not limited to intellectual property relating
21 * to a hardware implementation of the functionality of the software
22 * licensed hereunder. You may use the software subject to the license
23 * terms below provided that you ensure that this notice is replicated
24 * unmodified and in its entirety in all distributions of the software,
25 * modified or unmodified, in source code or in binary form.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions are
29 * met: redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer;
31 * redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution;
34 * neither the name of the copyright holders nor the names of its
35 * contributors may be used to endorse or promote products derived from
36 * this software without specific prior written permission.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
41 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 */
50
52
53#include <memory>
54
55#include "arch/riscv/faults.hh"
58#include "arch/riscv/tlb.hh"
59#include "base/bitfield.hh"
60#include "base/trie.hh"
61#include "cpu/base.hh"
62#include "cpu/thread_context.hh"
63#include "debug/PageTableWalker.hh"
64#include "mem/packet_access.hh"
65#include "mem/request.hh"
66
67namespace gem5
68{
69
70namespace RiscvISA {
71
74 const RequestPtr &_req, BaseMMU::Mode _mode, TlbEntry* result_entry)
75{
76 // TODO: in timing mode, instead of blocking when there are other
77 // outstanding requests, see if this request can be coalesced with
78 // another one (i.e. either coalesce or start walk)
79 WalkerState * newState = new WalkerState(this, _translation, _req);
80 newState->initState(_tc, _mode, sys->isTimingMode());
81 if (currStates.size()) {
82 assert(newState->isTiming());
83 DPRINTF(PageTableWalker, "Walks in progress: %d\n", currStates.size());
84 currStates.push_back(newState);
85 return NoFault;
86 } else {
87 currStates.push_back(newState);
88 Fault fault = newState->walk();
89
90 // Keep the resulting TLB entry
91 // in some cases we might need to use the result
92 // but not insert to the TLB, so we can't look it up if we return!
93 if (result_entry)
94 *result_entry = newState->entry;
95
96 // In functional mode, always pop the state
97 // In timing we must pop the state in the case of an early fault!
98 if (fault != NoFault || !newState->isTiming())
99 {
100 currStates.pop_front();
101 delete newState;
102 }
103 return fault;
104 }
105}
106
107Fault
108Walker::startFunctional(ThreadContext * _tc, Addr &addr, unsigned &logBytes,
109 BaseMMU::Mode _mode)
110{
111 funcState.initState(_tc, _mode);
112 return funcState.startFunctional(addr, logBytes);
113}
114
115bool
117{
118 return walker->recvTimingResp(pkt);
119}
120
121bool
123{
124 WalkerSenderState * senderState =
125 dynamic_cast<WalkerSenderState *>(pkt->popSenderState());
126 WalkerState * senderWalk = senderState->senderWalk;
127 bool walkComplete = senderWalk->recvPacket(pkt);
128 delete senderState;
129 if (walkComplete) {
131 for (iter = currStates.begin(); iter != currStates.end(); iter++) {
132 WalkerState * walkerState = *(iter);
133 if (walkerState == senderWalk) {
134 iter = currStates.erase(iter);
135 break;
136 }
137 }
138 delete senderWalk;
139 // Since we block requests when another is outstanding, we
140 // need to check if there is a waiting request to be serviced
141 if (currStates.size() && !startWalkWrapperEvent.scheduled())
142 // delay sending any new requests until we are finished
143 // with the responses
145 }
146 return true;
147}
148
149void
151{
152 walker->recvReqRetry();
153}
154
155void
157{
159 for (iter = currStates.begin(); iter != currStates.end(); iter++) {
160 WalkerState * walkerState = *(iter);
161 if (walkerState->isRetrying()) {
162 walkerState->retry();
163 }
164 }
165}
166
168{
169 WalkerSenderState* walker_state = new WalkerSenderState(sendingState);
170 pkt->pushSenderState(walker_state);
171 if (port.sendTimingReq(pkt)) {
172 return true;
173 } else {
174 // undo the adding of the sender state and delete it, as we
175 // will do it again the next time we attempt to send it
176 pkt->popSenderState();
177 delete walker_state;
178 return false;
179 }
180
181}
182
183Port &
184Walker::getPort(const std::string &if_name, PortID idx)
185{
186 if (if_name == "port")
187 return port;
188 else
189 return ClockedObject::getPort(if_name, idx);
190}
191
192void
194 BaseMMU::Mode _mode, bool _isTiming)
195{
196 assert(state == Ready);
197 started = false;
198 tc = _tc;
199 mode = _mode;
200 timing = _isTiming;
201 // fetch these now in case they change during the walk
203 walker->tlb->getMemAccessInfo(tc, mode, (Request::ArchFlagsType)0):
204 walker->tlb->getMemAccessInfo(tc, mode, req->getArchFlags());
205 pmode = memaccess.priv;
206 status = tc->readMiscReg(MISCREG_STATUS);
207 MISA misa = tc->readMiscReg(MISCREG_ISA);
208
209 // Find SATP
210 // If no rvh or effective V = 0, base is SATP
211 // otherwise base is VSATP (effective V=1)
212 satp = (!misa.rvh || !memaccess.virt) ?
213 tc->readMiscReg(MISCREG_SATP) :
214 tc->readMiscReg(MISCREG_VSATP);
215
216 // If effective V = 1, also read HGATP for
217 // G-stage because we will perform a two-stage translation.
218 hgatp = (misa.rvh && memaccess.virt) ?
219 tc->readMiscReg(MISCREG_HGATP) :
220 (RegVal)0;
221
222 // TODO move this somewhere else
223 // VSATP mode might be bare, but we still
224 // will have to go through G-stage
225 // assert(satp.mode == AddrXlateMode::SV39);
226
227 // If functional entry.vaddr will be set
228 // in start functional (req == NULL)
229 entry.vaddr = functional ?
230 (Addr)0 :
231 req->getVaddr();
232
233 entry.asid = satp.asid;
234}
235
236void
238{
239 unsigned num_squashed = 0;
240 WalkerState *currState = currStates.front();
241
242 // check if we get a tlb hit to skip the walk
243 Addr vaddr = Addr(sext<SV39_VADDR_BITS>(currState->req->getVaddr()));
244 Addr vpn = getVPNFromVAddr(vaddr, currState->satp.mode);
245 TlbEntry *e = tlb->lookup(vpn, currState->satp.asid, currState->mode,
246 true);
247 Fault fault = NoFault;
248 if (e) {
249 fault = tlb->checkPermissions(currState->tc, currState->memaccess,
250 e->vaddr, currState->mode, e->pte);
251 }
252
253 while ((num_squashed < numSquashable) && currState &&
254 (currState->translation->squashed() || (e && fault == NoFault))) {
255 currStates.pop_front();
256 num_squashed++;
257
258 DPRINTF(PageTableWalker, "Squashing table walk for address %#x\n",
259 currState->req->getVaddr());
260
261 // finish the translation which will delete the translation object
262 if (currState->translation->squashed()) {
263 currState->translation->finish(
264 std::make_shared<UnimpFault>("Squashed Inst"),
265 currState->req, currState->tc, currState->mode);
266 } else {
267 tlb->translateTiming(currState->req, currState->tc,
268 currState->translation, currState->mode);
269 }
270
271 // delete the current request if there are no inflight packets.
272 // if there is something in flight, delete when the packets are
273 // received and inflight is zero.
274 if (currState->numInflight() == 0) {
275 delete currState;
276 } else {
277 currState->squash();
278 }
279
280 // check the next translation request, if it exists
281 if (currStates.size()) {
282 currState = currStates.front();
283 vaddr = Addr(sext<SV39_VADDR_BITS>(currState->req->getVaddr()));
284 Addr vpn = getVPNFromVAddr(vaddr, currState->satp.mode);
285 e = tlb->lookup(vpn, currState->satp.asid, currState->mode,
286 true);
287 if (e) {
288 fault = tlb->checkPermissions(currState->tc,
289 currState->memaccess, e->vaddr, currState->mode, e->pte);
290 }
291 } else {
292 currState = NULL;
293 }
294 }
295 if (currState && !currState->wasStarted()) {
296 if (!e || fault != NoFault) {
297 Fault timingFault = currState->walk();
298 if (timingFault != NoFault) {
299 currStates.pop_front();
300 delete currState;
301 currState = NULL;
302 }
303 }
304 else {
306 }
307 }
308}
309
310Fault
312{
313 Fault fault = NoFault;
315
316
317 // reset gresult in case we were called again
318 // in a two stage translation
319 gresult.reset();
320 gresult.vaddr = guest_paddr;
321
324
325
326 const int maxgpabits = SV39_LEVELS * SV39_LEVEL_BITS +
328 Addr maxgpa = mask(maxgpabits);
329
330 // If there is a bit beyond maxgpa, throw pf
331 if (guest_paddr & ~maxgpa) {
332 return pageFault();
333 }
334
335 // If there is another read packet,
336 // deallocate it, gstage creates a new packet
337 if (read) {
338 delete read;
339 read = nullptr;
340 }
341
342 Addr pte_addr = setupWalk(guest_paddr);
343 read = createReqPacket(pte_addr, MemCmd::ReadReq, sizeof(PTESv39));
344 glevel = SV39_LEVELS - 1;
345
346 // TODO THE TIMING PATH IS UNTESTED
347 if (timing) {
348 panic("unimpl");
350 gstate = Waiting;
352 sendPackets();
353 }
354 else {
355 do {
356 walker->port.sendAtomic(read);
357 PacketPtr write = NULL;
358 fault = stepWalkGStage(write);
359 assert(fault == NoFault || read == NULL);
362 if (write) {
363 walker->port.sendAtomic(write);
364 }
365 } while (read);
366
367 if (fault) {
368 return fault;
369 }
370
371 // In GStageOnly result is in entry (which is put in TLB)
372 // otherwise it's a two stage walk so result is in gresult
373 // which is discarded after.
374 Addr ppn = walkType == GstageOnly ? entry.paddr : gresult.paddr;
375 Addr vpn = guest_paddr >> PageShift;
376 Addr vpn_bits = vpn & mask(glevel * SV39_LEVEL_BITS);
377
378 // Update gresult
379 gresult.paddr = (ppn | vpn_bits);
380
381 host_paddr = ((ppn | vpn_bits) << PageShift) |
382 (guest_paddr & mask(PageShift));
383
384 gstate = Ready;
386 }
387 return fault;
388}
389
390Fault
392{
393 Fault fault = NoFault;
394 assert(!started);
395 started = true;
398
399 // This is the vaddr to walk for
400 Addr vaddr = entry.vaddr;
401
402 // Decide the type of walk to perform
403 // When memaccess is virtual, GStage is enabled
404 if (satp.mode == AddrXlateMode::BARE && memaccess.virt) {
405 // In this case VSATP (== satp) is bare and
406 // we do G-stage translation only
407 Addr paddr;
409 fault = walkGStage(vaddr, paddr);
410 }
411 else if (memaccess.virt) {
413 fault = walkTwoStage(vaddr);
414 }
415 else {
417 fault = walkOneStage(vaddr);
418 }
419
420 return fault;
421}
422
423
424Fault
426{
427
429
430 // Make sure MSBS are the same
431 // riscv-privileged-20211203 page 84
432 auto mask_for_msbs = mask(64 - SV39_VADDR_BITS);
433 auto msbs = bits(vaddr, 63, SV39_VADDR_BITS);
434 if (msbs != 0 && msbs != mask_for_msbs) {
435 return pageFault();
436 }
437
438 Addr pte_addr = setupWalk(vaddr);
439 level = SV39_LEVELS - 1;
440 // Create physical request for first_pte_addr
441 // This is a host physical address
442 // In two-stage this gets discarded?
443 read = createReqPacket(pte_addr,
444 MemCmd::ReadReq, sizeof(PTESv39));
445
446 if (timing)
447 {
448 MISA misa = tc->readMiscReg(MISCREG_ISA);
449 panic_if(misa.rvh, "Timing walks are not supported with h extension");
451 state = Waiting;
453 // DO GSTAGE HERE IF NEEDED AND THEN DO PACKETS FOR *PTE
454 sendPackets();
455 return NoFault;
456 }
457
458 Fault fault = NoFault;
459 do
460 {
461 if (functional) {
462 walker->port.sendFunctional(read);
463 }
464 else {
465 walker->port.sendAtomic(read);
466 }
467
468 PacketPtr write = NULL;
469 fault = stepWalk(write);
470 assert(fault == NoFault || read == NULL);
473
474 // On a functional access (page table lookup), writes should
475 // not happen so this pointer is ignored after stepWalk
476 if (write && !functional) {
477 walker->port.sendAtomic(write);
478 }
479 } while (read);
480
481 state = Ready;
483 return fault;
484}
485
486
487
488
489
490Fault
492{
494
495 // Make sure MSBS are the same
496 // riscv-privileged-20211203 page 84
497 auto mask_for_msbs = mask(64 - SV39_VADDR_BITS);
498 auto msbs = bits(vaddr, 63, SV39_VADDR_BITS);
499 if (msbs != 0 && msbs != mask_for_msbs) {
500 return pageFault();
501 }
502
503 Addr pte_addr = setupWalk(vaddr);
504 level = SV39_LEVELS - 1;
505 // Create physical request for first_pte_addr
506 // This is a host physical address
507 // In two-stage this gets discarded?
508 read = createReqPacket(pte_addr,
509 MemCmd::ReadReq, sizeof(PTESv39));
510
511
512
513 if (timing)
514 {
515 MISA misa = tc->readMiscReg(MISCREG_ISA);
516 panic_if(misa.rvh, "Timing walks are not supported with h extension");
518 state = Waiting;
520 // DO GSTAGE HERE IF NEEDED AND THEN DO PACKETS FOR *PTE
521 sendPackets();
522 return NoFault;
523 }
524
525 Fault fault = NoFault;
526 do
527 {
528 // This is a "virtual" access, pte_address
529 // is guest physical (host virtual) so pass through
530 // G-stage before making a request to physmem.
531 Addr guest_paddr = pte_addr;
532 Addr host_paddr;
533
534 fault = walkGStage(guest_paddr, host_paddr);
535 if (fault != NoFault) { return fault; }
536 pte_addr = host_paddr;
537
538 // Create the physmem packet to be sent
539 read = createReqPacket(pte_addr,
540 MemCmd::ReadReq, sizeof(PTESv39));
541
542 // G-stage done go back to first_stage logic
544
545
546 if (functional) {
547 walker->port.sendFunctional(read);
548 } else {
549 walker->port.sendAtomic(read);
550 }
551
552 PacketPtr write = NULL;
553 fault = stepWalk(write);
554
555 // Set up next vpte_addr for GStage
556 // This read packet should not be sent to mem
557 // paddr contains a virtual (guest physical) address
558 if (read && fault == NoFault) {
559 pte_addr = read->req->getPaddr();
560 }
561
562 assert(fault == NoFault || read == NULL);
565
566 // On a functional access (page table lookup), writes should
567 // not happen so this pointer is ignored after stepWalk
568 if (write && !functional) {
569 walker->port.sendAtomic(write);
570 }
571 } while (read);
572
573
574 if (fault != NoFault) {
575 return fault;
576 }
577
578 // In 2-stage walks the TLB insert is done after an
579 // additional g-stage walk
580
581 // gpa is a host virtual address.
582 // To actually get the host physical address of the page,
583 // we have to pass through GStage one final time.
584 fault = guestToHostPage(vaddr);
585
586 if (fault != NoFault) {
587 return fault;
588 }
589
590 if (!functional && !memaccess.bypassTLB()) {
591 Addr vpn = getVPNFromVAddr(entry.vaddr, satp.mode);
592 walker->tlb->insert(vpn, entry);
593 }
594
595 state = Ready;
597 return NoFault;
598}
599
600
601Fault
603{
604 Addr gpa = (((entry.paddr) |
606 << PageShift) | (vaddr & mask(PageShift));
607
608 Addr host_page_address;
609 Fault fault = walkGStage(gpa, host_page_address);
610 if (fault != NoFault) { return fault; }
611
612 // Final G-stage done, go back to first_stage logic
614
615 // gpn (vaddr) -> ppn (paddr) translation is already
616 // in gresult, host_page_address is not needed here
617 // TLB stores ppn and pte
618 // entry.logBytes = PageShift + (level * SV39_LEVEL_BITS);
619 entry.logBytes = PageShift;
620 entry.paddr = gresult.paddr;
621 entry.vaddr &= ~((1 << entry.logBytes) - 1);
622
623 // entry.pte contains guest pte
624 // host pte is in gresult.pte from final GStage
625 entry.gpte = entry.pte;
626 entry.pte = gresult.pte;
627
628 return NoFault;
629}
630
631Fault
633{
634 // Pass the addess to entry here
635 // initState cannot because there is no req object
636 entry.vaddr = addr;
637 // just call walk
638 // it takes care to do the right thing
639 // when functional is true
640 Fault fault = walk();
641 logBytes = entry.logBytes;
642 addr = entry.paddr << PageShift;
643
644 return fault;
645}
646
647
648Fault
650 PTESv39 pte, WalkFlags& stepWalkFlags, int level)
651{
652 // If valid bit is off OR
653 // the page is writable but not readable, throw pf
654 if (!pte.v || (!pte.r && pte.w)) {
655 stepWalkFlags.doEndWalk = true;
656 return pageFault();
657 }
658
659 // If read-bit or exec-bit, then PTE is a leaf
660 if (pte.r || pte.x) {
661 stepWalkFlags.pteIsLeaf = true;
662 stepWalkFlags.doEndWalk = true;
663
664 Fault fault = walker->tlb->checkPermissions(tc, memaccess,
665 entry.vaddr, mode, pte, gresult.vaddr, curstage);
666
667 if (fault != NoFault) {
668 return fault;
669 }
670
671 // ppn fragments that correspond to unused
672 // vpn fragments have to be all zeroes
673 // Otherwise, throw a pagefault
674 if (level >= 1 && pte.ppn0 != 0)
675 {
676 return pageFault();
677 }
678 else if (level == 2 && pte.ppn1 != 0)
679 {
680 return pageFault();
681 }
682
683 if (pte.n && (pte.ppn0 & mask(NapotShift)) != 8) {
684 DPRINTF(PageTableWalker,
685 "SVNAPOT PTE has wrong encoding, \
686 raising PF\n");
687 fault = pageFault();
688 }
689
690 // Check if we need to write
691 if (!pte.a) {
692 pte.a = 1;
693 stepWalkFlags.doWrite = true;
694 }
695 if (!pte.d && mode == BaseMMU::Write) {
696 pte.d = 1;
697 stepWalkFlags.doWrite = true;
698 }
699 }
700
701 return NoFault;
702}
703
704Fault
706{
707 assert(state != Ready && state != Waiting);
708
709 Fault fault = NoFault;
710 write = NULL;
711 PTESv39 pte = read->getLE<uint64_t>();
712 Addr nextRead = 0;
713
714 // walk flags are initialized to false
715 WalkFlags stepWalkFlags;
716
717 DPRINTF(PageTableWalker, "Got level%d PTE: %#x\n", level, pte);
718
719 // step 2:
720 // Performing PMA/PMP checks on physical address of PTE
721
722 // Effective privilege mode for pmp checks for page table
723 // walks is S mode according to specs
724 fault = walker->pmp->pmpCheck(read->req, BaseMMU::Read,
726
727 if (fault == NoFault) {
728 fault = walker->pma->check(read->req, BaseMMU::Read, entry.vaddr);
729 }
730
731 if (fault == NoFault) {
732
733 fault = checkPTEPermissions(pte, stepWalkFlags, level);
734
735 if (fault == NoFault && stepWalkFlags.pteIsLeaf) {
736
737 if (stepWalkFlags.doWrite) {
738
739 // this read will eventually become write
740 // if doWrite is True
741
742 fault = walker->pmp->pmpCheck(read->req,
743 BaseMMU::Write, pmode, tc, entry.vaddr);
744
745 if (fault == NoFault) {
746 fault = walker->pma->check(read->req,
747 BaseMMU::Write, entry.vaddr);
748 }
749 }
750
751 // perform next step only if pmp checks pass
752 if (fault == NoFault) {
753 // TLB inserts are OK for single stage walks
754 // For two-stage, FIRST_STAGE will reach here just once
755 // but the TLB insertion is done in walkTwoStage()
756 if (walkType == OneStage ||
758 {
759 // Fill in TLB entry
760 // Check if N (contig bit) is set, if yes we have
761 // a 64K page mapping (SVNAPOT Extension)
762 assert(!(pte.n) || level == 0);
763 entry.pte = pte;
764 entry.paddr = (pte.n) ?
765 pte.ppn & ~mask(NapotShift) :
766 pte.ppn;
767
768 entry.logBytes = (pte.n) ?
771
772 // Only truncate the address in non-two stage walks
773 // The truncation for two-stage is done in
774 // walkTwoStage()
775 if (walkType != TwoStage) {
776 entry.logBytes = PageShift +
778 entry.vaddr &= ~((1 << entry.logBytes) - 1);
779 }
780
781 // put it non-writable into the TLB to detect
782 // writes and redo the page table walk in order
783 // to update the dirty flag
784 if (!pte.d && mode != BaseMMU::Write)
785 entry.pte.w = 0;
786
787 // Don't do TLB insert here when ending TwoStage.
788 // An additional GStage is done in walkTwoStage()
789 // and then we insert.
790 // Also don't insert on special_access
791 if (walkType != TwoStage && !memaccess.bypassTLB())
792 stepWalkFlags.doTLBInsert = true;
793 }
794
795 // Update statistics for completed page walks
796 if (level == 1) {
797 walker->pagewalkerstats.num_2mb_walks++;
798 }
799 if (level == 0) {
800 walker->pagewalkerstats.num_4kb_walks++;
801 }
802 DPRINTF(PageTableWalker,
803 "#1 leaf node at level %d, with vpn %#x\n",
804 level, entry.vaddr);
805 }
806 }
807 // PTE is not a leaf and there was no fault, decrement level
808 else if (fault == NoFault) {
809 Addr shift, idx;
810 level--;
811 if (level < 0)
812 {
813 stepWalkFlags.doEndWalk = true;
814 fault = pageFault();
815 }
816 else {
818 idx = (entry.vaddr >> shift) & mask(SV39_LEVEL_BITS);
819 nextRead = (pte.ppn << PageShift) + (idx * sizeof(pte));
821 }
822 }
823 } else {
824 stepWalkFlags.doEndWalk = true;
825 }
826
827 PacketPtr oldRead = read;
828 Request::Flags flags = oldRead->req->getFlags();
829
830 if (stepWalkFlags.doEndWalk) {
831 // If we need to write, adjust the read packet to write the modified
832 // value back to memory.
833 if (!functional && stepWalkFlags.doWrite &&
835 {
836 write = oldRead;
837 write->setLE<uint64_t>(pte);
838 write->cmd = MemCmd::WriteReq;
839 read = NULL;
840 } else {
841 write = NULL;
842 }
843
844 if (stepWalkFlags.doTLBInsert) {
845 if (!functional && !memaccess.bypassTLB()) {
846 Addr vpn = getVPNFromVAddr(entry.vaddr, satp.mode);
847 walker->tlb->insert(vpn, entry);
848 }
849 }
850 endWalk();
851 }
852 else {
853 //If we didn't return, we're setting up another read.
854 RequestPtr request = std::make_shared<Request>(
855 nextRead, oldRead->getSize(), flags, walker->requestorId);
856
857 delete oldRead;
858 oldRead = nullptr;
859
860 read = new Packet(request, MemCmd::ReadReq);
861 read->allocate();
862 }
863
864 return fault;
865}
866
867Fault
869{
870 assert(gstate != Ready && gstate != Waiting);
871
872 Fault fault = NoFault;
873 write = NULL;
874 PTESv39 pte = read->getLE<uint64_t>();
875 Addr nextRead = 0;
876
877 // walk flags are initialized to false
878 WalkFlags stepWalkFlags;
879
880 DPRINTF(PageTableWalker, "[GSTAGE]: Got level%d PTE: %#x\n", glevel, pte);
881
882 // step 2:
883 // Performing PMA/PMP checks on physical address of PTE
884
885 // Effective privilege mode for pmp checks for page table
886 // walks is S mode according to specs
887 fault = walker->pmp->pmpCheck(read->req, BaseMMU::Read,
889
890 if (fault == NoFault) {
891 fault = walker->pma->check(read->req, BaseMMU::Read, entry.vaddr);
892 }
893
894 if (fault == NoFault) {
895
896 fault = checkPTEPermissions(pte, stepWalkFlags, glevel);
897
898 if (fault == NoFault && stepWalkFlags.pteIsLeaf) {
899
900 if (stepWalkFlags.doWrite) {
901
902 // this read will eventually become write
903 // if doWrite is True
904
905 fault = walker->pmp->pmpCheck(read->req,
906 BaseMMU::Write, pmode, tc, entry.vaddr);
907
908 if (fault == NoFault) {
909 fault = walker->pma->check(read->req,
910 BaseMMU::Write, entry.vaddr);
911 }
912 }
913
914 // perform next step only if pmp checks pass
915 if (fault == NoFault) {
916 // Only change TLB entry if walk is
917 // GStageOnly. Otherwise the entry is produced
918 // at the end of the two-stage walk.
919 // (we do not currently store intermediate GStage
920 // results)
921 if (walkType == GstageOnly)
922 {
923 // Check if N (contig bit) is set, if yes we have
924 // a 64K page mapping (SVNAPOT Extension)
925 assert(!(pte.n) || glevel == 0);
926 entry.pte = pte;
927 entry.paddr = (pte.n) ?
928 pte.ppn & ~mask(NapotShift) :
929 pte.ppn;
930
931 entry.logBytes = (pte.n) ?
934
935 entry.vaddr &= ~((1 << entry.logBytes) - 1);
936
937 // put it non-writable into the TLB to detect
938 // writes and redo the page table walk in order
939 // to update the dirty flag.
940 if (!pte.d && mode != BaseMMU::Write)
941 entry.pte.w = 0;
942
943 // Also don't do TLB inserts on special_access
944 if (!memaccess.bypassTLB())
945 stepWalkFlags.doTLBInsert = true;
946 }
947 else {
948 gresult.logBytes = PageShift +
950 gresult.paddr = pte.ppn;
951 gresult.vaddr &= ~((1 << entry.logBytes) - 1);
952 gresult.pte = pte;
953 }
954
955 // Update statistics for completed page walks
956 if (glevel == 1) {
957 walker->pagewalkerstats.num_2mb_walks++;
958 }
959 if (glevel == 0) {
960 if (pte.n) {
961 walker->pagewalkerstats.num_64kb_walks++;
962 }
963 else {
964 walker->pagewalkerstats.num_4kb_walks++;
965 }
966 }
967 DPRINTF(PageTableWalker,
968 "[GSTAGE] #1 leaf node at level %d, with vpn %#x\n",
969 glevel, gresult.vaddr);
970 }
971 }
972 else if (fault == NoFault) {
973 Addr shift, idx;
974 glevel--;
975 if (glevel < 0)
976 {
977 stepWalkFlags.doEndWalk = true;
978 fault = pageFault();
979 }
980 else {
982 idx = (gresult.vaddr >> shift) & mask(SV39_LEVEL_BITS);
983 nextRead = (pte.ppn << PageShift) + (idx * sizeof(pte));
985 }
986 }
987 } else {
988 stepWalkFlags.doEndWalk = true;
989 }
990
991 PacketPtr oldRead = read;
992 Request::Flags flags = oldRead->req->getFlags();
993
994 if (stepWalkFlags.doEndWalk) {
995 // If we need to write, adjust the read packet to write the modified
996 // value back to memory.
997 if (!functional && stepWalkFlags.doWrite)
998 {
999 write = oldRead;
1000 write->setLE<uint64_t>(pte);
1001 write->cmd = MemCmd::WriteReq;
1002 read = NULL;
1003 }
1004 else {
1005 write = NULL;
1006 }
1007
1008 if (stepWalkFlags.doTLBInsert) {
1009 if (!functional && !memaccess.bypassTLB()) {
1010 // This TLB insertion should only be reachable
1011 // for GstageOnly walks. Two stage walks insert
1012 // in walkTwoStage.
1013 assert(walkType == GstageOnly);
1014 Addr vpn = getVPNFromVAddr(entry.vaddr, satp.mode);
1015 walker->tlb->insert(vpn, entry);
1016 }
1017 }
1018 endWalk();
1019 }
1020 else {
1021 //If we didn't return, we're setting up another read.
1022 RequestPtr request = std::make_shared<Request>(
1023 nextRead, oldRead->getSize(), flags, walker->requestorId);
1024
1025 delete oldRead;
1026 oldRead = nullptr;
1027
1028 read = new Packet(request, MemCmd::ReadReq);
1029 read->allocate();
1030 }
1031
1032 return fault;
1033}
1034
1035void
1037{
1038 nextState = Ready;
1039 delete read;
1040 read = NULL;
1041}
1042
1043Addr
1045{
1046 Addr shift;
1047 Addr idx;
1048 Addr pte_addr;
1049
1050 if (curstage == FIRST_STAGE) {
1051 //vaddr = Addr(sext<SV39_VADDR_BITS>(vaddr));
1053 idx = (vaddr >> shift) & mask(SV39_LEVEL_BITS);
1054 pte_addr = (satp.ppn << PageShift) + (idx * sizeof(PTESv39));
1055
1056 // original vaddress for first-stage is in entry.vaddr already
1057 }
1058 else if (curstage == GSTAGE) {
1060 idx = (vaddr >> shift) &
1062 pte_addr = ((hgatp.ppn << PageShift) & ~mask(2)) +
1063 (idx * sizeof(PTESv39));
1064
1065 gresult.vaddr = vaddr; // store original address for g-stage
1066 }
1067 else {
1068 panic("Unknown translation stage!");
1069 }
1070
1071 return pte_addr;
1072}
1073
1074bool
1076{
1077 assert(pkt->isResponse());
1078 assert(inflight);
1079 assert(state == Waiting);
1080 inflight--;
1081 if (squashed) {
1082 // if were were squashed, return true once inflight is zero and
1083 // this WalkerState will be freed there.
1084 return (inflight == 0);
1085 }
1086 if (pkt->isRead()) {
1087 // should not have a pending read it we also had one outstanding
1088 assert(!read);
1089
1090 // @todo someone should pay for this
1091 pkt->headerDelay = pkt->payloadDelay = 0;
1092
1093 state = nextState;
1094 nextState = Ready;
1095 PacketPtr write = NULL;
1096 read = pkt;
1097 timingFault = stepWalk(write);
1098 state = Waiting;
1099 assert(timingFault == NoFault || read == NULL);
1100 if (write) {
1101 writes.push_back(write);
1102 }
1103 sendPackets();
1104 } else {
1105 delete pkt;
1106
1107 sendPackets();
1108 }
1109 if (inflight == 0 && read == NULL && writes.size() == 0) {
1110 state = Ready;
1112 if (timingFault == NoFault) {
1113 /*
1114 * Finish the translation. Now that we know the right entry is
1115 * in the TLB, this should work with no memory accesses.
1116 * There could be new faults unrelated to the table walk like
1117 * permissions violations, so we'll need the return value as
1118 * well.
1119 */
1120 Addr vaddr = req->getVaddr();
1122 Addr paddr = walker->tlb->hiddenTranslateWithTLB(vaddr, satp.asid,
1123 satp.mode, mode);
1124
1125 req->setPaddr(paddr);
1126
1127 // do pmp check if any checking condition is met.
1128 // timingFault will be NoFault if pmp checks are
1129 // passed, otherwise an address fault will be returned.
1130 timingFault = walker->pmp->pmpCheck(req, mode, pmode, tc);
1131
1132 if (timingFault == NoFault) {
1133 timingFault = walker->pma->check(req, mode);
1134 }
1135
1136 // Let the CPU continue.
1137 translation->finish(timingFault, req, tc, mode);
1138 } else {
1139 // There was a fault during the walk. Let the CPU know.
1140 translation->finish(timingFault, req, tc, mode);
1141 }
1142 return true;
1143 }
1144
1145 return false;
1146}
1147
1148void
1150{
1151 //If we're already waiting for the port to become available, just return.
1152 if (retrying)
1153 return;
1154
1155 //Reads always have priority
1156 if (read) {
1157 PacketPtr pkt = read;
1158 read = NULL;
1159 inflight++;
1160 if (!walker->sendTiming(this, pkt)) {
1161 retrying = true;
1162 read = pkt;
1163 inflight--;
1164 return;
1165 }
1166 }
1167 //Send off as many of the writes as we can.
1168 while (writes.size()) {
1169 PacketPtr write = writes.back();
1170 writes.pop_back();
1171 inflight++;
1172 if (!walker->sendTiming(this, write)) {
1173 retrying = true;
1174 writes.push_back(write);
1175 inflight--;
1176 return;
1177 }
1178 }
1179}
1180
1183{
1185 RequestPtr request = std::make_shared<Request>(
1186 paddr, bytes, flags, walker->requestorId);
1187 PacketPtr pkt = new Packet(request, cmd);
1188 pkt->allocate();
1189 return pkt;
1190}
1191
1192unsigned
1194{
1195 return inflight;
1196}
1197
1198bool
1203
1204bool
1206{
1207 return timing;
1208}
1209
1210bool
1212{
1213 return started;
1214}
1215
1216void
1218{
1219 squashed = true;
1220}
1221
1222void
1224{
1225 retrying = false;
1226 sendPackets();
1227}
1228
1229Fault
1231{
1232 return walker->tlb->createPagefault(entry.vaddr, mode,
1233 gresult.vaddr, curstage == GSTAGE, memaccess.virt);
1234}
1235
1237 : statistics::Group(parent),
1238 ADD_STAT(num_4kb_walks, statistics::units::Count::get(),
1239 "Completed page walks with 4KB pages"),
1240 ADD_STAT(num_64kb_walks, statistics::units::Count::get(),
1241 "Completed page walks with 64KB pages"),
1242 ADD_STAT(num_2mb_walks, statistics::units::Count::get(),
1243 "Completed page walks with 2MB pages")
1244{
1245}
1246
1247} // namespace RiscvISA
1248} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
virtual bool squashed() const
This function is used by the page table walker to determine if it should translate the a pending requ...
Definition mmu.hh:84
virtual void finish(const Fault &fault, const RequestPtr &req, ThreadContext *tc, BaseMMU::Mode mode)=0
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
Cycles is a wrapper class for representing cycle counts, i.e.
Definition types.hh:79
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
bool isRead() const
Definition packet.hh:593
void setLE(T v)
Set the value in the data pointer to v as little endian.
bool isResponse() const
Definition packet.hh:598
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition packet.hh:449
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition packet.hh:431
void pushSenderState(SenderState *sender_state)
Push a new sender state to the packet and make the current sender state the predecessor of the new on...
Definition packet.cc:334
SenderState * popSenderState()
Pop the top of the state stack and return a pointer to it.
Definition packet.cc:342
RequestPtr req
A pointer to the original request.
Definition packet.hh:377
unsigned getSize() const
Definition packet.hh:817
MemCmd cmd
The command field of the packet.
Definition packet.hh:372
void allocate()
Allocate memory for the packet.
Definition packet.hh:1367
Ports are used to interface objects to each other.
Definition port.hh:62
uint8_t ArchFlagsType
Definition request.hh:101
@ PHYSICAL
The virtual address is also the physical address.
Definition request.hh:117
gem5::Flags< FlagsType > Flags
Definition request.hh:102
void recvReqRetry()
Called by the peer if sendTimingReq was called on this peer (causing recvTimingReq to be called on th...
bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
Fault startFunctional(Addr &addr, unsigned &logBytes)
PacketPtr createReqPacket(Addr paddr, MemCmd cmd, size_t bytes)
Fault checkPTEPermissions(PTESv39 pte, WalkFlags &stepWalkFlags, int level)
Fault walkGStage(Addr guest_paddr, Addr &host_paddr)
void initState(ThreadContext *_tc, BaseMMU::Mode _mode, bool _isTiming=false)
Fault startFunctional(ThreadContext *_tc, Addr &addr, unsigned &logBytes, BaseMMU::Mode mode)
EventFunctionWrapper startWalkWrapperEvent
Event used to call startWalkWrapper.
Fault start(ThreadContext *_tc, BaseMMU::Translation *translation, const RequestPtr &req, BaseMMU::Mode mode, TlbEntry *result_entry=nullptr)
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
bool sendTiming(WalkerState *sendingState, PacketPtr pkt)
bool recvTimingResp(PacketPtr pkt)
std::list< WalkerState * > currStates
ThreadContext is the external interface to all thread state for anything outside of the CPU.
Statistics container.
Definition group.hh:93
STL list class.
Definition stl.hh:51
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition group.hh:75
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition bitfield.hh:79
constexpr uint64_t sext(uint64_t val)
Sign-extend an N-bit value to 64 bits.
Definition bitfield.hh:129
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:246
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Bitfield< 27, 24 > gpa
Bitfield< 9 > e
Definition misc_types.hh:65
Bitfield< 6, 5 > shift
Definition types.hh:117
Bitfield< 43, 0 > ppn
Definition pagetable.hh:48
const Addr NapotShift
Definition page_size.hh:55
const Addr SV39X4_WIDENED_BITS
Definition pagetable.hh:64
const Addr SV39_VADDR_BITS
Definition pagetable.hh:61
Addr getVPNFromVAddr(Addr vaddr, Addr mode)
Definition pagetable.cc:64
const Addr PageShift
Definition page_size.hh:53
@ FIRST_STAGE
Definition tlb.hh:80
const Addr SV39_LEVELS
Definition pagetable.hh:62
@ MISCREG_STATUS
Definition misc.hh:78
const Addr SV39_LEVEL_BITS
Definition pagetable.hh:63
Bitfield< 3 > addr
Definition types.hh:84
Units for Stats.
Definition units.hh:113
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
std::shared_ptr< FaultBase > Fault
Definition types.hh:249
std::shared_ptr< Request > RequestPtr
Definition request.hh:94
uint64_t RegVal
Definition types.hh:173
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition types.hh:245
Packet * PacketPtr
constexpr decltype(nullptr) NoFault
Definition types.hh:253
Declaration of a request, the overall memory request consisting of the parts of the request that are ...

Generated on Sat Oct 18 2025 08:06:41 for gem5 by doxygen 1.14.0