1/*
| 1/*
|
| 2 * Copyright (c) 2011 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 *
|
2 * Copyright (c) 2006 The Regents of The University of Michigan 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 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Kevin Lim
| 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 * Authors: Kevin Lim
|
| 41 * Geoffrey Blake
|
29 */ 30 31#include <list> 32#include <string> 33 34#include "cpu/checker/cpu.hh" 35#include "cpu/base.hh" 36#include "cpu/simple_thread.hh" 37#include "cpu/static_inst.hh" 38#include "cpu/thread_context.hh"
| 42 */ 43 44#include <list> 45#include <string> 46 47#include "cpu/checker/cpu.hh" 48#include "cpu/base.hh" 49#include "cpu/simple_thread.hh" 50#include "cpu/static_inst.hh" 51#include "cpu/thread_context.hh"
|
| 52#include "params/CheckerCPU.hh" 53#include "sim/tlb.hh"
|
39 40#if FULL_SYSTEM 41#include "arch/kernel_stats.hh" 42#include "arch/vtophys.hh" 43#endif // FULL_SYSTEM 44 45using namespace std;
| 54 55#if FULL_SYSTEM 56#include "arch/kernel_stats.hh" 57#include "arch/vtophys.hh" 58#endif // FULL_SYSTEM 59 60using namespace std;
|
46//The CheckerCPU does alpha only 47using namespace AlphaISA;
| 61using namespace TheISA;
|
48 49void 50CheckerCPU::init() 51{ 52} 53 54CheckerCPU::CheckerCPU(Params *p) 55 : BaseCPU(p), thread(NULL), tc(NULL) 56{ 57 memReq = NULL;
| 62 63void 64CheckerCPU::init() 65{ 66} 67 68CheckerCPU::CheckerCPU(Params *p) 69 : BaseCPU(p), thread(NULL), tc(NULL) 70{ 71 memReq = NULL;
|
| 72 curStaticInst = NULL; 73 curMacroStaticInst = NULL;
|
58 59 numInst = 0; 60 startNumInst = 0; 61 numLoad = 0; 62 startNumLoad = 0; 63 youngestSN = 0; 64 65 changedPC = willChangePC = changedNextPC = false; 66 67 exitOnError = p->exitOnError; 68 warnOnlyOnLoadError = p->warnOnlyOnLoadError;
| 74 75 numInst = 0; 76 startNumInst = 0; 77 numLoad = 0; 78 startNumLoad = 0; 79 youngestSN = 0; 80 81 changedPC = willChangePC = changedNextPC = false; 82 83 exitOnError = p->exitOnError; 84 warnOnlyOnLoadError = p->warnOnlyOnLoadError;
|
69#if FULL_SYSTEM
| |
70 itb = p->itb; 71 dtb = p->dtb;
| 85 itb = p->itb; 86 dtb = p->dtb;
|
| 87#if FULL_SYSTEM
|
72 systemPtr = NULL; 73#else
| 88 systemPtr = NULL; 89#else
|
74 process = p->process; 75 thread = new SimpleThread(this, /* thread_num */ 0, process);
| 90 workload = p->workload; 91 // XXX: This is a hack to get this to work some 92 thread = new SimpleThread(this, /* thread_num */ 0, workload[0], itb, dtb);
|
76 77 tc = thread->getTC(); 78 threadContexts.push_back(tc); 79#endif 80
| 93 94 tc = thread->getTC(); 95 threadContexts.push_back(tc); 96#endif 97
|
81 result.integer = 0;
| 98 updateOnError = true;
|
82} 83 84CheckerCPU::~CheckerCPU() 85{ 86} 87 88void 89CheckerCPU::setSystem(System *system) 90{ 91#if FULL_SYSTEM 92 systemPtr = system; 93 94 thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false); 95 96 tc = thread->getTC(); 97 threadContexts.push_back(tc); 98 delete thread->kernelStats; 99 thread->kernelStats = NULL; 100#endif 101} 102 103void 104CheckerCPU::setIcachePort(Port *icache_port) 105{ 106 icachePort = icache_port; 107} 108 109void 110CheckerCPU::setDcachePort(Port *dcache_port) 111{ 112 dcachePort = dcache_port; 113} 114 115void 116CheckerCPU::serialize(ostream &os) 117{
| 99} 100 101CheckerCPU::~CheckerCPU() 102{ 103} 104 105void 106CheckerCPU::setSystem(System *system) 107{ 108#if FULL_SYSTEM 109 systemPtr = system; 110 111 thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false); 112 113 tc = thread->getTC(); 114 threadContexts.push_back(tc); 115 delete thread->kernelStats; 116 thread->kernelStats = NULL; 117#endif 118} 119 120void 121CheckerCPU::setIcachePort(Port *icache_port) 122{ 123 icachePort = icache_port; 124} 125 126void 127CheckerCPU::setDcachePort(Port *dcache_port) 128{ 129 dcachePort = dcache_port; 130} 131 132void 133CheckerCPU::serialize(ostream &os) 134{
|
118/* 119 BaseCPU::serialize(os); 120 SERIALIZE_SCALAR(inst); 121 nameOut(os, csprintf("%s.xc", name())); 122 thread->serialize(os); 123 cacheCompletionEvent.serialize(os); 124*/
| |
125} 126 127void 128CheckerCPU::unserialize(Checkpoint *cp, const string §ion) 129{
| 135} 136 137void 138CheckerCPU::unserialize(Checkpoint *cp, const string §ion) 139{
|
130/* 131 BaseCPU::unserialize(cp, section); 132 UNSERIALIZE_SCALAR(inst); 133 thread->unserialize(cp, csprintf("%s.xc", section)); 134*/
| |
135} 136
| 140} 141
|
137template <class T>
| |
138Fault
| 142Fault
|
139CheckerCPU::read(Addr addr, T &data, unsigned flags)
| 143CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags)
|
140{
| 144{
|
141 // need to fill in CPU & thread IDs here 142 memReq = new Request();
| 145 Fault fault = NoFault; 146 unsigned blockSize = dcachePort->peerBlockSize(); 147 int fullSize = size; 148 Addr secondAddr = roundDown(addr + size - 1, blockSize); 149 bool checked_flags = false; 150 bool flags_match = true; 151 Addr pAddr = 0x0;
|
143
| 152
|
144 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
| |
145
| 153
|
146 // translate to physical address 147 dtb->translateAtomic(memReq, tc, false);
| 154 if (secondAddr > addr) 155 size = secondAddr - addr;
|
148
| 156
|
149 PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
| 157 // Need to account for multiple accesses like the Atomic and TimingSimple 158 while (1) { 159 memReq = new Request(); 160 memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr());
|
150
| 161
|
151 pkt->dataStatic(&data);
| 162 // translate to physical address 163 fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read);
|
152
| 164
|
153 if (!(memReq->isUncacheable())) { 154 // Access memory to see if we have the same data 155 dcachePort->sendFunctional(pkt); 156 } else { 157 // Assume the data is correct if it's an uncached access 158 memcpy(&data, &unverifiedResult.integer, sizeof(T)); 159 }
| 165 if (!checked_flags && fault == NoFault && unverifiedReq) { 166 flags_match = checkFlags(unverifiedReq, memReq->getVaddr(), 167 memReq->getPaddr(), memReq->getFlags()); 168 pAddr = memReq->getPaddr(); 169 checked_flags = true; 170 }
|
160
| 171
|
161 delete pkt;
| 172 // Now do the access 173 if (fault == NoFault && 174 !memReq->getFlags().isSet(Request::NO_ACCESS)) { 175 PacketPtr pkt = new Packet(memReq, 176 memReq->isLLSC() ? 177 MemCmd::LoadLockedReq : MemCmd::ReadReq, 178 Packet::Broadcast);
|
162
| 179
|
163 return NoFault; 164}
| 180 pkt->dataStatic(data);
|
165
| 181
|
166#ifndef DOXYGEN_SHOULD_SKIP_THIS
| 182 if (!(memReq->isUncacheable() || memReq->isMmappedIpr())) { 183 // Access memory to see if we have the same data 184 dcachePort->sendFunctional(pkt); 185 } else { 186 // Assume the data is correct if it's an uncached access 187 memcpy(data, unverifiedMemData, size); 188 }
|
167
| 189
|
168template 169Fault 170CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags);
| 190 delete memReq; 191 memReq = NULL; 192 delete pkt; 193 }
|
171
| 194
|
172template 173Fault 174CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags);
| 195 if (fault != NoFault) { 196 if (memReq->isPrefetch()) { 197 fault = NoFault; 198 } 199 delete memReq; 200 memReq = NULL; 201 break; 202 }
|
175
| 203
|
176template 177Fault 178CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags);
| 204 if (memReq != NULL) { 205 delete memReq; 206 }
|
179
| 207
|
180template 181Fault 182CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags);
| 208 //If we don't need to access a second cache line, stop now. 209 if (secondAddr <= addr) 210 { 211 break; 212 }
|
183
| 213
|
184#endif //DOXYGEN_SHOULD_SKIP_THIS
| 214 // Setup for accessing next cache line 215 data += size; 216 unverifiedMemData += size; 217 size = addr + fullSize - secondAddr; 218 addr = secondAddr; 219 }
|
185
| 220
|
186template<> 187Fault 188CheckerCPU::read(Addr addr, double &data, unsigned flags) 189{ 190 return read(addr, *(uint64_t*)&data, flags); 191}
| 221 if (!flags_match) { 222 warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n", 223 curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(), 224 unverifiedReq->getFlags(), addr, pAddr, flags); 225 handleError(); 226 }
|
192
| 227
|
193template<> 194Fault 195CheckerCPU::read(Addr addr, float &data, unsigned flags) 196{ 197 return read(addr, *(uint32_t*)&data, flags);
| 228 return fault;
|
198} 199
| 229} 230
|
200template<>
| |
201Fault
| 231Fault
|
202CheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
| 232CheckerCPU::writeMem(uint8_t *data, unsigned size, 233 Addr addr, unsigned flags, uint64_t *res)
|
203{
| 234{
|
204 return read(addr, (uint32_t&)data, flags); 205}
| 235 Fault fault = NoFault; 236 bool checked_flags = false; 237 bool flags_match = true; 238 Addr pAddr = 0x0;
|
206
| 239
|
207template <class T> 208Fault 209CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 210{ 211 // need to fill in CPU & thread IDs here 212 memReq = new Request();
| 240 unsigned blockSize = dcachePort->peerBlockSize(); 241 int fullSize = size;
|
213
| 242
|
214 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
| 243 Addr secondAddr = roundDown(addr + size - 1, blockSize);
|
215
| 244
|
216 // translate to physical address 217 dtb->translateAtomic(memReq, tc, true);
| 245 if (secondAddr > addr) 246 size = secondAddr - addr;
|
218
| 247
|
219 // Can compare the write data and result only if it's cacheable, 220 // not a store conditional, or is a store conditional that 221 // succeeded. 222 // @todo: Verify that actual memory matches up with these values. 223 // Right now it only verifies that the instruction data is the 224 // same as what was in the request that got sent to memory; there 225 // is no verification that it is the same as what is in memory. 226 // This is because the LSQ would have to be snooped in the CPU to 227 // verify this data. 228 if (unverifiedReq && 229 !(unverifiedReq->isUncacheable()) && 230 (!(unverifiedReq->isLLSC()) || 231 ((unverifiedReq->isLLSC()) && 232 unverifiedReq->getExtraData() == 1))) { 233 T inst_data; 234/* 235 // This code would work if the LSQ allowed for snooping. 236 PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); 237 pkt.dataStatic(&inst_data);
| 248 // Need to account for a multiple access like Atomic and Timing CPUs 249 while (1) { 250 memReq = new Request(); 251 memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr());
|
238
| 252
|
239 dcachePort->sendFunctional(pkt);
| 253 // translate to physical address 254 fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write);
|
240
| 255
|
241 delete pkt; 242*/ 243 memcpy(&inst_data, unverifiedMemData, sizeof(T)); 244 245 if (data != inst_data) { 246 warn("%lli: Store value does not match value in memory! " 247 "Instruction: %#x, memory: %#x", 248 curTick(), inst_data, data); 249 handleError();
| 256 if (!checked_flags && fault == NoFault && unverifiedReq) { 257 flags_match = checkFlags(unverifiedReq, memReq->getVaddr(), 258 memReq->getPaddr(), memReq->getFlags()); 259 pAddr = memReq->getPaddr(); 260 checked_flags = true;
|
250 }
| 261 }
|
251 }
| |
252
| 262
|
253 // Assume the result was the same as the one passed in. This checker 254 // doesn't check if the SC should succeed or fail, it just checks the 255 // value. 256 if (res && unverifiedReq->scResultValid()) 257 *res = unverifiedReq->getExtraData();
| 263 /* 264 * We don't actually check memory for the store because there 265 * is no guarantee it has left the lsq yet, and therefore we 266 * can't verify the memory on stores without lsq snooping 267 * enabled. This is left as future work for the Checker: LSQ snooping 268 * and memory validation after stores have committed. 269 */
|
258
| 270
|
259 return NoFault; 260}
| 271 delete memReq;
|
261
| 272
|
| 273 //If we don't need to access a second cache line, stop now. 274 if (fault != NoFault || secondAddr <= addr) 275 { 276 if (fault != NoFault && memReq->isPrefetch()) { 277 fault = NoFault; 278 } 279 break; 280 }
|
262
| 281
|
263#ifndef DOXYGEN_SHOULD_SKIP_THIS 264template 265Fault 266CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
| 282 //Update size and access address 283 size = addr + fullSize - secondAddr; 284 //And access the right address. 285 addr = secondAddr; 286 }
|
267
| 287
|
268template 269Fault 270CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
| 288 if (!flags_match) { 289 warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n", 290 curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(), 291 unverifiedReq->getFlags(), addr, pAddr, flags); 292 handleError(); 293 }
|
271
| 294
|
272template 273Fault 274CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
| 295 // Assume the result was the same as the one passed in. This checker 296 // doesn't check if the SC should succeed or fail, it just checks the 297 // value. 298 if (unverifiedReq && res && unverifiedReq->extraDataValid()) 299 *res = unverifiedReq->getExtraData();
|
275
| 300
|
276template 277Fault 278CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
| 301 // Entire purpose here is to make sure we are getting the 302 // same data to send to the mem system as the CPU did. 303 // Cannot check this is actually what went to memory because 304 // there stores can be in ld/st queue or coherent operations 305 // overwriting values. 306 bool extraData; 307 if (unverifiedReq) { 308 extraData = unverifiedReq->extraDataValid() ? 309 unverifiedReq->getExtraData() : 1; 310 }
|
279
| 311
|
280#endif //DOXYGEN_SHOULD_SKIP_THIS
| 312 if (unverifiedReq && unverifiedMemData && 313 memcmp(data, unverifiedMemData, fullSize) && extraData) { 314 warn("%lli: Store value does not match value sent to memory!\ 315 data: %#x inst_data: %#x", curTick(), data, 316 unverifiedMemData); 317 handleError(); 318 }
|
281
| 319
|
282template<> 283Fault 284CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 285{ 286 return write(*(uint64_t*)&data, addr, flags, res);
| 320 return fault;
|
287} 288
| 321} 322
|
289template<> 290Fault 291CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 292{ 293 return write(*(uint32_t*)&data, addr, flags, res); 294} 295 296template<> 297Fault 298CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 299{ 300 return write((uint32_t)data, addr, flags, res); 301} 302 303
| |
304#if FULL_SYSTEM 305Addr 306CheckerCPU::dbg_vtophys(Addr addr) 307{ 308 return vtophys(tc, addr); 309} 310#endif // FULL_SYSTEM 311
| 323#if FULL_SYSTEM 324Addr 325CheckerCPU::dbg_vtophys(Addr addr) 326{ 327 return vtophys(tc, addr); 328} 329#endif // FULL_SYSTEM 330
|
| 331/** 332 * Checks if the flags set by the Checker and Checkee match. 333 */
|
312bool
| 334bool
|
313CheckerCPU::checkFlags(Request *req)
| 335CheckerCPU::checkFlags(Request *unverified_req, Addr vAddr, 336 Addr pAddr, int flags)
|
314{
| 337{
|
315 // Remove any dynamic flags that don't have to do with the request itself. 316 unsigned flags = unverifiedReq->getFlags(); 317 unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | PREFETCH; 318 flags = flags & (mask); 319 if (flags == req->getFlags()) {
| 338 Addr unverifiedVAddr = unverified_req->getVaddr(); 339 Addr unverifiedPAddr = unverified_req->getPaddr(); 340 int unverifiedFlags = unverified_req->getFlags(); 341 342 if (unverifiedVAddr != vAddr || 343 unverifiedPAddr != pAddr || 344 unverifiedFlags != flags) {
|
320 return false;
| 345 return false;
|
321 } else { 322 return true;
| |
323 }
| 346 }
|
| 347 348 return true;
|
324} 325 326void 327CheckerCPU::dumpAndExit() 328{
| 349} 350 351void 352CheckerCPU::dumpAndExit() 353{
|
329 warn("%lli: Checker PC:%#x, next PC:%#x", 330 curTick(), thread->readPC(), thread->readNextPC());
| 354 warn("%lli: Checker PC:%s", 355 curTick(), thread->pcState());
|
331 panic("Checker found an error!"); 332}
| 356 panic("Checker found an error!"); 357}
|