gem5  v22.1.0.0
cpu.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011,2013,2017-2018, 2020 ARM Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Copyright (c) 2006 The Regents of The University of Michigan
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are
19  * met: redistributions of source code must retain the above copyright
20  * notice, this list of conditions and the following disclaimer;
21  * redistributions in binary form must reproduce the above copyright
22  * notice, this list of conditions and the following disclaimer in the
23  * documentation and/or other materials provided with the distribution;
24  * neither the name of the copyright holders nor the names of its
25  * contributors may be used to endorse or promote products derived from
26  * this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  */
40 
41 #include "cpu/checker/cpu.hh"
42 
43 #include <list>
44 #include <string>
45 
46 #include "arch/generic/tlb.hh"
47 #include "cpu/base.hh"
48 #include "cpu/simple_thread.hh"
49 #include "cpu/static_inst.hh"
50 #include "cpu/thread_context.hh"
51 #include "cpu/utils.hh"
52 #include "params/CheckerCPU.hh"
53 #include "sim/full_system.hh"
54 
55 namespace gem5
56 {
57 
58 void
60 {
63 }
64 
66  : BaseCPU(p, true),
67  systemPtr(NULL), icachePort(NULL), dcachePort(NULL),
68  tc(NULL), thread(NULL),
69  unverifiedReq(nullptr),
70  unverifiedMemData(nullptr)
71 {
72  curStaticInst = NULL;
73  curMacroStaticInst = NULL;
74 
75  numInst = 0;
76  startNumInst = 0;
77  numLoad = 0;
78  startNumLoad = 0;
79  youngestSN = 0;
80 
81  changedPC = willChangePC = false;
82 
83  exitOnError = p.exitOnError;
84  warnOnlyOnLoadError = p.warnOnlyOnLoadError;
85  mmu = p.mmu;
86  workload = p.workload;
87 
88  updateOnError = true;
89 }
90 
92 {
93 }
94 
95 void
97 {
98  const Params &p = params();
99 
100  systemPtr = system;
101 
102  if (FullSystem) {
103  thread = new SimpleThread(this, 0, systemPtr, mmu, p.isa[0],
104  p.decoder[0]);
105  } else {
106  thread = new SimpleThread(this, 0, systemPtr,
107  workload.size() ? workload[0] : NULL,
108  mmu, p.isa[0], p.decoder[0]);
109  }
110 
111  tc = thread->getTC();
112  threadContexts.push_back(tc);
113  // Thread should never be null after this
114  assert(thread != NULL);
115 }
116 
117 void
119 {
120  icachePort = icache_port;
121 }
122 
123 void
125 {
126  dcachePort = dcache_port;
127 }
128 
129 void
130 CheckerCPU::serialize(std::ostream &os) const
131 {
132 }
133 
134 void
136 {
137 }
138 
142  const std::vector<bool>& byte_enable,
143  int& frag_size, int& size_left) const
144 {
145  frag_size = std::min(
146  cacheLineSize() - addrBlockOffset(frag_addr, cacheLineSize()),
147  (Addr) size_left);
148  size_left -= frag_size;
149 
150  RequestPtr mem_req;
151 
152  // Set up byte-enable mask for the current fragment
153  auto it_start = byte_enable.cbegin() + (size - (frag_size +
154  size_left));
155  auto it_end = byte_enable.cbegin() + (size - size_left);
156  if (isAnyActiveElement(it_start, it_end)) {
157  mem_req = std::make_shared<Request>(frag_addr, frag_size,
159  tc->contextId());
160  mem_req->setByteEnable(std::vector<bool>(it_start, it_end));
161  }
162 
163  return mem_req;
164 }
165 
166 Fault
167 CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size,
169  const std::vector<bool>& byte_enable)
170 {
171  assert(byte_enable.size() == size);
172 
173  Fault fault = NoFault;
174  bool checked_flags = false;
175  bool flags_match = true;
176  Addr pAddr = 0x0;
177 
178  Addr frag_addr = addr;
179  int frag_size = 0;
180  int size_left = size;
181  bool predicate;
182 
183  // Need to account for multiple accesses like the Atomic and TimingSimple
184  while (1) {
185  RequestPtr mem_req = genMemFragmentRequest(frag_addr, size, flags,
186  byte_enable, frag_size,
187  size_left);
188 
189  predicate = (mem_req != nullptr);
190 
191  // translate to physical address
192  if (predicate) {
193  fault = mmu->translateFunctional(mem_req, tc, BaseMMU::Read);
194  }
195 
196  if (predicate && !checked_flags && fault == NoFault && unverifiedReq) {
197  flags_match = checkFlags(unverifiedReq, mem_req->getVaddr(),
198  mem_req->getPaddr(), mem_req->getFlags());
199  pAddr = mem_req->getPaddr();
200  checked_flags = true;
201  }
202 
203  // Now do the access
204  if (predicate && fault == NoFault &&
205  !mem_req->getFlags().isSet(Request::NO_ACCESS)) {
206  PacketPtr pkt = Packet::createRead(mem_req);
207 
208  pkt->dataStatic(data);
209 
210  if (!(mem_req->isUncacheable() || mem_req->isLocalAccess())) {
211  // Access memory to see if we have the same data
213  } else {
214  // Assume the data is correct if it's an uncached access
215  memcpy(data, unverifiedMemData, frag_size);
216  }
217 
218  delete pkt;
219  }
220 
221  if (fault != NoFault) {
222  if (mem_req->isPrefetch()) {
223  fault = NoFault;
224  }
225  break;
226  }
227 
228  //If we don't need to access a second cache line, stop now.
229  if (size_left == 0)
230  {
231  break;
232  }
233 
234  // Setup for accessing next cache line
235  frag_addr += frag_size;
236  data += frag_size;
237  unverifiedMemData += frag_size;
238  }
239 
240  if (!flags_match) {
241  warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n",
242  curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
243  unverifiedReq->getFlags(), frag_addr, pAddr, flags);
244  handleError();
245  }
246 
247  return fault;
248 }
249 
250 Fault
251 CheckerCPU::writeMem(uint8_t *data, unsigned size,
252  Addr addr, Request::Flags flags, uint64_t *res,
253  const std::vector<bool>& byte_enable)
254 {
255  assert(byte_enable.size() == size);
256 
257  Fault fault = NoFault;
258  bool checked_flags = false;
259  bool flags_match = true;
260  Addr pAddr = 0x0;
261  static uint8_t zero_data[64] = {};
262 
263  Addr frag_addr = addr;
264  int frag_size = 0;
265  int size_left = size;
266  bool predicate;
267 
268  // Need to account for a multiple access like Atomic and Timing CPUs
269  while (1) {
270  RequestPtr mem_req = genMemFragmentRequest(frag_addr, size, flags,
271  byte_enable, frag_size,
272  size_left);
273 
274  predicate = (mem_req != nullptr);
275 
276  if (predicate) {
277  fault = mmu->translateFunctional(mem_req, tc, BaseMMU::Write);
278  }
279 
280  if (predicate && !checked_flags && fault == NoFault && unverifiedReq) {
281  flags_match = checkFlags(unverifiedReq, mem_req->getVaddr(),
282  mem_req->getPaddr(), mem_req->getFlags());
283  pAddr = mem_req->getPaddr();
284  checked_flags = true;
285  }
286 
287  /*
288  * We don't actually check memory for the store because there
289  * is no guarantee it has left the lsq yet, and therefore we
290  * can't verify the memory on stores without lsq snooping
291  * enabled. This is left as future work for the Checker: LSQ snooping
292  * and memory validation after stores have committed.
293  */
294  bool was_prefetch = mem_req->isPrefetch();
295 
296  //If we don't need to access a second cache line, stop now.
297  if (fault != NoFault || size_left == 0)
298  {
299  if (fault != NoFault && was_prefetch) {
300  fault = NoFault;
301  }
302  break;
303  }
304 
305  frag_addr += frag_size;
306  }
307 
308  if (!flags_match) {
309  warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n",
310  curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
311  unverifiedReq->getFlags(), frag_addr, pAddr, flags);
312  handleError();
313  }
314 
315  // Assume the result was the same as the one passed in. This checker
316  // doesn't check if the SC should succeed or fail, it just checks the
317  // value.
318  if (unverifiedReq && res && unverifiedReq->extraDataValid())
319  *res = unverifiedReq->getExtraData();
320 
321  // Entire purpose here is to make sure we are getting the
322  // same data to send to the mem system as the CPU did.
323  // Cannot check this is actually what went to memory because
324  // there stores can be in ld/st queue or coherent operations
325  // overwriting values.
326  bool extraData = false;
327  if (unverifiedReq) {
328  extraData = unverifiedReq->extraDataValid() ?
329  unverifiedReq->getExtraData() : true;
330  }
331 
332  // If the request is to ZERO a cache block, there is no data to check
333  // against, but it's all zero. We need something to compare to, so use a
334  // const set of zeros.
336  assert(!data);
337  assert(sizeof(zero_data) <= size);
338  data = zero_data;
339  }
340 
342  memcmp(data, unverifiedMemData, size) && extraData) {
343  warn("%lli: Store value does not match value sent to memory! "
344  "data: %#x inst_data: %#x", curTick(), data,
346  handleError();
347  }
348 
349  return fault;
350 }
351 
355 bool
356 CheckerCPU::checkFlags(const RequestPtr &unverified_req, Addr vAddr,
357  Addr pAddr, int flags)
358 {
359  Addr unverifiedVAddr = unverified_req->getVaddr();
360  Addr unverifiedPAddr = unverified_req->getPaddr();
361  int unverifiedFlags = unverified_req->getFlags();
362 
363  if (unverifiedVAddr != vAddr ||
364  unverifiedPAddr != pAddr ||
365  unverifiedFlags != flags) {
366  return false;
367  }
368 
369  return true;
370 }
371 
372 void
374 {
375  warn("%lli: Checker PC:%s",
376  curTick(), thread->pcState());
377  panic("Checker found an error!");
378 }
379 
380 } // namespace gem5
const char data[]
System * system
Definition: base.hh:375
unsigned int cacheLineSize() const
Get the cache line size of the system.
Definition: base.hh:380
std::vector< ThreadContext * > threadContexts
Definition: base.hh:256
virtual void setThreadContext(ThreadContext *_tc)
Definition: isa.hh:80
virtual Fault translateFunctional(const RequestPtr &req, ThreadContext *tc, Mode mode)
Definition: mmu.cc:118
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: cpu.cc:59
Fault readMem(Addr addr, uint8_t *data, unsigned size, Request::Flags flags, const std::vector< bool > &byte_enable) override
Definition: cpu.cc:167
Counter numInst
Definition: cpu.hh:142
RequestPort * icachePort
Definition: cpu.hh:127
StaticInstPtr curStaticInst
Definition: cpu.hh:138
Counter numLoad
Definition: cpu.hh:159
bool updateOnError
Definition: cpu.hh:434
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
Definition: cpu.cc:130
bool exitOnError
Definition: cpu.hh:433
void setIcachePort(RequestPort *icache_port)
Definition: cpu.cc:118
bool willChangePC
Definition: cpu.hh:431
CheckerCPU(const Params &p)
Definition: cpu.cc:65
void setSystem(System *system)
Definition: cpu.cc:96
ThreadContext * tc
Definition: cpu.hh:130
std::vector< Process * > workload
Definition: cpu.hh:123
SimpleThread * thread
Definition: cpu.hh:150
bool warnOnlyOnLoadError
Definition: cpu.hh:435
Fault writeMem(uint8_t *data, unsigned size, Addr addr, Request::Flags flags, uint64_t *res, const std::vector< bool > &byte_enable) override
Definition: cpu.cc:251
Counter startNumLoad
Definition: cpu.hh:160
RequestPort * dcachePort
Definition: cpu.hh:128
void handleError()
Definition: cpu.hh:412
RequestorID requestorId
id attached to all issued requests
Definition: cpu.hh:88
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition: cpu.cc:135
bool changedPC
Definition: cpu.hh:430
bool checkFlags(const RequestPtr &unverified_req, Addr vAddr, Addr pAddr, int flags)
Checks if the flags set by the Checker and Checkee match.
Definition: cpu.cc:356
System * systemPtr
Definition: cpu.hh:125
uint8_t * unverifiedMemData
Definition: cpu.hh:428
InstSeqNum youngestSN
Definition: cpu.hh:437
RequestPtr genMemFragmentRequest(Addr frag_addr, int size, Request::Flags flags, const std::vector< bool > &byte_enable, int &frag_size, int &size_left) const
Helper function used to generate the request for a single fragment of a memory access.
Definition: cpu.cc:140
BaseMMU * mmu
Definition: cpu.hh:132
void dumpAndExit()
Definition: cpu.cc:373
RequestPtr unverifiedReq
Definition: cpu.hh:427
void setDcachePort(RequestPort *dcache_port)
Definition: cpu.cc:124
Counter startNumInst
Definition: cpu.hh:143
StaticInstPtr curMacroStaticInst
Definition: cpu.hh:139
virtual ~CheckerCPU()
Definition: cpu.cc:91
ClockedObjectParams Params
Parameters of ClockedObject.
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
Definition: pcstate.hh:107
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
void dataStatic(T *p)
Set the data pointer to the following value that should not be freed.
Definition: packet.hh:1162
static PacketPtr createRead(const RequestPtr &req)
Constructor-like methods that return Packets based on Request objects.
Definition: packet.hh:1035
A RequestPort is a specialisation of a Port, which implements the default protocol for the three diff...
Definition: port.hh:79
void sendFunctional(PacketPtr pkt) const
Send a functional request packet, where the data is instantly updated everywhere in the memory system...
Definition: port.hh:485
@ NO_ACCESS
The request should not cause a memory access.
Definition: request.hh:146
static const FlagsType STORE_NO_DATA
Definition: request.hh:260
The SimpleThread object provides a combination of the ThreadState object and the ThreadContext interf...
ThreadContext * getTC()
Returns the pointer to this SimpleThread's ThreadContext.
const PCStateBase & pcState() const override
RequestorID getRequestorId(const SimObject *requestor, std::string subrequestor={})
Request an id used to create a request object in the system.
Definition: system.cc:475
virtual BaseISA * getIsaPtr() const =0
virtual ContextID contextId() const =0
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
const Params & params() const
Definition: sim_object.hh:176
uint8_t flags
Definition: helpers.cc:66
#define warn(...)
Definition: logging.hh:246
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 15 > system
Definition: misc.hh:1004
Bitfield< 17 > os
Definition: misc.hh:810
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:248
std::shared_ptr< Request > RequestPtr
Definition: request.hh:92
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
Addr addrBlockOffset(Addr addr, Addr block_size)
Calculates the offset of a given address wrt aligned fixed-size blocks.
Definition: utils.hh:53
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
Definition: root.cc:220
constexpr decltype(nullptr) NoFault
Definition: types.hh:253
bool isAnyActiveElement(const std::vector< bool >::const_iterator &it_start, const std::vector< bool >::const_iterator &it_end)
Test if there is any active element in an enablement range.
Definition: utils.hh:89

Generated on Wed Dec 21 2022 10:22:24 for gem5 by doxygen 1.9.1