gem5 [DEVELOP-FOR-25.0]
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());
68 funcState.initState(mode, base, vaddr, true);
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 * Timing mode methods
105 */
106void
108{
109 DPRINTF(GPUPTWalker, "Vega walker starting with addr: %#lx "
110 "logical: %#lx\n", vaddr, vaddr >> PageShift);
111
112 WalkerState *newState = new WalkerState(this, pkt);
113
114 newState->initState(mode, base, vaddr);
115 currStates.push_back(newState);
116 DPRINTF(GPUPTWalker, "There are %ld walker states\n", currStates.size());
117
118 newState->startWalk();
119}
120
121void
123 bool is_functional)
124{
125 DPRINTF(GPUPTWalker, "Walker::WalkerState::initState\n");
126 DPRINTF(GPUPTWalker, "Walker::WalkerState::initState %p\n", this);
127 DPRINTF(GPUPTWalker, "Walker::WalkerState::initState %d\n", state);
128 assert(state == Ready);
129
130 started = false;
131 mode = _mode;
132 timing = !is_functional;
133 enableNX = true;
134 dataSize = 8; // 64-bit PDEs / PTEs
135 nextState = PDE2;
136
137 DPRINTF(GPUPTWalker, "Setup walk with base %#lx\n", baseAddr);
138
139 // First level in Vega is PDE2. Calculate the address for that PDE using
140 // baseAddr and vaddr.
141 state = PDE2;
142 Addr logical_addr = vaddr >> PageShift;
143 Addr pde2Addr = (((baseAddr >> 6) << 3) + (logical_addr >> 3*9)) << 3;
144 DPRINTF(GPUPTWalker, "Walk PDE2 address is %#lx\n", pde2Addr);
145
146 // Start populating the VegaTlbEntry response
147 entry.vaddr = logical_addr;
148
149 // Prepare the read packet that will be used at each level
151
152 RequestPtr request = std::make_shared<Request>(
153 pde2Addr, dataSize, flags, walker->deviceRequestorId);
154
155 read = new Packet(request, MemCmd::ReadReq);
156 read->allocate();
157}
158
159void
161{
162 if (!started) {
163 // Read the first PDE to begin
164 DPRINTF(GPUPTWalker, "Sending timing read to %#lx\n",
165 read->getAddr());
166
167 started = true;
168 sendPackets();
169 } else {
170 // This is mostly the same as stepWalk except we update the state and
171 // send the new timing read request.
173 assert(timingFault == NoFault || read == NULL);
174
176
177 if (read) {
178 DPRINTF(GPUPTWalker, "Sending timing read to %#lx\n",
179 read->getAddr());
180 sendPackets();
181 } else {
182 // Set physical page address in entry
183 entry.paddr = entry.pte.ppn << PageShift;
184 entry.paddr += entry.vaddr & mask(entry.logBytes);
185
186 // Insert to TLB
187 assert(walker);
188 assert(walker->tlb);
189 walker->tlb->insert(entry.vaddr, entry);
190
191 // Send translation return event
192 walker->walkerResponse(this, entry, tlbPkt);
193 }
194 }
195}
196
197Fault
199{
200 assert(state != Ready && state != Waiting && read);
201 Fault fault = NoFault;
202 PageTableEntry pte = read->getLE<uint64_t>();
203
204 bool uncacheable = !pte.c;
205 Addr nextRead = 0;
206 bool doEndWalk = false;
207
208 walkStateMachine(pte, nextRead, doEndWalk, fault);
209
210 if (doEndWalk) {
211 DPRINTF(GPUPTWalker, "ending walk\n");
212 endWalk();
213 } else {
214 PacketPtr oldRead = read;
215
216 //If we didn't return, we're setting up another read.
217 Request::Flags flags = oldRead->req->getFlags();
218 flags.set(Request::UNCACHEABLE, uncacheable);
219 RequestPtr request = std::make_shared<Request>(
220 nextRead, oldRead->getSize(), flags, walker->deviceRequestorId);
221
222 read = new Packet(request, MemCmd::ReadReq);
223 read->allocate();
224
225 delete oldRead;
226 }
227
228 return fault;
229}
230
231void
233 bool &doEndWalk, Fault &fault)
234{
235 Addr vaddr = entry.vaddr;
236 bool badNX = pte.x && mode == BaseMMU::Execute && enableNX;
237 Addr part1 = 0;
238 Addr part2 = 0;
239 PageDirectoryEntry pde = static_cast<PageDirectoryEntry>(pte);
240
241 // Block fragment size can change the size of the pages pointed to while
242 // moving to the next PDE. A value of 0 implies native page size. A
243 // non-zero value implies the next leaf in the page table is a PTE unless
244 // the F bit is set. If we see a non-zero value, set it here and print
245 // for debugging.
246 if (pde.blockFragmentSize) {
247 DPRINTF(GPUPTWalker,
248 "blockFragmentSize: %d, pde: %#016lx, state: %d\n",
249 pde.blockFragmentSize, pde, state);
250 blockFragmentSize = pde.blockFragmentSize;
251
252 // At this time, only a value of 9 is used in the driver:
253 // https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/
254 // amd/amdgpu/gmc_v9_0.c#L1165
255 assert(pde.blockFragmentSize == 9);
256 }
257
258 switch(state) {
259 case PDE2:
260 if (pde.p) {
261 DPRINTF(GPUPTWalker, "Treating PDE2 as PTE: %#016x frag: %d\n",
262 (uint64_t)pte, pte.fragment);
263 entry.pte = pte;
264 int fragment = pte.fragment;
265 entry.logBytes = PageShift + std::min(3*9, fragment);
266 entry.vaddr <<= PageShift;
267 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
268 doEndWalk = true;
269 }
270
271 // Read the pde1Addr
272 part1 = ((((uint64_t)pte) >> 6) << 3);
273 part2 = offsetFunc(vaddr, 3*9, 2*9);
274 nextRead = ((part1 + part2) << 3) & mask(48);
275 DPRINTF(GPUPTWalker,
276 "Got PDE2 entry %#016x. write:%s->%#016x va:%#016x\n",
277 (uint64_t)pte, pte.w == 0 ? "yes" : "no", nextRead, vaddr);
278 nextState = PDE1;
279 break;
280 case PDE1:
281 if (pde.p) {
282 DPRINTF(GPUPTWalker, "Treating PDE1 as PTE: %#016x frag: %d\n",
283 (uint64_t)pte, pte.fragment);
284 entry.pte = pte;
285 int fragment = pte.fragment;
286 entry.logBytes = PageShift + std::min(2*9, fragment);
287 entry.vaddr <<= PageShift;
288 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
289 doEndWalk = true;
290 }
291
292 // Read the pde0Addr
293 part1 = ((((uint64_t)pte) >> 6) << 3);
294 part2 = offsetFunc(vaddr, 2*9, 9);
295 nextRead = ((part1 + part2) << 3) & mask(48);
296 DPRINTF(GPUPTWalker,
297 "Got PDE1 entry %#016x. write:%s->%#016x va: %#016x\n",
298 (uint64_t)pte, pte.w == 0 ? "yes" : "no", nextRead, vaddr);
299 nextState = PDE0;
300 break;
301 case PDE0:
302 if (pde.p || (blockFragmentSize && !pte.f)) {
303 DPRINTF(GPUPTWalker, "Treating PDE0 as PTE: %#016x frag: %d\n",
304 (uint64_t)pte, pte.fragment);
305 entry.pte = pte;
306 int fragment = pte.fragment;
307 entry.logBytes = PageShift + std::min(9, fragment);
308 entry.vaddr <<= PageShift;
309 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
310 doEndWalk = true;
311 }
312 // Read the PteAddr
313 part1 = ((((uint64_t)pte) >> 6) << 3);
314 if (pte.f) {
315 // For F bit we want to use the blockFragmentSize in the previous
316 // PDE and the blockFragmentSize in this PTE for offset function.
317 part2 = offsetFunc(vaddr,
319 pde.blockFragmentSize);
320 } else {
321 part2 = offsetFunc(vaddr, 9, 0);
322 }
323 nextRead = ((part1 + part2) << 3) & mask(48);
324 DPRINTF(GPUPTWalker,
325 "Got PDE0 entry %#016x. write:%s->%#016x va:%#016x\n",
326 (uint64_t)pte, pte.w == 0 ? "yes" : "no", nextRead, vaddr);
327 nextState = PTE;
328 break;
329 case PTE:
330 DPRINTF(GPUPTWalker,
331 " PTE entry %#016x. write: %s va: %#016x\n",
332 (uint64_t)pte, pte.w == 0 ? "yes" : "no", vaddr);
333 entry.pte = pte;
334 entry.logBytes = PageShift;
335 entry.vaddr <<= PageShift;
336 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
337 doEndWalk = true;
338 break;
339 default:
340 panic("Unknown page table walker state %d!\n");
341 }
342
343 if (badNX || !pte.v) {
344 doEndWalk = true;
345 fault = pageFault(pte.v);
347 }
348}
349
350void
352{
354 delete read;
355 read = NULL;
356 walker->currStates.remove(this);
357}
358
362void
364{
365 // If we're already waiting for the port to become available, just return.
366 if (retrying)
367 return;
368 [[maybe_unused]] auto addr = read->getAddr();
369 if (!walker->sendTiming(this, read)) {
370 DPRINTF(GPUPTWalker, "Timing request for %#lx failed\n",
371 addr);
372
373 retrying = true;
374 }
375 // No lines after sendTiming because the state might be freed
376 // else {
377 // DPRINTF(GPUPTWalker, "Timing request for %#lx successful\n",
378 // addr);
379 // }
380}
381
382bool Walker::sendTiming(WalkerState* sending_walker, PacketPtr pkt)
383{
384 auto walker_state = new WalkerSenderState(sending_walker);
385 pkt->pushSenderState(walker_state);
386
387 // If hit, send the response pkt immediately.
388 PWCEntry *entry = pwc.findEntry(pkt->getAddr());
389 if (entry != nullptr) {
390 DPRINTF(GPUPTWalker, "PTE found in buffer, skipping timing request.");
391 pkt->setLE<uint64_t>(entry->pteEntry);
392
393 recvTimingResp(pkt);
394
395 return true;
396 }
397
398 if (port.sendTimingReq(pkt)) {
399 DPRINTF(GPUPTWalker, "Sending timing read to %#lx from walker %p\n",
400 pkt->getAddr(), sending_walker);
401
402 return true;
403 } else {
404 (void)pkt->popSenderState();
405 delete walker_state;
406 }
407
408 return false;
409}
410
411bool
413{
414 walker->recvTimingResp(pkt);
415
416 return true;
417}
418
419void
421{
422 WalkerSenderState * senderState =
424
425 DPRINTF(GPUPTWalker, "Got response for %#lx from walker %p -- %#lx\n",
426 pkt->getAddr(), senderState->senderWalk, pkt->getLE<uint64_t>());
427 // on PWC miss, add the entry to PWC
428 if (enable_pwc && pwc.findEntry(pkt->getAddr()) == nullptr) {
429 pwc.insert(pkt->getAddr(), pkt->getLE<uint64_t>());
430 }
431
432 senderState->senderWalk->startWalk();
433
434 delete senderState;
435}
436
437void
439{
440 for (auto &i : pwc) {
441 if (i.valid) {
442 pwc.invalidate(&i);
443 }
444 }
445}
446
447void
449{
450 walker->recvReqRetry();
451}
452
453void
455{
457 for (iter = currStates.begin(); iter != currStates.end(); ) {
458 WalkerState * walkerState = *(iter);
459 // retry() might finish the walk, thus the current iterator
460 // might be invalid after retry(). Need to update iter now
461 iter++;
462 if (walkerState->isRetrying()) {
463 walkerState->retry();
464 }
465 }
466}
467
468void
469Walker::walkerResponse(WalkerState *state, VegaTlbEntry& entry, PacketPtr pkt)
470{
471 tlb->walkerResponse(entry, pkt);
472
473 delete state;
474}
475
476
477/*
478 * Helper methods
479 */
480bool
485
486void
488{
489 retrying = false;
490 sendPackets();
491}
492
493Fault
495{
496 DPRINTF(GPUPTWalker, "Raising page fault.\n");
497 ExceptionCode code;
498 if (mode == BaseMMU::Read)
500 else if (mode == BaseMMU::Write)
502 else
504 if (mode == BaseMMU::Execute && !enableNX)
506 return std::make_shared<PageFault>(entry.vaddr, code, present, mode, true);
507}
508
509uint64_t
510Walker::WalkerState::offsetFunc(Addr logicalAddr, int top, int lsb)
511{
512 assert(top < 32);
513 assert(lsb < 32);
514 return ((logicalAddr & ((1 << top) - 1)) >> lsb);
515}
516
517
521Port &
522Walker::getPort(const std::string &if_name, PortID idx)
523{
524 if (if_name == "port")
525 return port;
526 else
527 return ClockedObject::getPort(if_name, idx);
528}
529
530} // namespace VegaISA
531} // namespace gem5
AbstractMemory declaration.
#define DPRINTF(x,...)
Definition trace.hh:209
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 setLE(T v)
Set the value in the data pointer to v as little endian.
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
@ 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
gem5::Flags< FlagsType > Flags
Definition request.hh:102
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
void set(Type mask)
Set all flag's bits matching the given mask.
Definition flags.hh:116
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Bitfield< 3, 0 > mask
Definition pcstate.hh:63
Bitfield< 4, 0 > mode
Definition misc_types.hh:74
Bitfield< 7 > i
Definition misc_types.hh:67
classes that represnt vector/scalar operands in VEGA ISA.
Definition faults.cc:39
Bitfield< 11, 7 > fragment
Definition pagetable.hh:58
const Addr PageShift
Definition page_size.hh:41
Bitfield< 7 > present
Definition misc.hh:1027
Bitfield< 3 > addr
Definition types.hh:84
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
std::shared_ptr< FaultBase > Fault
Definition types.hh:249
T safe_cast(U &&ref_or_ptr)
Definition cast.hh:74
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
Packet * PacketPtr
constexpr decltype(nullptr) NoFault
Definition types.hh:253

Generated on Mon May 26 2025 09:19:06 for gem5 by doxygen 1.13.2