786cb8193ed623f6591338eb0eefc4b11d2e281f
2 * Copyright (c) 2012 ARM Limited
3 * Copyright (c) 2020 Barkhausen Institut
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.
15 * Copyright (c) 2007 The Hewlett-Packard Development Company
16 * All rights reserved.
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.
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.
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.
51 #include "arch/riscv/pagetable_walker.hh"
55 #include "arch/riscv/faults.hh"
56 #include "arch/riscv/pagetable.hh"
57 #include "arch/riscv/tlb.hh"
58 #include "base/bitfield.hh"
59 #include "base/trie.hh"
60 #include "cpu/base.hh"
61 #include "cpu/thread_context.hh"
62 #include "debug/PageTableWalker.hh"
63 #include "mem/packet_access.hh"
64 #include "mem/request.hh"
69 Walker::start(ThreadContext
* _tc
, BaseTLB::Translation
*_translation
,
70 const RequestPtr
&_req
, BaseTLB::Mode _mode
)
72 // TODO: in timing mode, instead of blocking when there are other
73 // outstanding requests, see if this request can be coalesced with
74 // another one (i.e. either coalesce or start walk)
75 WalkerState
* newState
= new WalkerState(this, _translation
, _req
);
76 newState
->initState(_tc
, _mode
, sys
->isTimingMode());
77 if (currStates
.size()) {
78 assert(newState
->isTiming());
79 DPRINTF(PageTableWalker
, "Walks in progress: %d\n", currStates
.size());
80 currStates
.push_back(newState
);
83 currStates
.push_back(newState
);
84 Fault fault
= newState
->startWalk();
85 if (!newState
->isTiming()) {
86 currStates
.pop_front();
94 Walker::startFunctional(ThreadContext
* _tc
, Addr
&addr
, unsigned &logBytes
,
97 funcState
.initState(_tc
, _mode
);
98 return funcState
.startFunctional(addr
, logBytes
);
102 Walker::WalkerPort::recvTimingResp(PacketPtr pkt
)
104 return walker
->recvTimingResp(pkt
);
108 Walker::recvTimingResp(PacketPtr pkt
)
110 WalkerSenderState
* senderState
=
111 dynamic_cast<WalkerSenderState
*>(pkt
->popSenderState());
112 WalkerState
* senderWalk
= senderState
->senderWalk
;
113 bool walkComplete
= senderWalk
->recvPacket(pkt
);
116 std::list
<WalkerState
*>::iterator iter
;
117 for (iter
= currStates
.begin(); iter
!= currStates
.end(); iter
++) {
118 WalkerState
* walkerState
= *(iter
);
119 if (walkerState
== senderWalk
) {
120 iter
= currStates
.erase(iter
);
125 // Since we block requests when another is outstanding, we
126 // need to check if there is a waiting request to be serviced
127 if (currStates
.size() && !startWalkWrapperEvent
.scheduled())
128 // delay sending any new requests until we are finished
129 // with the responses
130 schedule(startWalkWrapperEvent
, clockEdge());
136 Walker::WalkerPort::recvReqRetry()
138 walker
->recvReqRetry();
142 Walker::recvReqRetry()
144 std::list
<WalkerState
*>::iterator iter
;
145 for (iter
= currStates
.begin(); iter
!= currStates
.end(); iter
++) {
146 WalkerState
* walkerState
= *(iter
);
147 if (walkerState
->isRetrying()) {
148 walkerState
->retry();
153 bool Walker::sendTiming(WalkerState
* sendingState
, PacketPtr pkt
)
155 WalkerSenderState
* walker_state
= new WalkerSenderState(sendingState
);
156 pkt
->pushSenderState(walker_state
);
157 if (port
.sendTimingReq(pkt
)) {
160 // undo the adding of the sender state and delete it, as we
161 // will do it again the next time we attempt to send it
162 pkt
->popSenderState();
170 Walker::getPort(const std::string
&if_name
, PortID idx
)
172 if (if_name
== "port")
175 return ClockedObject::getPort(if_name
, idx
);
179 Walker::WalkerState::initState(ThreadContext
* _tc
,
180 BaseTLB::Mode _mode
, bool _isTiming
)
182 assert(state
== Ready
);
187 // fetch these now in case they change during the walk
188 status
= tc
->readMiscReg(MISCREG_STATUS
);
189 pmode
= walker
->tlb
->getMemPriv(tc
, mode
);
190 satp
= tc
->readMiscReg(MISCREG_SATP
);
191 assert(satp
.mode
== AddrXlateMode::SV39
);
195 Walker::startWalkWrapper()
197 unsigned num_squashed
= 0;
198 WalkerState
*currState
= currStates
.front();
199 while ((num_squashed
< numSquashable
) && currState
&&
200 currState
->translation
->squashed()) {
201 currStates
.pop_front();
204 DPRINTF(PageTableWalker
, "Squashing table walk for address %#x\n",
205 currState
->req
->getVaddr());
207 // finish the translation which will delete the translation object
208 currState
->translation
->finish(
209 std::make_shared
<UnimpFault
>("Squashed Inst"),
210 currState
->req
, currState
->tc
, currState
->mode
);
212 // delete the current request if there are no inflight packets.
213 // if there is something in flight, delete when the packets are
214 // received and inflight is zero.
215 if (currState
->numInflight() == 0) {
221 // check the next translation request, if it exists
222 if (currStates
.size())
223 currState
= currStates
.front();
227 if (currState
&& !currState
->wasStarted())
228 currState
->startWalk();
232 Walker::WalkerState::startWalk()
234 Fault fault
= NoFault
;
237 setupWalk(req
->getVaddr());
241 timingFault
= NoFault
;
245 walker
->port
.sendAtomic(read
);
246 PacketPtr write
= NULL
;
247 fault
= stepWalk(write
);
248 assert(fault
== NoFault
|| read
== NULL
);
252 walker
->port
.sendAtomic(write
);
261 Walker::WalkerState::startFunctional(Addr
&addr
, unsigned &logBytes
)
263 Fault fault
= NoFault
;
269 walker
->port
.sendFunctional(read
);
270 // On a functional access (page table lookup), writes should
271 // not happen so this pointer is ignored after stepWalk
272 PacketPtr write
= NULL
;
273 fault
= stepWalk(write
);
274 assert(fault
== NoFault
|| read
== NULL
);
278 logBytes
= entry
.logBytes
;
279 addr
= entry
.paddr
<< PageShift
;
285 Walker::WalkerState::stepWalk(PacketPtr
&write
)
287 assert(state
!= Ready
&& state
!= Waiting
);
288 Fault fault
= NoFault
;
290 PTESv39 pte
= read
->getLE
<uint64_t>();
292 bool doWrite
= false;
293 bool doTLBInsert
= false;
294 bool doEndWalk
= false;
296 DPRINTF(PageTableWalker
, "Got level%d PTE: %#x\n", level
, pte
);
298 // step 2: TODO check PMA and PMP
301 if (!pte
.v
|| (!pte
.r
&& pte
.w
)) {
303 DPRINTF(PageTableWalker
, "PTE invalid, raising PF\n");
304 fault
= pageFault(pte
.v
);
308 if (pte
.r
|| pte
.x
) {
311 fault
= walker
->tlb
->checkPermissions(status
, pmode
,
312 entry
.vaddr
, mode
, pte
);
315 if (fault
== NoFault
) {
316 if (level
>= 1 && pte
.ppn0
!= 0) {
317 DPRINTF(PageTableWalker
,
318 "PTE has misaligned PPN, raising PF\n");
319 fault
= pageFault(true);
321 else if (level
== 2 && pte
.ppn1
!= 0) {
322 DPRINTF(PageTableWalker
,
323 "PTE has misaligned PPN, raising PF\n");
324 fault
= pageFault(true);
328 if (fault
== NoFault
) {
334 if (!pte
.d
&& mode
== TLB::Write
) {
338 // TODO check if this violates a PMA or PMP
341 entry
.logBytes
= PageShift
+ (level
* LEVEL_BITS
);
342 entry
.paddr
= pte
.ppn
;
343 entry
.vaddr
&= ~((1 << entry
.logBytes
) - 1);
345 // put it non-writable into the TLB to detect writes and redo
346 // the page table walk in order to update the dirty flag.
347 if (!pte
.d
&& mode
!= TLB::Write
)
355 DPRINTF(PageTableWalker
, "No leaf PTE found, raising PF\n");
357 fault
= pageFault(true);
360 Addr shift
= (PageShift
+ LEVEL_BITS
* level
);
361 Addr idx
= (entry
.vaddr
>> shift
) & LEVEL_MASK
;
362 nextRead
= (pte
.ppn
<< PageShift
) + (idx
* sizeof(pte
));
363 nextState
= Translate
;
368 PacketPtr oldRead
= read
;
369 Request::Flags flags
= oldRead
->req
->getFlags();
372 // If we need to write, adjust the read packet to write the modified
373 // value back to memory.
374 if (!functional
&& doWrite
) {
375 DPRINTF(PageTableWalker
, "Writing level%d PTE to %#x: %#x\n",
376 level
, oldRead
->getAddr(), pte
);
378 write
->setLE
<uint64_t>(pte
);
379 write
->cmd
= MemCmd::WriteReq
;
387 walker
->tlb
->insert(entry
.vaddr
, entry
);
389 DPRINTF(PageTableWalker
, "Translated %#x -> %#x\n",
390 entry
.vaddr
, entry
.paddr
<< PageShift
|
391 (entry
.vaddr
& mask(entry
.logBytes
)));
397 //If we didn't return, we're setting up another read.
398 RequestPtr request
= std::make_shared
<Request
>(
399 nextRead
, oldRead
->getSize(), flags
, walker
->masterId
);
400 read
= new Packet(request
, MemCmd::ReadReq
);
403 DPRINTF(PageTableWalker
,
404 "Loading level%d PTE from %#x\n", level
, nextRead
);
411 Walker::WalkerState::endWalk()
419 Walker::WalkerState::setupWalk(Addr vaddr
)
421 vaddr
&= (static_cast<Addr
>(1) << VADDR_BITS
) - 1;
423 Addr shift
= PageShift
+ LEVEL_BITS
* 2;
424 Addr idx
= (vaddr
>> shift
) & LEVEL_MASK
;
425 Addr topAddr
= (satp
.ppn
<< PageShift
) + (idx
* sizeof(PTESv39
));
428 DPRINTF(PageTableWalker
, "Performing table walk for address %#x\n", vaddr
);
429 DPRINTF(PageTableWalker
, "Loading level%d PTE from %#x\n", level
, topAddr
);
434 entry
.asid
= satp
.asid
;
436 Request::Flags flags
= Request::PHYSICAL
;
437 RequestPtr request
= std::make_shared
<Request
>(
438 topAddr
, sizeof(PTESv39
), flags
, walker
->masterId
);
440 read
= new Packet(request
, MemCmd::ReadReq
);
445 Walker::WalkerState::recvPacket(PacketPtr pkt
)
447 assert(pkt
->isResponse());
449 assert(state
== Waiting
);
452 // if were were squashed, return true once inflight is zero and
453 // this WalkerState will be freed there.
454 return (inflight
== 0);
457 // should not have a pending read it we also had one outstanding
460 // @todo someone should pay for this
461 pkt
->headerDelay
= pkt
->payloadDelay
= 0;
465 PacketPtr write
= NULL
;
467 timingFault
= stepWalk(write
);
469 assert(timingFault
== NoFault
|| read
== NULL
);
471 writes
.push_back(write
);
477 if (inflight
== 0 && read
== NULL
&& writes
.size() == 0) {
480 if (timingFault
== NoFault
) {
482 * Finish the translation. Now that we know the right entry is
483 * in the TLB, this should work with no memory accesses.
484 * There could be new faults unrelated to the table walk like
485 * permissions violations, so we'll need the return value as
488 Addr vaddr
= req
->getVaddr();
489 vaddr
&= (static_cast<Addr
>(1) << VADDR_BITS
) - 1;
490 Addr paddr
= walker
->tlb
->translateWithTLB(vaddr
, satp
.asid
, mode
);
491 req
->setPaddr(paddr
);
492 // Let the CPU continue.
493 translation
->finish(NoFault
, req
, tc
, mode
);
495 // There was a fault during the walk. Let the CPU know.
496 translation
->finish(timingFault
, req
, tc
, mode
);
505 Walker::WalkerState::sendPackets()
507 //If we're already waiting for the port to become available, just return.
511 //Reads always have priority
513 PacketPtr pkt
= read
;
516 if (!walker
->sendTiming(this, pkt
)) {
523 //Send off as many of the writes as we can.
524 while (writes
.size()) {
525 PacketPtr write
= writes
.back();
528 if (!walker
->sendTiming(this, write
)) {
530 writes
.push_back(write
);
538 Walker::WalkerState::numInflight() const
544 Walker::WalkerState::isRetrying()
550 Walker::WalkerState::isTiming()
556 Walker::WalkerState::wasStarted()
562 Walker::WalkerState::squash()
568 Walker::WalkerState::retry()
575 Walker::WalkerState::pageFault(bool present
)
577 DPRINTF(PageTableWalker
, "Raising page fault.\n");
578 return walker
->tlb
->createPagefault(entry
.vaddr
, mode
);
581 } /* end namespace RiscvISA */
584 RiscvPagetableWalkerParams::create()
586 return new RiscvISA::Walker(this);