gem5  v22.1.0.0
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 
40 namespace gem5
41 {
42 namespace VegaISA
43 {
44 
45 /*
46  * Functional/atomic mode methods
47  */
48 Fault
49 Walker::startFunctional(Addr base, Addr &addr, unsigned &logBytes,
50  BaseMMU::Mode mode, bool &isSystem)
51 {
52  PageTableEntry pte;
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 
61 Fault
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 
72 Fault
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 
94  state = nextState;
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  */
107 void
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 
122 void
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 
160 void
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 
198 Fault
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 
232 void
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 
330 void
332 {
333  nextState = Ready;
334  delete read;
335  read = NULL;
336  walker->currStates.remove(this);
337 }
338 
342 void
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 
360 bool 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 
377 bool
379 {
380  walker->recvTimingResp(pkt);
381 
382  return true;
383 }
384 
385 void
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 
398 void
400 {
401  walker->recvReqRetry();
402 }
403 
404 void
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 
416 void
418 {
419  tlb->walkerResponse(entry, pkt);
420 
421  delete state;
422 }
423 
424 
425 /*
426  * Helper methods
427  */
428 bool
430 {
431  return retrying;
432 }
433 
434 void
436 {
437  retrying = false;
438  sendPackets();
439 }
440 
441 Fault
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 
457 uint64_t
458 Walker::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 
469 Port &
470 Walker::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:186
@ Execute
Definition: mmu.hh:56
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
Addr getAddr() const
Definition: packet.hh:805
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:376
unsigned getSize() const
Definition: packet.hh:815
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:495
@ 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
constexpr uint64_t mask(unsigned nbits)
Generate a 64-bit mask of 'nbits' 1s, right justified.
Definition: bitfield.hh:63
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Definition: sim_object.cc:126
atomic_var_t state
Definition: helpers.cc:188
uint8_t flags
Definition: helpers.cc:66
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
ProbePointArg< PacketInfo > Packet
Packet probe point.
Definition: mem.hh:109
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
std::shared_ptr< FaultBase > Fault
Definition: types.hh:248
std::shared_ptr< Request > RequestPtr
Definition: request.hh:92
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 Wed Dec 21 2022 10:22:24 for gem5 by doxygen 1.9.1