gem5 v23.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)
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->startWalk();
89 if (!newState->isTiming()) {
90 currStates.pop_front();
91 delete newState;
92 }
93 return fault;
94 }
95}
96
98Walker::startFunctional(ThreadContext * _tc, Addr &addr, unsigned &logBytes,
99 BaseMMU::Mode _mode)
100{
101 funcState.initState(_tc, _mode);
102 return funcState.startFunctional(addr, logBytes);
103}
104
105bool
107{
108 return walker->recvTimingResp(pkt);
109}
110
111bool
113{
114 WalkerSenderState * senderState =
115 dynamic_cast<WalkerSenderState *>(pkt->popSenderState());
116 WalkerState * senderWalk = senderState->senderWalk;
117 bool walkComplete = senderWalk->recvPacket(pkt);
118 delete senderState;
119 if (walkComplete) {
121 for (iter = currStates.begin(); iter != currStates.end(); iter++) {
122 WalkerState * walkerState = *(iter);
123 if (walkerState == senderWalk) {
124 iter = currStates.erase(iter);
125 break;
126 }
127 }
128 delete senderWalk;
129 // Since we block requests when another is outstanding, we
130 // need to check if there is a waiting request to be serviced
132 // delay sending any new requests until we are finished
133 // with the responses
135 }
136 return true;
137}
138
139void
141{
142 walker->recvReqRetry();
143}
144
145void
147{
149 for (iter = currStates.begin(); iter != currStates.end(); iter++) {
150 WalkerState * walkerState = *(iter);
151 if (walkerState->isRetrying()) {
152 walkerState->retry();
153 }
154 }
155}
156
158{
159 WalkerSenderState* walker_state = new WalkerSenderState(sendingState);
160 pkt->pushSenderState(walker_state);
161 if (port.sendTimingReq(pkt)) {
162 return true;
163 } else {
164 // undo the adding of the sender state and delete it, as we
165 // will do it again the next time we attempt to send it
166 pkt->popSenderState();
167 delete walker_state;
168 return false;
169 }
170
171}
172
173Port &
174Walker::getPort(const std::string &if_name, PortID idx)
175{
176 if (if_name == "port")
177 return port;
178 else
179 return ClockedObject::getPort(if_name, idx);
180}
181
182void
184 BaseMMU::Mode _mode, bool _isTiming)
185{
186 assert(state == Ready);
187 started = false;
188 tc = _tc;
189 mode = _mode;
190 timing = _isTiming;
191 // fetch these now in case they change during the walk
192 status = tc->readMiscReg(MISCREG_STATUS);
193 pmode = walker->tlb->getMemPriv(tc, mode);
194 satp = tc->readMiscReg(MISCREG_SATP);
195 assert(satp.mode == AddrXlateMode::SV39);
196}
197
198void
200{
201 unsigned num_squashed = 0;
202 WalkerState *currState = currStates.front();
203 while ((num_squashed < numSquashable) && currState &&
204 currState->translation->squashed()) {
205 currStates.pop_front();
206 num_squashed++;
207
208 DPRINTF(PageTableWalker, "Squashing table walk for address %#x\n",
209 currState->req->getVaddr());
210
211 // finish the translation which will delete the translation object
212 currState->translation->finish(
213 std::make_shared<UnimpFault>("Squashed Inst"),
214 currState->req, currState->tc, currState->mode);
215
216 // delete the current request if there are no inflight packets.
217 // if there is something in flight, delete when the packets are
218 // received and inflight is zero.
219 if (currState->numInflight() == 0) {
220 delete currState;
221 } else {
222 currState->squash();
223 }
224
225 // check the next translation request, if it exists
226 if (currStates.size())
227 currState = currStates.front();
228 else
229 currState = NULL;
230 }
231 if (currState && !currState->wasStarted())
232 currState->startWalk();
233}
234
235Fault
237{
238 Fault fault = NoFault;
239 assert(!started);
240 started = true;
241 setupWalk(req->getVaddr());
242 if (timing) {
243 nextState = state;
244 state = Waiting;
245 timingFault = NoFault;
246 sendPackets();
247 } else {
248 do {
249 walker->port.sendAtomic(read);
250 PacketPtr write = NULL;
251 fault = stepWalk(write);
252 assert(fault == NoFault || read == NULL);
253 state = nextState;
254 nextState = Ready;
255 if (write)
256 walker->port.sendAtomic(write);
257 } while (read);
258 state = Ready;
259 nextState = Waiting;
260 }
261 return fault;
262}
263
264Fault
266{
267 Fault fault = NoFault;
268 assert(!started);
269 started = true;
270 setupWalk(addr);
271
272 do {
273 walker->port.sendFunctional(read);
274 // On a functional access (page table lookup), writes should
275 // not happen so this pointer is ignored after stepWalk
276 PacketPtr write = NULL;
277 fault = stepWalk(write);
278 assert(fault == NoFault || read == NULL);
279 state = nextState;
280 nextState = Ready;
281 } while (read);
282 logBytes = entry.logBytes;
283 addr = entry.paddr << PageShift;
284
285 return fault;
286}
287
288Fault
290{
291 assert(state != Ready && state != Waiting);
292 Fault fault = NoFault;
293 write = NULL;
294 PTESv39 pte = read->getLE<uint64_t>();
295 Addr nextRead = 0;
296 bool doWrite = false;
297 bool doTLBInsert = false;
298 bool doEndWalk = false;
299
300 DPRINTF(PageTableWalker, "Got level%d PTE: %#x\n", level, pte);
301
302 // step 2:
303 // Performing PMA/PMP checks on physical address of PTE
304
305 walker->pma->check(read->req);
306 // Effective privilege mode for pmp checks for page table
307 // walks is S mode according to specs
308 fault = walker->pmp->pmpCheck(read->req, BaseMMU::Read,
309 RiscvISA::PrivilegeMode::PRV_S, tc, entry.vaddr);
310
311 if (fault == NoFault) {
312 // step 3:
313 if (!pte.v || (!pte.r && pte.w)) {
314 doEndWalk = true;
315 DPRINTF(PageTableWalker, "PTE invalid, raising PF\n");
316 fault = pageFault(pte.v);
317 }
318 else {
319 // step 4:
320 if (pte.r || pte.x) {
321 // step 5: leaf PTE
322 doEndWalk = true;
323 fault = walker->tlb->checkPermissions(status, pmode,
324 entry.vaddr, mode, pte);
325
326 // step 6
327 if (fault == NoFault) {
328 if (level >= 1 && pte.ppn0 != 0) {
329 DPRINTF(PageTableWalker,
330 "PTE has misaligned PPN, raising PF\n");
331 fault = pageFault(true);
332 }
333 else if (level == 2 && pte.ppn1 != 0) {
334 DPRINTF(PageTableWalker,
335 "PTE has misaligned PPN, raising PF\n");
336 fault = pageFault(true);
337 }
338 }
339
340 if (fault == NoFault) {
341 // step 7
342 if (!pte.a) {
343 pte.a = 1;
344 doWrite = true;
345 }
346 if (!pte.d && mode == BaseMMU::Write) {
347 pte.d = 1;
348 doWrite = true;
349 }
350 // Performing PMA/PMP checks
351
352 if (doWrite) {
353
354 // this read will eventually become write
355 // if doWrite is True
356
357 walker->pma->check(read->req);
358
359 fault = walker->pmp->pmpCheck(read->req,
360 BaseMMU::Write, pmode, tc, entry.vaddr);
361
362 }
363 // perform step 8 only if pmp checks pass
364 if (fault == NoFault) {
365
366 // step 8
367 entry.logBytes = PageShift + (level * LEVEL_BITS);
368 entry.paddr = pte.ppn;
369 entry.vaddr &= ~((1 << entry.logBytes) - 1);
370 entry.pte = pte;
371 // put it non-writable into the TLB to detect
372 // writes and redo the page table walk in order
373 // to update the dirty flag.
374 if (!pte.d && mode != BaseMMU::Write)
375 entry.pte.w = 0;
376 doTLBInsert = true;
377 }
378 }
379 } else {
380 level--;
381 if (level < 0) {
382 DPRINTF(PageTableWalker, "No leaf PTE found,"
383 "raising PF\n");
384 doEndWalk = true;
385 fault = pageFault(true);
386 } else {
388 Addr idx = (entry.vaddr >> shift) & LEVEL_MASK;
389 nextRead = (pte.ppn << PageShift) + (idx * sizeof(pte));
390 nextState = Translate;
391 }
392 }
393 }
394 } else {
395 doEndWalk = true;
396 }
397 PacketPtr oldRead = read;
398 Request::Flags flags = oldRead->req->getFlags();
399
400 if (doEndWalk) {
401 // If we need to write, adjust the read packet to write the modified
402 // value back to memory.
403 if (!functional && doWrite) {
404 DPRINTF(PageTableWalker, "Writing level%d PTE to %#x: %#x\n",
405 level, oldRead->getAddr(), pte);
406 write = oldRead;
407 write->setLE<uint64_t>(pte);
408 write->cmd = MemCmd::WriteReq;
409 read = NULL;
410 } else {
411 write = NULL;
412 }
413
414 if (doTLBInsert) {
415 if (!functional)
416 walker->tlb->insert(entry.vaddr, entry);
417 else {
418 DPRINTF(PageTableWalker, "Translated %#x -> %#x\n",
419 entry.vaddr, entry.paddr << PageShift |
420 (entry.vaddr & mask(entry.logBytes)));
421 }
422 }
423 endWalk();
424 }
425 else {
426 //If we didn't return, we're setting up another read.
427 RequestPtr request = std::make_shared<Request>(
428 nextRead, oldRead->getSize(), flags, walker->requestorId);
429
430 delete oldRead;
431 oldRead = nullptr;
432
433 read = new Packet(request, MemCmd::ReadReq);
434 read->allocate();
435
436 DPRINTF(PageTableWalker,
437 "Loading level%d PTE from %#x\n", level, nextRead);
438 }
439
440 return fault;
441}
442
443void
445{
446 nextState = Ready;
447 delete read;
448 read = NULL;
449}
450
451void
453{
454 vaddr = Addr(sext<VADDR_BITS>(vaddr));
455
457 Addr idx = (vaddr >> shift) & LEVEL_MASK;
458 Addr topAddr = (satp.ppn << PageShift) + (idx * sizeof(PTESv39));
459 level = 2;
460
461 DPRINTF(PageTableWalker, "Performing table walk for address %#x\n", vaddr);
462 DPRINTF(PageTableWalker, "Loading level%d PTE from %#x\n", level, topAddr);
463
464 state = Translate;
465 nextState = Ready;
466 entry.vaddr = vaddr;
467 entry.asid = satp.asid;
468
470 RequestPtr request = std::make_shared<Request>(
471 topAddr, sizeof(PTESv39), flags, walker->requestorId);
472
473 read = new Packet(request, MemCmd::ReadReq);
474 read->allocate();
475}
476
477bool
479{
480 assert(pkt->isResponse());
481 assert(inflight);
482 assert(state == Waiting);
483 inflight--;
484 if (squashed) {
485 // if were were squashed, return true once inflight is zero and
486 // this WalkerState will be freed there.
487 return (inflight == 0);
488 }
489 if (pkt->isRead()) {
490 // should not have a pending read it we also had one outstanding
491 assert(!read);
492
493 // @todo someone should pay for this
494 pkt->headerDelay = pkt->payloadDelay = 0;
495
496 state = nextState;
497 nextState = Ready;
498 PacketPtr write = NULL;
499 read = pkt;
500 timingFault = stepWalk(write);
501 state = Waiting;
502 assert(timingFault == NoFault || read == NULL);
503 if (write) {
504 writes.push_back(write);
505 }
506 sendPackets();
507 } else {
508 delete pkt;
509
510 sendPackets();
511 }
512 if (inflight == 0 && read == NULL && writes.size() == 0) {
513 state = Ready;
514 nextState = Waiting;
515 if (timingFault == NoFault) {
516 /*
517 * Finish the translation. Now that we know the right entry is
518 * in the TLB, this should work with no memory accesses.
519 * There could be new faults unrelated to the table walk like
520 * permissions violations, so we'll need the return value as
521 * well.
522 */
523 Addr vaddr = req->getVaddr();
524 vaddr = Addr(sext<VADDR_BITS>(vaddr));
525 Addr paddr = walker->tlb->translateWithTLB(vaddr, satp.asid, mode);
526 req->setPaddr(paddr);
527 walker->pma->check(req);
528
529 // do pmp check if any checking condition is met.
530 // timingFault will be NoFault if pmp checks are
531 // passed, otherwise an address fault will be returned.
532 timingFault = walker->pmp->pmpCheck(req, mode, pmode, tc);
533
534 // Let the CPU continue.
535 translation->finish(timingFault, req, tc, mode);
536 } else {
537 // There was a fault during the walk. Let the CPU know.
538 translation->finish(timingFault, req, tc, mode);
539 }
540 return true;
541 }
542
543 return false;
544}
545
546void
548{
549 //If we're already waiting for the port to become available, just return.
550 if (retrying)
551 return;
552
553 //Reads always have priority
554 if (read) {
555 PacketPtr pkt = read;
556 read = NULL;
557 inflight++;
558 if (!walker->sendTiming(this, pkt)) {
559 retrying = true;
560 read = pkt;
561 inflight--;
562 return;
563 }
564 }
565 //Send off as many of the writes as we can.
566 while (writes.size()) {
567 PacketPtr write = writes.back();
568 writes.pop_back();
569 inflight++;
570 if (!walker->sendTiming(this, write)) {
571 retrying = true;
572 writes.push_back(write);
573 inflight--;
574 return;
575 }
576 }
577}
578
579unsigned
581{
582 return inflight;
583}
584
585bool
587{
588 return retrying;
589}
590
591bool
593{
594 return timing;
595}
596
597bool
599{
600 return started;
601}
602
603void
605{
606 squashed = true;
607}
608
609void
611{
612 retrying = false;
613 sendPackets();
614}
615
616Fault
618{
619 DPRINTF(PageTableWalker, "Raising page fault.\n");
620 return walker->tlb->createPagefault(entry.vaddr, mode);
621}
622
623} // namespace RiscvISA
624} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
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...
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
Addr getAddr() const
Definition packet.hh:807
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
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
Ports are used to interface objects to each other.
Definition port.hh:62
bool sendTimingReq(PacketPtr pkt)
Attempt to send a timing request to the responder port by calling its corresponding receive function.
Definition port.hh:530
@ PHYSICAL
The virtual address is also the physical address.
Definition request.hh:117
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)
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.
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
Fault start(ThreadContext *_tc, BaseMMU::Translation *translation, const RequestPtr &req, BaseMMU::Mode mode)
bool isTimingMode() const
Is the system in timing mode?
Definition system.hh:270
ThreadContext is the external interface to all thread state for anything outside of the CPU.
STL list class.
Definition stl.hh:51
bool scheduled() const
Determine if the current event is scheduled.
Definition eventq.hh:458
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
atomic_var_t state
Definition helpers.cc:188
uint8_t flags
Definition helpers.cc:66
Bitfield< 5, 0 > status
Bitfield< 6, 5 > shift
Definition types.hh:117
const Addr LEVEL_BITS
Definition pagetable.hh:60
const Addr PageShift
Definition page_size.hh:53
const Addr LEVEL_MASK
Definition pagetable.hh:61
@ MISCREG_STATUS
Definition misc.hh:75
Bitfield< 20 > level
Definition intmessage.hh:51
Bitfield< 7 > present
Definition misc.hh:999
Bitfield< 3 > addr
Definition types.hh:84
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
std::shared_ptr< FaultBase > Fault
Definition types.hh:249
std::shared_ptr< Request > RequestPtr
Definition request.hh:94
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
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 Jul 10 2023 15:32:00 for gem5 by doxygen 1.9.7