gem5 [DEVELOP-FOR-25.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
299 // Catch all walker states that have early fault!
300 while (!currStates.empty() && timingFault != NoFault) {
301 // Delete currState due to early fault
302 currStates.pop_front();
303 delete currState;
304
305 // Get next currState & walk
306 if (currStates.size() > 0) {
307 currState = currStates.front();
308 timingFault = currState->walk();
309 }
310 }
311 }
312 else {
314 }
315 }
316}
317
318Fault
320{
321 Fault fault = NoFault;
323
324
325 // reset gresult in case we were called again
326 // in a two stage translation
327 gresult.reset();
328 gresult.vaddr = guest_paddr;
329
332
333
334 const int maxgpabits = SV39_LEVELS * SV39_LEVEL_BITS +
336 Addr maxgpa = mask(maxgpabits);
337
338 // If there is a bit beyond maxgpa, throw pf
339 if (guest_paddr & ~maxgpa) {
340 return pageFault();
341 }
342
343 // If there is another read packet,
344 // deallocate it, gstage creates a new packet
345 if (read) {
346 delete read;
347 read = nullptr;
348 }
349
350 Addr pte_addr = setupWalk(guest_paddr);
351 read = createReqPacket(pte_addr, MemCmd::ReadReq, sizeof(PTESv39));
352 glevel = SV39_LEVELS - 1;
353
354 // TODO THE TIMING PATH IS UNTESTED
355 if (timing) {
356 panic("unimpl");
358 gstate = Waiting;
360 sendPackets();
361 }
362 else {
363 do {
364 walker->port.sendAtomic(read);
365 PacketPtr write = NULL;
366 fault = stepWalkGStage(write);
367 assert(fault == NoFault || read == NULL);
370 if (write) {
371 walker->port.sendAtomic(write);
372 }
373 } while (read);
374
375 if (fault) {
376 return fault;
377 }
378
379 // In GStageOnly result is in entry (which is put in TLB)
380 // otherwise it's a two stage walk so result is in gresult
381 // which is discarded after.
382 Addr ppn = walkType == GstageOnly ? entry.paddr : gresult.paddr;
383 Addr vpn = guest_paddr >> PageShift;
384 Addr vpn_bits = vpn & mask(glevel * SV39_LEVEL_BITS);
385
386 // Update gresult
387 gresult.paddr = (ppn | vpn_bits);
388
389 host_paddr = ((ppn | vpn_bits) << PageShift) |
390 (guest_paddr & mask(PageShift));
391
392 gstate = Ready;
394 }
395 return fault;
396}
397
398Fault
400{
401 Fault fault = NoFault;
402 assert(!started);
403 started = true;
406
407 // This is the vaddr to walk for
408 Addr vaddr = entry.vaddr;
409
410 // Decide the type of walk to perform
411 // When memaccess is virtual, GStage is enabled
412 if (satp.mode == AddrXlateMode::BARE && memaccess.virt) {
413 // In this case VSATP (== satp) is bare and
414 // we do G-stage translation only
415 Addr paddr;
417 fault = walkGStage(vaddr, paddr);
418 }
419 else if (memaccess.virt) {
421 fault = walkTwoStage(vaddr);
422 }
423 else {
425 fault = walkOneStage(vaddr);
426 }
427
428 return fault;
429}
430
431
432Fault
434{
435
437
438 // Make sure MSBS are the same
439 // riscv-privileged-20211203 page 84
440 auto mask_for_msbs = mask(64 - SV39_VADDR_BITS);
441 auto msbs = bits(vaddr, 63, SV39_VADDR_BITS);
442 if (msbs != 0 && msbs != mask_for_msbs) {
443 return pageFault();
444 }
445
446 Addr pte_addr = setupWalk(vaddr);
447 level = SV39_LEVELS - 1;
448 // Create physical request for first_pte_addr
449 // This is a host physical address
450 // In two-stage this gets discarded?
451 read = createReqPacket(pte_addr,
452 MemCmd::ReadReq, sizeof(PTESv39));
453
454 if (timing)
455 {
456 MISA misa = tc->readMiscReg(MISCREG_ISA);
457 panic_if(misa.rvh, "Timing walks are not supported with h extension");
459 state = Waiting;
461 // DO GSTAGE HERE IF NEEDED AND THEN DO PACKETS FOR *PTE
462 sendPackets();
463 return NoFault;
464 }
465
466 Fault fault = NoFault;
467 do
468 {
469 if (functional) {
470 walker->port.sendFunctional(read);
471 }
472 else {
473 walker->port.sendAtomic(read);
474 }
475
476 PacketPtr write = NULL;
477 fault = stepWalk(write);
478 assert(fault == NoFault || read == NULL);
481
482 // On a functional access (page table lookup), writes should
483 // not happen so this pointer is ignored after stepWalk
484 if (write && !functional) {
485 walker->port.sendAtomic(write);
486 }
487 } while (read);
488
489 state = Ready;
491 return fault;
492}
493
494
495
496
497
498Fault
500{
502
503 // Make sure MSBS are the same
504 // riscv-privileged-20211203 page 84
505 auto mask_for_msbs = mask(64 - SV39_VADDR_BITS);
506 auto msbs = bits(vaddr, 63, SV39_VADDR_BITS);
507 if (msbs != 0 && msbs != mask_for_msbs) {
508 return pageFault();
509 }
510
511 Addr pte_addr = setupWalk(vaddr);
512 level = SV39_LEVELS - 1;
513 // Create physical request for first_pte_addr
514 // This is a host physical address
515 // In two-stage this gets discarded?
516 read = createReqPacket(pte_addr,
517 MemCmd::ReadReq, sizeof(PTESv39));
518
519
520
521 if (timing)
522 {
523 MISA misa = tc->readMiscReg(MISCREG_ISA);
524 panic_if(misa.rvh, "Timing walks are not supported with h extension");
526 state = Waiting;
528 // DO GSTAGE HERE IF NEEDED AND THEN DO PACKETS FOR *PTE
529 sendPackets();
530 return NoFault;
531 }
532
533 Fault fault = NoFault;
534 do
535 {
536 // This is a "virtual" access, pte_address
537 // is guest physical (host virtual) so pass through
538 // G-stage before making a request to physmem.
539 Addr guest_paddr = pte_addr;
540 Addr host_paddr;
541
542 fault = walkGStage(guest_paddr, host_paddr);
543 if (fault != NoFault) { return fault; }
544 pte_addr = host_paddr;
545
546 // Create the physmem packet to be sent
547 read = createReqPacket(pte_addr,
548 MemCmd::ReadReq, sizeof(PTESv39));
549
550 // G-stage done go back to first_stage logic
552
553
554 if (functional) {
555 walker->port.sendFunctional(read);
556 } else {
557 walker->port.sendAtomic(read);
558 }
559
560 PacketPtr write = NULL;
561 fault = stepWalk(write);
562
563 // Set up next vpte_addr for GStage
564 // This read packet should not be sent to mem
565 // paddr contains a virtual (guest physical) address
566 if (read && fault == NoFault) {
567 pte_addr = read->req->getPaddr();
568 }
569
570 assert(fault == NoFault || read == NULL);
573
574 // On a functional access (page table lookup), writes should
575 // not happen so this pointer is ignored after stepWalk
576 if (write && !functional) {
577 walker->port.sendAtomic(write);
578 }
579 } while (read);
580
581
582 if (fault != NoFault) {
583 return fault;
584 }
585
586 // In 2-stage walks the TLB insert is done after an
587 // additional g-stage walk
588
589 // gpa is a host virtual address.
590 // To actually get the host physical address of the page,
591 // we have to pass through GStage one final time.
592 fault = guestToHostPage(vaddr);
593
594 if (fault != NoFault) {
595 return fault;
596 }
597
598 if (!functional && !memaccess.bypassTLB()) {
599 Addr vpn = getVPNFromVAddr(entry.vaddr, satp.mode);
600 walker->tlb->insert(vpn, entry);
601 }
602
603 state = Ready;
605 return NoFault;
606}
607
608
609Fault
611{
612 Addr gpa = (((entry.paddr) |
614 << PageShift) | (vaddr & mask(PageShift));
615
616 Addr host_page_address;
617 Fault fault = walkGStage(gpa, host_page_address);
618 if (fault != NoFault) { return fault; }
619
620 // Final G-stage done, go back to first_stage logic
622
623 // gpn (vaddr) -> ppn (paddr) translation is already
624 // in gresult, host_page_address is not needed here
625 // TLB stores ppn and pte
626 // entry.logBytes = PageShift + (level * SV39_LEVEL_BITS);
627 entry.logBytes = PageShift;
628 entry.paddr = gresult.paddr;
629 entry.vaddr &= ~((1 << entry.logBytes) - 1);
630
631 // entry.pte contains guest pte
632 // host pte is in gresult.pte from final GStage
633 entry.gpte = entry.pte;
634 entry.pte = gresult.pte;
635
636 return NoFault;
637}
638
639Fault
641{
642 // Pass the addess to entry here
643 // initState cannot because there is no req object
644 entry.vaddr = addr;
645 // just call walk
646 // it takes care to do the right thing
647 // when functional is true
648 Fault fault = walk();
649 logBytes = entry.logBytes;
650 addr = entry.paddr << PageShift;
651
652 return fault;
653}
654
655
656Fault
658 PTESv39 pte, WalkFlags& stepWalkFlags, int level)
659{
660 // If valid bit is off OR
661 // the page is writable but not readable, throw pf
662 if (!pte.v || (!pte.r && pte.w)) {
663 stepWalkFlags.doEndWalk = true;
664 return pageFault();
665 }
666
667 // If read-bit or exec-bit, then PTE is a leaf
668 if (pte.r || pte.x) {
669 stepWalkFlags.pteIsLeaf = true;
670 stepWalkFlags.doEndWalk = true;
671
672 Fault fault = walker->tlb->checkPermissions(tc, memaccess,
673 entry.vaddr, mode, pte, gresult.vaddr, curstage);
674
675 if (fault != NoFault) {
676 return fault;
677 }
678
679 // ppn fragments that correspond to unused
680 // vpn fragments have to be all zeroes
681 // Otherwise, throw a pagefault
682 if (level >= 1 && pte.ppn0 != 0)
683 {
684 return pageFault();
685 }
686 else if (level == 2 && pte.ppn1 != 0)
687 {
688 return pageFault();
689 }
690
691 if (pte.n && (pte.ppn0 & mask(NapotShift)) != 8) {
692 DPRINTF(PageTableWalker,
693 "SVNAPOT PTE has wrong encoding, \
694 raising PF\n");
695 fault = pageFault();
696 }
697
698 // Check if we need to write
699 if (!pte.a) {
700 pte.a = 1;
701 stepWalkFlags.doWrite = true;
702 }
703 if (!pte.d && mode == BaseMMU::Write) {
704 pte.d = 1;
705 stepWalkFlags.doWrite = true;
706 }
707 }
708
709 return NoFault;
710}
711
712Fault
714{
715 assert(state != Ready && state != Waiting);
716
717 Fault fault = NoFault;
718 write = NULL;
719 PTESv39 pte = read->getLE<uint64_t>();
720 Addr nextRead = 0;
721
722 // walk flags are initialized to false
723 WalkFlags stepWalkFlags;
724
725 DPRINTF(PageTableWalker, "Got level%d PTE: %#x\n", level, pte);
726
727 // step 2:
728 // Performing PMA/PMP checks on physical address of PTE
729
730 // Effective privilege mode for pmp checks for page table
731 // walks is S mode according to specs
732 fault = walker->pmp->pmpCheck(read->req, BaseMMU::Read,
734
735 if (fault == NoFault) {
736 fault = walker->pma->check(read->req, BaseMMU::Read, entry.vaddr);
737 }
738
739 if (fault == NoFault) {
740
741 fault = checkPTEPermissions(pte, stepWalkFlags, level);
742
743 if (fault == NoFault && stepWalkFlags.pteIsLeaf) {
744
745 if (stepWalkFlags.doWrite) {
746
747 // this read will eventually become write
748 // if doWrite is True
749
750 fault = walker->pmp->pmpCheck(read->req,
751 BaseMMU::Write, pmode, tc, entry.vaddr);
752
753 if (fault == NoFault) {
754 fault = walker->pma->check(read->req,
755 BaseMMU::Write, entry.vaddr);
756 }
757 }
758
759 // perform next step only if pmp checks pass
760 if (fault == NoFault) {
761 // TLB inserts are OK for single stage walks
762 // For two-stage, FIRST_STAGE will reach here just once
763 // but the TLB insertion is done in walkTwoStage()
764 if (walkType == OneStage ||
766 {
767 // Fill in TLB entry
768 // Check if N (contig bit) is set, if yes we have
769 // a 64K page mapping (SVNAPOT Extension)
770 assert(!(pte.n) || level == 0);
771 entry.pte = pte;
772 entry.paddr = (pte.n) ?
773 pte.ppn & ~mask(NapotShift) :
774 pte.ppn;
775
776 entry.logBytes = (pte.n) ?
779
780 // Only truncate the address in non-two stage walks
781 // The truncation for two-stage is done in
782 // walkTwoStage()
783 if (walkType != TwoStage) {
784 entry.logBytes = PageShift +
786 entry.vaddr &= ~((1 << entry.logBytes) - 1);
787 }
788
789 // put it non-writable into the TLB to detect
790 // writes and redo the page table walk in order
791 // to update the dirty flag
792 if (!pte.d && mode != BaseMMU::Write)
793 entry.pte.w = 0;
794
795 // Don't do TLB insert here when ending TwoStage.
796 // An additional GStage is done in walkTwoStage()
797 // and then we insert.
798 // Also don't insert on special_access
799 if (walkType != TwoStage && !memaccess.bypassTLB())
800 stepWalkFlags.doTLBInsert = true;
801 }
802
803 // Update statistics for completed page walks
804 if (level == 1) {
805 walker->pagewalkerstats.num_2mb_walks++;
806 }
807 if (level == 0) {
808 walker->pagewalkerstats.num_4kb_walks++;
809 }
810 DPRINTF(PageTableWalker,
811 "#1 leaf node at level %d, with vpn %#x\n",
812 level, entry.vaddr);
813 }
814 }
815 // PTE is not a leaf and there was no fault, decrement level
816 else if (fault == NoFault) {
817 Addr shift, idx;
818 level--;
819 if (level < 0)
820 {
821 stepWalkFlags.doEndWalk = true;
822 fault = pageFault();
823 }
824 else {
826 idx = (entry.vaddr >> shift) & mask(SV39_LEVEL_BITS);
827 nextRead = (pte.ppn << PageShift) + (idx * sizeof(pte));
829 }
830 }
831 } else {
832 stepWalkFlags.doEndWalk = true;
833 }
834
835 PacketPtr oldRead = read;
836 Request::Flags flags = oldRead->req->getFlags();
837
838 if (stepWalkFlags.doEndWalk) {
839 // If we need to write, adjust the read packet to write the modified
840 // value back to memory.
841 if (!functional && stepWalkFlags.doWrite &&
843 {
844 write = oldRead;
845 write->setLE<uint64_t>(pte);
846 write->cmd = MemCmd::WriteReq;
847 read = NULL;
848 } else {
849 write = NULL;
850 }
851
852 if (stepWalkFlags.doTLBInsert) {
853 if (!functional && !memaccess.bypassTLB()) {
854 Addr vpn = getVPNFromVAddr(entry.vaddr, satp.mode);
855 walker->tlb->insert(vpn, entry);
856 }
857 }
858 endWalk();
859 }
860 else {
861 //If we didn't return, we're setting up another read.
862 RequestPtr request = std::make_shared<Request>(
863 nextRead, oldRead->getSize(), flags, walker->requestorId);
864
865 delete oldRead;
866 oldRead = nullptr;
867
868 read = new Packet(request, MemCmd::ReadReq);
869 read->allocate();
870 }
871
872 return fault;
873}
874
875Fault
877{
878 assert(gstate != Ready && gstate != Waiting);
879
880 Fault fault = NoFault;
881 write = NULL;
882 PTESv39 pte = read->getLE<uint64_t>();
883 Addr nextRead = 0;
884
885 // walk flags are initialized to false
886 WalkFlags stepWalkFlags;
887
888 DPRINTF(PageTableWalker, "[GSTAGE]: Got level%d PTE: %#x\n", glevel, pte);
889
890 // step 2:
891 // Performing PMA/PMP checks on physical address of PTE
892
893 // Effective privilege mode for pmp checks for page table
894 // walks is S mode according to specs
895 fault = walker->pmp->pmpCheck(read->req, BaseMMU::Read,
897
898 if (fault == NoFault) {
899 fault = walker->pma->check(read->req, BaseMMU::Read, entry.vaddr);
900 }
901
902 if (fault == NoFault) {
903
904 fault = checkPTEPermissions(pte, stepWalkFlags, glevel);
905
906 if (fault == NoFault && stepWalkFlags.pteIsLeaf) {
907
908 if (stepWalkFlags.doWrite) {
909
910 // this read will eventually become write
911 // if doWrite is True
912
913 fault = walker->pmp->pmpCheck(read->req,
914 BaseMMU::Write, pmode, tc, entry.vaddr);
915
916 if (fault == NoFault) {
917 fault = walker->pma->check(read->req,
918 BaseMMU::Write, entry.vaddr);
919 }
920 }
921
922 // perform next step only if pmp checks pass
923 if (fault == NoFault) {
924 // Only change TLB entry if walk is
925 // GStageOnly. Otherwise the entry is produced
926 // at the end of the two-stage walk.
927 // (we do not currently store intermediate GStage
928 // results)
929 if (walkType == GstageOnly)
930 {
931 // Check if N (contig bit) is set, if yes we have
932 // a 64K page mapping (SVNAPOT Extension)
933 assert(!(pte.n) || glevel == 0);
934 entry.pte = pte;
935 entry.paddr = (pte.n) ?
936 pte.ppn & ~mask(NapotShift) :
937 pte.ppn;
938
939 entry.logBytes = (pte.n) ?
942
943 entry.vaddr &= ~((1 << entry.logBytes) - 1);
944
945 // put it non-writable into the TLB to detect
946 // writes and redo the page table walk in order
947 // to update the dirty flag.
948 if (!pte.d && mode != BaseMMU::Write)
949 entry.pte.w = 0;
950
951 // Also don't do TLB inserts on special_access
952 if (!memaccess.bypassTLB())
953 stepWalkFlags.doTLBInsert = true;
954 }
955 else {
956 gresult.logBytes = PageShift +
958 gresult.paddr = pte.ppn;
959 gresult.vaddr &= ~((1 << entry.logBytes) - 1);
960 gresult.pte = pte;
961 }
962
963 // Update statistics for completed page walks
964 if (glevel == 1) {
965 walker->pagewalkerstats.num_2mb_walks++;
966 }
967 if (glevel == 0) {
968 if (pte.n) {
969 walker->pagewalkerstats.num_64kb_walks++;
970 }
971 else {
972 walker->pagewalkerstats.num_4kb_walks++;
973 }
974 }
975 DPRINTF(PageTableWalker,
976 "[GSTAGE] #1 leaf node at level %d, with vpn %#x\n",
977 glevel, gresult.vaddr);
978 }
979 }
980 else if (fault == NoFault) {
981 Addr shift, idx;
982 glevel--;
983 if (glevel < 0)
984 {
985 stepWalkFlags.doEndWalk = true;
986 fault = pageFault();
987 }
988 else {
990 idx = (gresult.vaddr >> shift) & mask(SV39_LEVEL_BITS);
991 nextRead = (pte.ppn << PageShift) + (idx * sizeof(pte));
993 }
994 }
995 } else {
996 stepWalkFlags.doEndWalk = true;
997 }
998
999 PacketPtr oldRead = read;
1000 Request::Flags flags = oldRead->req->getFlags();
1001
1002 if (stepWalkFlags.doEndWalk) {
1003 // If we need to write, adjust the read packet to write the modified
1004 // value back to memory.
1005 if (!functional && stepWalkFlags.doWrite)
1006 {
1007 write = oldRead;
1008 write->setLE<uint64_t>(pte);
1009 write->cmd = MemCmd::WriteReq;
1010 read = NULL;
1011 }
1012 else {
1013 write = NULL;
1014 }
1015
1016 if (stepWalkFlags.doTLBInsert) {
1017 if (!functional && !memaccess.bypassTLB()) {
1018 // This TLB insertion should only be reachable
1019 // for GstageOnly walks. Two stage walks insert
1020 // in walkTwoStage.
1021 assert(walkType == GstageOnly);
1022 Addr vpn = getVPNFromVAddr(entry.vaddr, satp.mode);
1023 walker->tlb->insert(vpn, entry);
1024 }
1025 }
1026 endWalk();
1027 }
1028 else {
1029 //If we didn't return, we're setting up another read.
1030 RequestPtr request = std::make_shared<Request>(
1031 nextRead, oldRead->getSize(), flags, walker->requestorId);
1032
1033 delete oldRead;
1034 oldRead = nullptr;
1035
1036 read = new Packet(request, MemCmd::ReadReq);
1037 read->allocate();
1038 }
1039
1040 return fault;
1041}
1042
1043void
1045{
1046 nextState = Ready;
1047 delete read;
1048 read = NULL;
1049}
1050
1051Addr
1053{
1054 Addr shift;
1055 Addr idx;
1056 Addr pte_addr;
1057
1058 if (curstage == FIRST_STAGE) {
1059 //vaddr = Addr(sext<SV39_VADDR_BITS>(vaddr));
1061 idx = (vaddr >> shift) & mask(SV39_LEVEL_BITS);
1062 pte_addr = (satp.ppn << PageShift) + (idx * sizeof(PTESv39));
1063
1064 // original vaddress for first-stage is in entry.vaddr already
1065 }
1066 else if (curstage == GSTAGE) {
1068 idx = (vaddr >> shift) &
1070 pte_addr = ((hgatp.ppn << PageShift) & ~mask(2)) +
1071 (idx * sizeof(PTESv39));
1072
1073 gresult.vaddr = vaddr; // store original address for g-stage
1074 }
1075 else {
1076 panic("Unknown translation stage!");
1077 }
1078
1079 return pte_addr;
1080}
1081
1082bool
1084{
1085 assert(pkt->isResponse());
1086 assert(inflight);
1087 assert(state == Waiting);
1088 inflight--;
1089 if (squashed) {
1090 // if were were squashed, return true once inflight is zero and
1091 // this WalkerState will be freed there.
1092 return (inflight == 0);
1093 }
1094 if (pkt->isRead()) {
1095 // should not have a pending read it we also had one outstanding
1096 assert(!read);
1097
1098 // @todo someone should pay for this
1099 pkt->headerDelay = pkt->payloadDelay = 0;
1100
1101 state = nextState;
1102 nextState = Ready;
1103 PacketPtr write = NULL;
1104 read = pkt;
1105 timingFault = stepWalk(write);
1106 state = Waiting;
1107 assert(timingFault == NoFault || read == NULL);
1108 if (write) {
1109 writes.push_back(write);
1110 }
1111 sendPackets();
1112 } else {
1113 delete pkt;
1114
1115 sendPackets();
1116 }
1117 if (inflight == 0 && read == NULL && writes.size() == 0) {
1118 state = Ready;
1120 if (timingFault == NoFault) {
1121 /*
1122 * Finish the translation. Now that we know the right entry is
1123 * in the TLB, this should work with no memory accesses.
1124 * There could be new faults unrelated to the table walk like
1125 * permissions violations, so we'll need the return value as
1126 * well.
1127 */
1128 Addr vaddr = req->getVaddr();
1130 Addr paddr = walker->tlb->hiddenTranslateWithTLB(vaddr, satp.asid,
1131 satp.mode, mode);
1132
1133 req->setPaddr(paddr);
1134
1135 // do pmp check if any checking condition is met.
1136 // timingFault will be NoFault if pmp checks are
1137 // passed, otherwise an address fault will be returned.
1138 timingFault = walker->pmp->pmpCheck(req, mode, pmode, tc);
1139
1140 if (timingFault == NoFault) {
1141 timingFault = walker->pma->check(req, mode);
1142 }
1143
1144 // Let the CPU continue.
1145 translation->finish(timingFault, req, tc, mode);
1146 } else {
1147 // There was a fault during the walk. Let the CPU know.
1148 translation->finish(timingFault, req, tc, mode);
1149 }
1150 return true;
1151 }
1152
1153 return false;
1154}
1155
1156void
1158{
1159 //If we're already waiting for the port to become available, just return.
1160 if (retrying)
1161 return;
1162
1163 //Reads always have priority
1164 if (read) {
1165 PacketPtr pkt = read;
1166 read = NULL;
1167 inflight++;
1168 if (!walker->sendTiming(this, pkt)) {
1169 retrying = true;
1170 read = pkt;
1171 inflight--;
1172 return;
1173 }
1174 }
1175 //Send off as many of the writes as we can.
1176 while (writes.size()) {
1177 PacketPtr write = writes.back();
1178 writes.pop_back();
1179 inflight++;
1180 if (!walker->sendTiming(this, write)) {
1181 retrying = true;
1182 writes.push_back(write);
1183 inflight--;
1184 return;
1185 }
1186 }
1187}
1188
1191{
1193 RequestPtr request = std::make_shared<Request>(
1194 paddr, bytes, flags, walker->requestorId);
1195 PacketPtr pkt = new Packet(request, cmd);
1196 pkt->allocate();
1197 return pkt;
1198}
1199
1200unsigned
1202{
1203 return inflight;
1204}
1205
1206bool
1211
1212bool
1214{
1215 return timing;
1216}
1217
1218bool
1220{
1221 return started;
1222}
1223
1224void
1226{
1227 squashed = true;
1228}
1229
1230void
1232{
1233 retrying = false;
1234 sendPackets();
1235}
1236
1237Fault
1239{
1240 return walker->tlb->createPagefault(entry.vaddr, mode,
1241 gresult.vaddr, curstage == GSTAGE, memaccess.virt);
1242}
1243
1245 : statistics::Group(parent),
1246 ADD_STAT(num_4kb_walks, statistics::units::Count::get(),
1247 "Completed page walks with 4KB pages"),
1248 ADD_STAT(num_64kb_walks, statistics::units::Count::get(),
1249 "Completed page walks with 64KB pages"),
1250 ADD_STAT(num_2mb_walks, statistics::units::Count::get(),
1251 "Completed page walks with 2MB pages")
1252{
1253}
1254
1255} // namespace RiscvISA
1256} // 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 Mon Oct 27 2025 04:12:59 for gem5 by doxygen 1.14.0