gem5 v24.0.0.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());
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 // Block fragment size can change the size of the pages pointed to while
243 // moving to the next PDE. A value of 0 implies native page size. A
244 // non-zero value implies the next leaf in the page table is a PTE unless
245 // the F bit is set. If we see a non-zero value, set it here and print
246 // for debugging.
247 if (pde.blockFragmentSize) {
248 DPRINTF(GPUPTWalker,
249 "blockFragmentSize: %d, pde: %#016lx, state: %d\n",
250 pde.blockFragmentSize, pde, state);
251 blockFragmentSize = pde.blockFragmentSize;
252
253 // At this time, only a value of 9 is used in the driver:
254 // https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/
255 // amd/amdgpu/gmc_v9_0.c#L1165
256 assert(pde.blockFragmentSize == 9);
257 }
258
259 switch(state) {
260 case PDE2:
261 if (pde.p) {
262 DPRINTF(GPUPTWalker, "Treating PDE2 as PTE: %#016x frag: %d\n",
263 (uint64_t)pte, pte.fragment);
264 entry.pte = pte;
265 int fragment = pte.fragment;
266 entry.logBytes = PageShift + std::min(3*9, fragment);
267 entry.vaddr <<= PageShift;
268 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
269 doEndWalk = true;
270 }
271
272 // Read the pde1Addr
273 part1 = ((((uint64_t)pte) >> 6) << 3);
274 part2 = offsetFunc(vaddr, 3*9, 2*9);
275 nextRead = ((part1 + part2) << 3) & mask(48);
276 DPRINTF(GPUPTWalker,
277 "Got PDE2 entry %#016x. write:%s->%#016x va:%#016x\n",
278 (uint64_t)pte, pte.w == 0 ? "yes" : "no", nextRead, vaddr);
279 nextState = PDE1;
280 break;
281 case PDE1:
282 if (pde.p) {
283 DPRINTF(GPUPTWalker, "Treating PDE1 as PTE: %#016x frag: %d\n",
284 (uint64_t)pte, pte.fragment);
285 entry.pte = pte;
286 int fragment = pte.fragment;
287 entry.logBytes = PageShift + std::min(2*9, fragment);
288 entry.vaddr <<= PageShift;
289 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
290 doEndWalk = true;
291 }
292
293 // Read the pde0Addr
294 part1 = ((((uint64_t)pte) >> 6) << 3);
295 part2 = offsetFunc(vaddr, 2*9, 9);
296 nextRead = ((part1 + part2) << 3) & mask(48);
297 DPRINTF(GPUPTWalker,
298 "Got PDE1 entry %#016x. write:%s->%#016x va: %#016x\n",
299 (uint64_t)pte, pte.w == 0 ? "yes" : "no", nextRead, vaddr);
300 nextState = PDE0;
301 break;
302 case PDE0:
303 if (pde.p || (blockFragmentSize && !pte.f)) {
304 DPRINTF(GPUPTWalker, "Treating PDE0 as PTE: %#016x frag: %d\n",
305 (uint64_t)pte, pte.fragment);
306 entry.pte = pte;
307 int fragment = pte.fragment;
308 entry.logBytes = PageShift + std::min(9, fragment);
309 entry.vaddr <<= PageShift;
310 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
311 doEndWalk = true;
312 }
313 // Read the PteAddr
314 part1 = ((((uint64_t)pte) >> 6) << 3);
315 if (pte.f) {
316 // For F bit we want to use the blockFragmentSize in the previous
317 // PDE and the blockFragmentSize in this PTE for offset function.
318 part2 = offsetFunc(vaddr,
320 pde.blockFragmentSize);
321 } else {
322 part2 = offsetFunc(vaddr, 9, 0);
323 }
324 nextRead = ((part1 + part2) << 3) & mask(48);
325 DPRINTF(GPUPTWalker,
326 "Got PDE0 entry %#016x. write:%s->%#016x va:%#016x\n",
327 (uint64_t)pte, pte.w == 0 ? "yes" : "no", nextRead, vaddr);
328 nextState = PTE;
329 break;
330 case PTE:
331 DPRINTF(GPUPTWalker,
332 " PTE entry %#016x. write: %s va: %#016x\n",
333 (uint64_t)pte, pte.w == 0 ? "yes" : "no", vaddr);
334 entry.pte = pte;
335 entry.logBytes = PageShift;
336 entry.vaddr <<= PageShift;
337 entry.vaddr = entry.vaddr & ~mask(entry.logBytes);
338 doEndWalk = true;
339 break;
340 default:
341 panic("Unknown page table walker state %d!\n");
342 }
343
344 if (badNX || !pte.v) {
345 doEndWalk = true;
346 fault = pageFault(pte.v);
347 nextState = state;
348 }
349}
350
351void
353{
354 nextState = Ready;
355 delete read;
356 read = NULL;
357 walker->currStates.remove(this);
358}
359
363void
365{
366 // If we're already waiting for the port to become available, just return.
367 if (retrying)
368 return;
369
370 if (!walker->sendTiming(this, read)) {
371 DPRINTF(GPUPTWalker, "Timing request for %#lx failed\n",
372 read->getAddr());
373
374 retrying = true;
375 } else {
376 DPRINTF(GPUPTWalker, "Timing request for %#lx successful\n",
377 read->getAddr());
378 }
379}
380
381bool Walker::sendTiming(WalkerState* sending_walker, PacketPtr pkt)
382{
383 auto walker_state = new WalkerSenderState(sending_walker);
384 pkt->pushSenderState(walker_state);
385
386 if (port.sendTimingReq(pkt)) {
387 DPRINTF(GPUPTWalker, "Sending timing read to %#lx from walker %p\n",
388 pkt->getAddr(), sending_walker);
389
390 return true;
391 } else {
392 (void)pkt->popSenderState();
393 delete walker_state;
394 }
395
396 return false;
397}
398
399bool
401{
402 walker->recvTimingResp(pkt);
403
404 return true;
405}
406
407void
409{
410 WalkerSenderState * senderState =
412
413 DPRINTF(GPUPTWalker, "Got response for %#lx from walker %p -- %#lx\n",
414 pkt->getAddr(), senderState->senderWalk, pkt->getLE<uint64_t>());
415 senderState->senderWalk->startWalk();
416
417 delete senderState;
418}
419
420void
422{
423 walker->recvReqRetry();
424}
425
426void
428{
430 for (iter = currStates.begin(); iter != currStates.end(); iter++) {
431 WalkerState * walkerState = *(iter);
432 if (walkerState->isRetrying()) {
433 walkerState->retry();
434 }
435 }
436}
437
438void
440{
441 tlb->walkerResponse(entry, pkt);
442
443 delete state;
444}
445
446
447/*
448 * Helper methods
449 */
450bool
452{
453 return retrying;
454}
455
456void
458{
459 retrying = false;
460 sendPackets();
461}
462
463Fault
465{
466 DPRINTF(GPUPTWalker, "Raising page fault.\n");
467 ExceptionCode code;
468 if (mode == BaseMMU::Read)
470 else if (mode == BaseMMU::Write)
472 else
474 if (mode == BaseMMU::Execute && !enableNX)
476 return std::make_shared<PageFault>(entry.vaddr, code, present, mode, true);
477}
478
479uint64_t
480Walker::WalkerState::offsetFunc(Addr logicalAddr, int top, int lsb)
481{
482 assert(top < 32);
483 assert(lsb < 32);
484 return ((logicalAddr & ((1 << top) - 1)) >> lsb);
485}
486
487
491Port &
492Walker::getPort(const std::string &if_name, PortID idx)
493{
494 if (if_name == "port")
495 return port;
496 else
497 return ClockedObject::getPort(if_name, idx);
498}
499
500} // namespace VegaISA
501} // 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:603
@ 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
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:211
uint8_t flags
Definition helpers.cc:87
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:1027
Bitfield< 3 > addr
Definition types.hh:84
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria 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
constexpr decltype(nullptr) NoFault
Definition types.hh:253

Generated on Tue Jun 18 2024 16:24:00 for gem5 by doxygen 1.11.0