gem5  v20.1.0.0
cpu.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011,2013,2017-2018 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 using namespace std;
56 using namespace TheISA;
57 
58 void
60 {
61  requestorId = systemPtr->getRequestorId(this);
62 }
63 
65  : BaseCPU(p, true), systemPtr(NULL), icachePort(NULL), dcachePort(NULL),
66  tc(NULL), thread(NULL),
67  unverifiedReq(nullptr),
68  unverifiedMemData(nullptr)
69 {
70  curStaticInst = NULL;
71  curMacroStaticInst = NULL;
72 
73  numInst = 0;
74  startNumInst = 0;
75  numLoad = 0;
76  startNumLoad = 0;
77  youngestSN = 0;
78 
79  changedPC = willChangePC = false;
80 
81  exitOnError = p->exitOnError;
82  warnOnlyOnLoadError = p->warnOnlyOnLoadError;
83  itb = p->itb;
84  dtb = p->dtb;
85  workload = p->workload;
86 
87  updateOnError = true;
88 }
89 
91 {
92 }
93 
94 void
96 {
97  const Params *p(dynamic_cast<const Params *>(_params));
98 
99  systemPtr = system;
100 
101  if (FullSystem) {
102  thread = new SimpleThread(this, 0, systemPtr, itb, dtb, p->isa[0]);
103  } else {
104  thread = new SimpleThread(this, 0, systemPtr,
105  workload.size() ? workload[0] : NULL,
106  itb, dtb, p->isa[0]);
107  }
108 
109  tc = thread->getTC();
110  threadContexts.push_back(tc);
111  // Thread should never be null after this
112  assert(thread != NULL);
113 }
114 
115 void
117 {
118  icachePort = icache_port;
119 }
120 
121 void
123 {
124  dcachePort = dcache_port;
125 }
126 
127 void
128 CheckerCPU::serialize(ostream &os) const
129 {
130 }
131 
132 void
134 {
135 }
136 
139  Request::Flags flags,
140  const std::vector<bool>& byte_enable,
141  int& frag_size, int& size_left) const
142 {
143  frag_size = std::min(
144  cacheLineSize() - addrBlockOffset(frag_addr, cacheLineSize()),
145  (Addr) size_left);
146  size_left -= frag_size;
147 
148  RequestPtr mem_req;
149 
150  if (!byte_enable.empty()) {
151  // Set up byte-enable mask for the current fragment
152  auto it_start = byte_enable.cbegin() + (size - (frag_size +
153  size_left));
154  auto it_end = byte_enable.cbegin() + (size - size_left);
155  if (isAnyActiveElement(it_start, it_end)) {
156  mem_req = std::make_shared<Request>(frag_addr, frag_size,
157  flags, requestorId, thread->pcState().instAddr(),
158  tc->contextId());
159  mem_req->setByteEnable(std::vector<bool>(it_start, it_end));
160  }
161  } else {
162  mem_req = std::make_shared<Request>(frag_addr, frag_size,
163  flags, requestorId, thread->pcState().instAddr(),
164  tc->contextId());
165  }
166 
167  return mem_req;
168 }
169 
170 Fault
171 CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size,
172  Request::Flags flags,
173  const std::vector<bool>& byte_enable)
174 {
175  assert(byte_enable.empty() || byte_enable.size() == size);
176 
177  Fault fault = NoFault;
178  bool checked_flags = false;
179  bool flags_match = true;
180  Addr pAddr = 0x0;
181 
182  Addr frag_addr = addr;
183  int frag_size = 0;
184  int size_left = size;
185  bool predicate;
186 
187  // Need to account for multiple accesses like the Atomic and TimingSimple
188  while (1) {
189  RequestPtr mem_req = genMemFragmentRequest(frag_addr, size, flags,
190  byte_enable, frag_size,
191  size_left);
192 
193  predicate = (mem_req != nullptr);
194 
195  // translate to physical address
196  if (predicate) {
197  fault = dtb->translateFunctional(mem_req, tc, BaseTLB::Read);
198  }
199 
200  if (predicate && !checked_flags && fault == NoFault && unverifiedReq) {
201  flags_match = checkFlags(unverifiedReq, mem_req->getVaddr(),
202  mem_req->getPaddr(), mem_req->getFlags());
203  pAddr = mem_req->getPaddr();
204  checked_flags = true;
205  }
206 
207  // Now do the access
208  if (predicate && fault == NoFault &&
209  !mem_req->getFlags().isSet(Request::NO_ACCESS)) {
210  PacketPtr pkt = Packet::createRead(mem_req);
211 
212  pkt->dataStatic(data);
213 
214  if (!(mem_req->isUncacheable() || mem_req->isLocalAccess())) {
215  // Access memory to see if we have the same data
217  } else {
218  // Assume the data is correct if it's an uncached access
219  memcpy(data, unverifiedMemData, frag_size);
220  }
221 
222  delete pkt;
223  }
224 
225  if (fault != NoFault) {
226  if (mem_req->isPrefetch()) {
227  fault = NoFault;
228  }
229  break;
230  }
231 
232  //If we don't need to access a second cache line, stop now.
233  if (size_left == 0)
234  {
235  break;
236  }
237 
238  // Setup for accessing next cache line
239  frag_addr += frag_size;
240  data += frag_size;
241  unverifiedMemData += frag_size;
242  }
243 
244  if (!flags_match) {
245  warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n",
246  curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
247  unverifiedReq->getFlags(), frag_addr, pAddr, flags);
248  handleError();
249  }
250 
251  return fault;
252 }
253 
254 Fault
255 CheckerCPU::writeMem(uint8_t *data, unsigned size,
256  Addr addr, Request::Flags flags, uint64_t *res,
257  const std::vector<bool>& byte_enable)
258 {
259  assert(byte_enable.empty() || byte_enable.size() == size);
260 
261  Fault fault = NoFault;
262  bool checked_flags = false;
263  bool flags_match = true;
264  Addr pAddr = 0x0;
265  static uint8_t zero_data[64] = {};
266 
267  Addr frag_addr = addr;
268  int frag_size = 0;
269  int size_left = size;
270  bool predicate;
271 
272  // Need to account for a multiple access like Atomic and Timing CPUs
273  while (1) {
274  RequestPtr mem_req = genMemFragmentRequest(frag_addr, size, flags,
275  byte_enable, frag_size,
276  size_left);
277 
278  predicate = (mem_req != nullptr);
279 
280  if (predicate) {
281  fault = dtb->translateFunctional(mem_req, tc, BaseTLB::Write);
282  }
283 
284  if (predicate && !checked_flags && fault == NoFault && unverifiedReq) {
285  flags_match = checkFlags(unverifiedReq, mem_req->getVaddr(),
286  mem_req->getPaddr(), mem_req->getFlags());
287  pAddr = mem_req->getPaddr();
288  checked_flags = true;
289  }
290 
291  /*
292  * We don't actually check memory for the store because there
293  * is no guarantee it has left the lsq yet, and therefore we
294  * can't verify the memory on stores without lsq snooping
295  * enabled. This is left as future work for the Checker: LSQ snooping
296  * and memory validation after stores have committed.
297  */
298  bool was_prefetch = mem_req->isPrefetch();
299 
300  //If we don't need to access a second cache line, stop now.
301  if (fault != NoFault || size_left == 0)
302  {
303  if (fault != NoFault && was_prefetch) {
304  fault = NoFault;
305  }
306  break;
307  }
308 
309  frag_addr += frag_size;
310  }
311 
312  if (!flags_match) {
313  warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n",
314  curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
315  unverifiedReq->getFlags(), frag_addr, pAddr, flags);
316  handleError();
317  }
318 
319  // Assume the result was the same as the one passed in. This checker
320  // doesn't check if the SC should succeed or fail, it just checks the
321  // value.
322  if (unverifiedReq && res && unverifiedReq->extraDataValid())
323  *res = unverifiedReq->getExtraData();
324 
325  // Entire purpose here is to make sure we are getting the
326  // same data to send to the mem system as the CPU did.
327  // Cannot check this is actually what went to memory because
328  // there stores can be in ld/st queue or coherent operations
329  // overwriting values.
330  bool extraData = false;
331  if (unverifiedReq) {
332  extraData = unverifiedReq->extraDataValid() ?
333  unverifiedReq->getExtraData() : true;
334  }
335 
336  // If the request is to ZERO a cache block, there is no data to check
337  // against, but it's all zero. We need something to compare to, so use a
338  // const set of zeros.
339  if (flags & Request::STORE_NO_DATA) {
340  assert(!data);
341  assert(sizeof(zero_data) <= size);
342  data = zero_data;
343  }
344 
346  memcmp(data, unverifiedMemData, size) && extraData) {
347  warn("%lli: Store value does not match value sent to memory! "
348  "data: %#x inst_data: %#x", curTick(), data,
350  handleError();
351  }
352 
353  return fault;
354 }
355 
359 bool
360 CheckerCPU::checkFlags(const RequestPtr &unverified_req, Addr vAddr,
361  Addr pAddr, int flags)
362 {
363  Addr unverifiedVAddr = unverified_req->getVaddr();
364  Addr unverifiedPAddr = unverified_req->getPaddr();
365  int unverifiedFlags = unverified_req->getFlags();
366 
367  if (unverifiedVAddr != vAddr ||
368  unverifiedPAddr != pAddr ||
369  unverifiedFlags != flags) {
370  return false;
371  }
372 
373  return true;
374 }
375 
376 void
378 {
379  warn("%lli: Checker PC:%s",
380  curTick(), thread->pcState());
381  panic("Checker found an error!");
382 }
CheckerCPU::startNumInst
Counter startNumInst
Definition: cpu.hh:147
CheckerCPU::writeMem
Fault writeMem(uint8_t *data, unsigned size, Addr addr, Request::Flags flags, uint64_t *res, const std::vector< bool > &byte_enable=std::vector< bool >()) override
Definition: cpu.cc:255
utils.hh
X86ISA::os
Bitfield< 17 > os
Definition: misc.hh:803
warn
#define warn(...)
Definition: logging.hh:239
SimpleThread::pcState
TheISA::PCState pcState() const override
Definition: simple_thread.hh:517
BaseTLB::Read
@ Read
Definition: tlb.hh:57
data
const char data[]
Definition: circlebuf.test.cc:42
CheckerCPU::thread
SimpleThread * thread
Definition: cpu.hh:154
CheckerCPU::serialize
void serialize(CheckpointOut &cp) const override
Definition: cpu.cc:128
CheckerCPU::startNumLoad
Counter startNumLoad
Definition: cpu.hh:171
Flags< FlagsType >
Request::NO_ACCESS
@ NO_ACCESS
The request should not cause a memory access.
Definition: request.hh:135
TheISA
Definition: decode_cache.hh:37
BaseCPU::cacheLineSize
unsigned int cacheLineSize() const
Get the cache line size of the system.
Definition: base.hh:376
tlb.hh
CheckerCPU::workload
std::vector< Process * > workload
Definition: cpu.hh:126
CheckerCPU::setSystem
void setSystem(System *system)
Definition: cpu.cc:95
CheckerCPU::readMem
Fault readMem(Addr addr, uint8_t *data, unsigned size, Request::Flags flags, const std::vector< bool > &byte_enable=std::vector< bool >()) override
Definition: cpu.cc:171
RequestPtr
std::shared_ptr< Request > RequestPtr
Definition: request.hh:82
std::vector< bool >
FullSystem
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
Definition: root.cc:132
CheckerCPU::numInst
Counter numInst
Definition: cpu.hh:146
RequestPort::sendFunctional
void sendFunctional(PacketPtr pkt) const
Send a functional request packet, where the data is instantly updated everywhere in the memory system...
Definition: port.hh:482
CheckerCPU::itb
BaseTLB * itb
Definition: cpu.hh:135
CheckerCPU::~CheckerCPU
virtual ~CheckerCPU()
Definition: cpu.cc:90
CheckerCPU::CheckerCPU
CheckerCPU(Params *p)
Definition: cpu.cc:64
CheckerCPU::warnOnlyOnLoadError
bool warnOnlyOnLoadError
Definition: cpu.hh:641
CheckerCPU::init
void init() override
Definition: cpu.cc:59
SimpleThread
The SimpleThread object provides a combination of the ThreadState object and the ThreadContext interf...
Definition: simple_thread.hh:89
isAnyActiveElement
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:86
CheckerCPU::dcachePort
RequestPort * dcachePort
Definition: cpu.hh:131
CheckerCPU::curStaticInst
StaticInstPtr curStaticInst
Definition: cpu.hh:142
CheckerCPU::numLoad
Counter numLoad
Definition: cpu.hh:170
X86ISA::system
Bitfield< 15 > system
Definition: misc.hh:997
CheckerCPU::dtb
BaseTLB * dtb
Definition: cpu.hh:136
CheckerCPU::youngestSN
InstSeqNum youngestSN
Definition: cpu.hh:643
cp
Definition: cprintf.cc:40
CheckerCPU::unserialize
void unserialize(CheckpointIn &cp) override
Definition: cpu.cc:133
CheckerCPU::handleError
void handleError()
Definition: cpu.hh:618
CheckerCPU::dumpAndExit
void dumpAndExit()
Definition: cpu.cc:377
SimpleThread::getTC
ThreadContext * getTC()
Returns the pointer to this SimpleThread's ThreadContext.
Definition: simple_thread.hh:169
System
Definition: system.hh:73
Fault
std::shared_ptr< FaultBase > Fault
Definition: types.hh:240
Packet::createRead
static PacketPtr createRead(const RequestPtr &req)
Constructor-like methods that return Packets based on Request objects.
Definition: packet.hh:980
cpu.hh
BaseTLB::translateFunctional
virtual Fault translateFunctional(const RequestPtr &req, ThreadContext *tc, Mode mode)
Definition: tlb.hh:96
BaseCPU::threadContexts
std::vector< ThreadContext * > threadContexts
Definition: base.hh:252
CheckerCPU::setIcachePort
void setIcachePort(RequestPort *icache_port)
Definition: cpu.cc:116
CheckerCPU::changedPC
bool changedPC
Definition: cpu.hh:636
ThreadContext::contextId
virtual ContextID contextId() const =0
static_inst.hh
addrBlockOffset
Addr addrBlockOffset(Addr addr, Addr block_size)
Calculates the offset of a given address wrt aligned fixed-size blocks.
Definition: utils.hh:50
CheckerCPU::unverifiedReq
RequestPtr unverifiedReq
Definition: cpu.hh:633
RequestPort
A RequestPort is a specialisation of a Port, which implements the default protocol for the three diff...
Definition: port.hh:74
NoFault
constexpr decltype(nullptr) NoFault
Definition: types.hh:245
CheckerCPU::requestorId
RequestorID requestorId
id attached to all issued requests
Definition: cpu.hh:92
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
CheckerCPU::checkFlags
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:360
full_system.hh
BaseTLB::Write
@ Write
Definition: tlb.hh:57
BaseCPU
Definition: cpu_dummy.hh:43
CheckerCPU::systemPtr
System * systemPtr
Definition: cpu.hh:128
BaseCPU::Params
BaseCPUParams Params
Definition: base.hh:295
simple_thread.hh
base.hh
std
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:587
CheckerCPU::curMacroStaticInst
StaticInstPtr curMacroStaticInst
Definition: cpu.hh:143
BaseCPU::system
System * system
Definition: base.hh:371
Packet::dataStatic
void dataStatic(T *p)
Set the data pointer to the following value that should not be freed.
Definition: packet.hh:1107
Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:257
CheckerCPU::updateOnError
bool updateOnError
Definition: cpu.hh:640
addr
ip6_addr_t addr
Definition: inet.hh:423
CheckerCPU::setDcachePort
void setDcachePort(RequestPort *dcache_port)
Definition: cpu.cc:122
CheckerCPU::willChangePC
bool willChangePC
Definition: cpu.hh:637
CheckerCPU::icachePort
RequestPort * icachePort
Definition: cpu.hh:130
CheckerCPU::tc
ThreadContext * tc
Definition: cpu.hh:133
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
Request::STORE_NO_DATA
static const FlagsType STORE_NO_DATA
Definition: request.hh:233
CheckpointIn
Definition: serialize.hh:67
CheckerCPU::genMemFragmentRequest
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:138
thread_context.hh
CheckerCPU::unverifiedMemData
uint8_t * unverifiedMemData
Definition: cpu.hh:634
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
curTick
Tick curTick()
The current simulated tick.
Definition: core.hh:45
CheckerCPU::exitOnError
bool exitOnError
Definition: cpu.hh:639

Generated on Wed Sep 30 2020 14:01:58 for gem5 by doxygen 1.8.17