gem5 v23.0.0.1
Loading...
Searching...
No Matches
pagetable_walker.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
33
34#include <memory>
35
37#include "mem/abstract_mem.hh"
38#include "mem/packet_access.hh"
39
40namespace gem5
41{
42namespace VegaISA
43{
44
45/*
46 * Functional/atomic mode methods
47 */
50 BaseMMU::Mode mode, bool &isSystem)
51{
53 Addr vaddr = addr;
54 Fault fault = startFunctional(base, vaddr, pte, logBytes, mode);
55 isSystem = pte.s;
56 addr = ((pte.ppn << PageShift) + (vaddr & mask(logBytes)));
57
58 return fault;
59}
60
63 unsigned &logBytes, BaseMMU::Mode mode)
64{
65 DPRINTF(GPUPTWalker, "Vega walker walker: %p funcState: %p "
66 "funcState->walker %p\n",
67 this, &funcState, funcState.getWalker());
69 return funcState.startFunctional(base, vaddr, pte, logBytes);
70}
71
74 PageTableEntry &pte, unsigned &logBytes)
75{
76 Fault fault = NoFault;
77 DPRINTF(GPUPTWalker, "Vega walker starting with addr: %#lx "
78 "logical: %#lx\n", vaddr, vaddr >> PageShift);
79
80 assert(!started);
81 started = true;
82
83 do {
84 DPRINTF(GPUPTWalker, "Sending functional read to %#lx\n",
85 read->getAddr());
86
87 auto devmem = walker->system->getDeviceMemory(read);
88 assert(devmem);
89 devmem->access(read);
90
91 fault = stepWalk();
92 assert(fault == NoFault || read == NULL);
93
95 } while (read);
96
97 logBytes = entry.logBytes;
98 pte = entry.pte;
99
100 return fault;
101}
102
103
104/*
105 * Timing mode methods
106 */
107void
109{
110 DPRINTF(GPUPTWalker, "Vega walker starting with addr: %#lx "
111 "logical: %#lx\n", vaddr, vaddr >> PageShift);
112
113 WalkerState *newState = new WalkerState(this, pkt);
114
115 newState->initState(mode, base, vaddr);
116 currStates.push_back(newState);
117 DPRINTF(GPUPTWalker, "There are %ld walker states\n", currStates.size());
118
119 newState->startWalk();
120}
121
122void
124 bool is_functional)
125{
126 DPRINTF(GPUPTWalker, "Walker::WalkerState::initState\n");
127 DPRINTF(GPUPTWalker, "Walker::WalkerState::initState %p\n", this);
128 DPRINTF(GPUPTWalker, "Walker::WalkerState::initState %d\n", state);
129 assert(state == Ready);
130
131 started = false;
132 mode = _mode;
133 timing = !is_functional;
134 enableNX = true;
135 dataSize = 8; // 64-bit PDEs / PTEs
136 nextState = PDE2;
137
138 DPRINTF(GPUPTWalker, "Setup walk with base %#lx\n", baseAddr);
139
140 // First level in Vega is PDE2. Calculate the address for that PDE using
141 // baseAddr and vaddr.
142 state = PDE2;
143 Addr logical_addr = vaddr >> PageShift;
144 Addr pde2Addr = (((baseAddr >> 6) << 3) + (logical_addr >> 3*9)) << 3;
145 DPRINTF(GPUPTWalker, "Walk PDE2 address is %#lx\n", pde2Addr);
146
147 // Start populating the VegaTlbEntry response
148 entry.vaddr = logical_addr;
149
150 // Prepare the read packet that will be used at each level
152
153 RequestPtr request = std::make_shared<Request>(
154 pde2Addr, dataSize, flags, walker->deviceRequestorId);
155
156 read = new Packet(request, MemCmd::ReadReq);
157 read->allocate();
158}
159
160void
162{
163 if (!started) {
164 // Read the first PDE to begin
165 DPRINTF(GPUPTWalker, "Sending timing read to %#lx\n",
166 read->getAddr());
167
168 sendPackets();
169 started = true;
170 } else {
171 // This is mostly the same as stepWalk except we update the state and
172 // send the new timing read request.
173 timingFault = stepWalk();
174 assert(timingFault == NoFault || read == NULL);
175
176 state = nextState;
177
178 if (read) {
179 DPRINTF(GPUPTWalker, "Sending timing read to %#lx\n",
180 read->getAddr());
181 sendPackets();
182 } else {
183 // Set physical page address in entry
184 entry.paddr = entry.pte.ppn << PageShift;
185 entry.paddr += entry.vaddr & mask(entry.logBytes);
186
187 // Insert to TLB
188 assert(walker);
189 assert(walker->tlb);
190 walker->tlb->insert(entry.vaddr, entry);
191
192 // Send translation return event
193 walker->walkerResponse(this, entry, tlbPkt);
194 }
195 }
196}
197
198Fault
200{
201 assert(state != Ready && state != Waiting && read);
202 Fault fault = NoFault;
203 PageTableEntry pte = read->getLE<uint64_t>();
204
205 bool uncacheable = !pte.c;
206 Addr nextRead = 0;
207 bool doEndWalk = false;
208
209 walkStateMachine(pte, nextRead, doEndWalk, fault);
210
211 if (doEndWalk) {
212 DPRINTF(GPUPTWalker, "ending walk\n");
213 endWalk();
214 } else {
215 PacketPtr oldRead = read;
216
217 //If we didn't return, we're setting up another read.
218 Request::Flags flags = oldRead->req->getFlags();
219 flags.set(Request::UNCACHEABLE, uncacheable);
220 RequestPtr request = std::make_shared<Request>(
221 nextRead, oldRead->getSize(), flags, walker->deviceRequestorId);
222
223 read = new Packet(request, MemCmd::ReadReq);
224 read->allocate();
225
226 delete oldRead;
227 }
228
229 return fault;
230}
231
232void
234 bool &doEndWalk, Fault &fault)
235{
236 Addr vaddr = entry.vaddr;
237 bool badNX = pte.x && mode == BaseMMU::Execute && enableNX;
238 Addr part1 = 0;
239 Addr part2 = 0;
240 PageDirectoryEntry pde = static_cast<PageDirectoryEntry>(pte);
241
242 // For a four level page table block fragment size should not be needed.
243 // For now issue a panic to prevent strange behavior if it is non-zero.
244 panic_if(pde.blockFragmentSize, "PDE blockFragmentSize must be 0");
245
246 switch(state) {
247 case PDE2:
248 if (pde.p) {
249 DPRINTF(GPUPTWalker, "Treating PDE2 as PTE: %#016x frag: %d\n",
250 (uint64_t)pte, pte.fragment);
251 entry.pte = pte;
252 int fragment = pte.fragment;
253 entry.logBytes = PageShift + std::min(3*9, fragment);
254 entry.vaddr <<= PageShift;
255 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
256 doEndWalk = true;
257 }
258
259 // Read the pde1Addr
260 part1 = ((((uint64_t)pte) >> 6) << 3);
261 part2 = offsetFunc(vaddr, 3*9, 2*9);
262 nextRead = ((part1 + part2) << 3) & mask(48);
263 DPRINTF(GPUPTWalker,
264 "Got PDE2 entry %#016x. write:%s->%#016x va:%#016x\n",
265 (uint64_t)pte, pte.w == 0 ? "yes" : "no", nextRead, vaddr);
266 nextState = PDE1;
267 break;
268 case PDE1:
269 if (pde.p) {
270 DPRINTF(GPUPTWalker, "Treating PDE1 as PTE: %#016x frag: %d\n",
271 (uint64_t)pte, pte.fragment);
272 entry.pte = pte;
273 int fragment = pte.fragment;
274 entry.logBytes = PageShift + std::min(2*9, fragment);
275 entry.vaddr <<= PageShift;
276 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
277 doEndWalk = true;
278 }
279
280 // Read the pde0Addr
281 part1 = ((((uint64_t)pte) >> 6) << 3);
282 part2 = offsetFunc(vaddr, 2*9, 9);
283 nextRead = ((part1 + part2) << 3) & mask(48);
284 DPRINTF(GPUPTWalker,
285 "Got PDE1 entry %#016x. write:%s->%#016x va: %#016x\n",
286 (uint64_t)pte, pte.w == 0 ? "yes" : "no", nextRead, vaddr);
287 nextState = PDE0;
288 break;
289 case PDE0:
290 if (pde.p) {
291 DPRINTF(GPUPTWalker, "Treating PDE0 as PTE: %#016x frag: %d\n",
292 (uint64_t)pte, pte.fragment);
293 entry.pte = pte;
294 int fragment = pte.fragment;
295 entry.logBytes = PageShift + std::min(9, fragment);
296 entry.vaddr <<= PageShift;
297 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
298 doEndWalk = true;
299 }
300 // Read the PteAddr
301 part1 = ((((uint64_t)pte) >> 6) << 3);
302 part2 = offsetFunc(vaddr, 9, 0);
303 nextRead = ((part1 + part2) << 3) & mask(48);
304 DPRINTF(GPUPTWalker,
305 "Got PDE0 entry %#016x. write:%s->%#016x va:%#016x\n",
306 (uint64_t)pte, pte.w == 0 ? "yes" : "no", nextRead, vaddr);
307 nextState = PTE;
308 break;
309 case PTE:
310 DPRINTF(GPUPTWalker,
311 " PTE entry %#016x. write: %s va: %#016x\n",
312 (uint64_t)pte, pte.w == 0 ? "yes" : "no", vaddr);
313 entry.pte = pte;
314 entry.logBytes = PageShift;
315 entry.vaddr <<= PageShift;
316 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
317 doEndWalk = true;
318 break;
319 default:
320 panic("Unknown page table walker state %d!\n");
321 }
322
323 if (badNX || !pte.v) {
324 doEndWalk = true;
325 fault = pageFault(pte.v);
326 nextState = state;
327 }
328}
329
330void
332{
333 nextState = Ready;
334 delete read;
335 read = NULL;
336 walker->currStates.remove(this);
337}
338
342void
344{
345 // If we're already waiting for the port to become available, just return.
346 if (retrying)
347 return;
348
349 if (!walker->sendTiming(this, read)) {
350 DPRINTF(GPUPTWalker, "Timing request for %#lx failed\n",
351 read->getAddr());
352
353 retrying = true;
354 } else {
355 DPRINTF(GPUPTWalker, "Timing request for %#lx successful\n",
356 read->getAddr());
357 }
358}
359
360bool Walker::sendTiming(WalkerState* sending_walker, PacketPtr pkt)
361{
362 auto walker_state = new WalkerSenderState(sending_walker);
363 pkt->pushSenderState(walker_state);
364
365 if (port.sendTimingReq(pkt)) {
366 DPRINTF(GPUPTWalker, "Sending timing read to %#lx from walker %p\n",
367 pkt->getAddr(), sending_walker);
368
369 return true;
370 } else {
371 (void)pkt->popSenderState();
372 }
373
374 return false;
375}
376
377bool
379{
380 walker->recvTimingResp(pkt);
381
382 return true;
383}
384
385void
387{
388 WalkerSenderState * senderState =
389 safe_cast<WalkerSenderState *>(pkt->popSenderState());
390
391 DPRINTF(GPUPTWalker, "Got response for %#lx from walker %p -- %#lx\n",
392 pkt->getAddr(), senderState->senderWalk, pkt->getLE<uint64_t>());
393 senderState->senderWalk->startWalk();
394
395 delete senderState;
396}
397
398void
400{
401 walker->recvReqRetry();
402}
403
404void
406{
408 for (iter = currStates.begin(); iter != currStates.end(); iter++) {
409 WalkerState * walkerState = *(iter);
410 if (walkerState->isRetrying()) {
411 walkerState->retry();
412 }
413 }
414}
415
416void
418{
419 tlb->walkerResponse(entry, pkt);
420
421 delete state;
422}
423
424
425/*
426 * Helper methods
427 */
428bool
430{
431 return retrying;
432}
433
434void
436{
437 retrying = false;
438 sendPackets();
439}
440
441Fault
443{
444 DPRINTF(GPUPTWalker, "Raising page fault.\n");
445 ExceptionCode code;
446 if (mode == BaseMMU::Read)
448 else if (mode == BaseMMU::Write)
450 else
452 if (mode == BaseMMU::Execute && !enableNX)
454 return std::make_shared<PageFault>(entry.vaddr, code, present, mode, true);
455}
456
457uint64_t
458Walker::WalkerState::offsetFunc(Addr logicalAddr, int top, int lsb)
459{
460 assert(top < 32);
461 assert(lsb < 32);
462 return ((logicalAddr & ((1 << top) - 1)) >> lsb);
463}
464
465
469Port &
470Walker::getPort(const std::string &if_name, PortID idx)
471{
472 if (if_name == "port")
473 return port;
474 else
475 return ClockedObject::getPort(if_name, idx);
476}
477
478} // namespace VegaISA
479} // namespace gem5
AbstractMemory declaration.
#define DPRINTF(x,...)
Definition trace.hh:210
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
Addr getAddr() const
Definition packet.hh:807
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
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
@ UNCACHEABLE
The request is to an uncacheable address.
Definition request.hh:125
memory::AbstractMemory * getDeviceMemory(const PacketPtr &pkt) const
Return a pointer to the device memory.
Definition system.cc:311
void walkerResponse(VegaTlbEntry &entry, PacketPtr pkt)
Definition tlb.cc:425
bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
void recvReqRetry()
Called by the peer if sendTimingReq was called on this peer (causing recvTimingReq to be called on th...
Fault startFunctional(Addr base, Addr vaddr, PageTableEntry &pte, unsigned &logBytes)
void initState(BaseMMU::Mode _mode, Addr baseAddr, Addr vaddr, bool is_functional=false)
uint64_t offsetFunc(Addr logicalAddr, int top, int lsb)
void walkStateMachine(PageTableEntry &pte, Addr &nextRead, bool &doEndWalk, Fault &fault)
void sendPackets()
Port related methods.
void recvTimingResp(PacketPtr pkt)
void walkerResponse(WalkerState *state, VegaTlbEntry &entry, PacketPtr pkt)
bool sendTiming(WalkerState *sendingState, PacketPtr pkt)
Fault startFunctional(Addr base, Addr vaddr, PageTableEntry &pte, unsigned &logBytes, BaseMMU::Mode mode)
std::list< WalkerState * > currStates
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
gem5 methods
void startTiming(PacketPtr pkt, Addr base, Addr vaddr, BaseMMU::Mode mode)
STL list class.
Definition stl.hh:51
Definition test.h:63
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
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< 3, 0 > mask
Definition pcstate.hh:63
Bitfield< 4, 0 > mode
Definition misc_types.hh:74
Bitfield< 11, 7 > fragment
Definition pagetable.hh:58
const Addr PageShift
Definition page_size.hh:41
Bitfield< 51, 12 > base
Definition pagetable.hh:141
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

Generated on Mon Jul 10 2023 15:32:00 for gem5 by doxygen 1.9.7