cpu.cc revision 11429:cf5af0cc3be4
112853Sgabeblack@google.com/* 212853Sgabeblack@google.com * Copyright (c) 2011,2013 ARM Limited 312853Sgabeblack@google.com * All rights reserved 412853Sgabeblack@google.com * 512853Sgabeblack@google.com * The license below extends only to copyright in the software and shall 612853Sgabeblack@google.com * not be construed as granting a license to any other intellectual 712853Sgabeblack@google.com * property including but not limited to intellectual property relating 812853Sgabeblack@google.com * to a hardware implementation of the functionality of the software 912853Sgabeblack@google.com * licensed hereunder. You may use the software subject to the license 1012853Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated 1112853Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software, 1212853Sgabeblack@google.com * modified or unmodified, in source code or in binary form. 1312853Sgabeblack@google.com * 1412853Sgabeblack@google.com * Copyright (c) 2006 The Regents of The University of Michigan 1512853Sgabeblack@google.com * All rights reserved. 1612853Sgabeblack@google.com * 1712853Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 1812853Sgabeblack@google.com * modification, are permitted provided that the following conditions are 1912853Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 2012853Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 2112853Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 2212853Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 2312853Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 2412853Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 2512853Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 2612853Sgabeblack@google.com * this software without specific prior written permission. 2712853Sgabeblack@google.com * 2812853Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2912853Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3012853Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3112853Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3212853Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3312853Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3412853Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3512853Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3612853Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3712853Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3812853Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3912853Sgabeblack@google.com * 4012853Sgabeblack@google.com * Authors: Kevin Lim 4112853Sgabeblack@google.com * Geoffrey Blake 4212853Sgabeblack@google.com */ 4312853Sgabeblack@google.com 4412853Sgabeblack@google.com#include <list> 4512853Sgabeblack@google.com#include <string> 4612853Sgabeblack@google.com 4712853Sgabeblack@google.com#include "arch/generic/tlb.hh" 4812853Sgabeblack@google.com#include "arch/kernel_stats.hh" 4912853Sgabeblack@google.com#include "arch/vtophys.hh" 5012853Sgabeblack@google.com#include "cpu/checker/cpu.hh" 5112853Sgabeblack@google.com#include "cpu/base.hh" 5212853Sgabeblack@google.com#include "cpu/simple_thread.hh" 5312853Sgabeblack@google.com#include "cpu/static_inst.hh" 5412853Sgabeblack@google.com#include "cpu/thread_context.hh" 5512853Sgabeblack@google.com#include "params/CheckerCPU.hh" 5612853Sgabeblack@google.com#include "sim/full_system.hh" 5712853Sgabeblack@google.com 5812853Sgabeblack@google.comusing namespace std; 5912853Sgabeblack@google.comusing namespace TheISA; 6012853Sgabeblack@google.com 6112853Sgabeblack@google.comvoid 6212853Sgabeblack@google.comCheckerCPU::init() 6312853Sgabeblack@google.com{ 6412853Sgabeblack@google.com masterId = systemPtr->getMasterId(name()); 6512853Sgabeblack@google.com} 6612853Sgabeblack@google.com 6712853Sgabeblack@google.comCheckerCPU::CheckerCPU(Params *p) 6812853Sgabeblack@google.com : BaseCPU(p, true), systemPtr(NULL), icachePort(NULL), dcachePort(NULL), 6912853Sgabeblack@google.com tc(NULL), thread(NULL) 7012853Sgabeblack@google.com{ 7112853Sgabeblack@google.com memReq = NULL; 7212853Sgabeblack@google.com curStaticInst = NULL; 7312853Sgabeblack@google.com curMacroStaticInst = NULL; 7412853Sgabeblack@google.com 7512853Sgabeblack@google.com numInst = 0; 7612853Sgabeblack@google.com startNumInst = 0; 7712853Sgabeblack@google.com numLoad = 0; 7812853Sgabeblack@google.com startNumLoad = 0; 7912853Sgabeblack@google.com youngestSN = 0; 8012853Sgabeblack@google.com 8112853Sgabeblack@google.com changedPC = willChangePC = false; 8212853Sgabeblack@google.com 8312853Sgabeblack@google.com exitOnError = p->exitOnError; 8412853Sgabeblack@google.com warnOnlyOnLoadError = p->warnOnlyOnLoadError; 8512853Sgabeblack@google.com itb = p->itb; 8612853Sgabeblack@google.com dtb = p->dtb; 8712853Sgabeblack@google.com workload = p->workload; 8812853Sgabeblack@google.com 8912853Sgabeblack@google.com updateOnError = true; 9012853Sgabeblack@google.com} 9112853Sgabeblack@google.com 9212853Sgabeblack@google.comCheckerCPU::~CheckerCPU() 9312853Sgabeblack@google.com{ 9412853Sgabeblack@google.com} 9512853Sgabeblack@google.com 9612853Sgabeblack@google.comvoid 9712853Sgabeblack@google.comCheckerCPU::setSystem(System *system) 9812853Sgabeblack@google.com{ 9912853Sgabeblack@google.com const Params *p(dynamic_cast<const Params *>(_params)); 10012853Sgabeblack@google.com 10112853Sgabeblack@google.com systemPtr = system; 10212853Sgabeblack@google.com 10312853Sgabeblack@google.com if (FullSystem) { 10412853Sgabeblack@google.com thread = new SimpleThread(this, 0, systemPtr, itb, dtb, 10512853Sgabeblack@google.com p->isa[0], false); 10612853Sgabeblack@google.com } else { 10712853Sgabeblack@google.com thread = new SimpleThread(this, 0, systemPtr, 10812853Sgabeblack@google.com workload.size() ? workload[0] : NULL, 10912853Sgabeblack@google.com itb, dtb, p->isa[0]); 11012853Sgabeblack@google.com } 11112853Sgabeblack@google.com 11212853Sgabeblack@google.com tc = thread->getTC(); 11312853Sgabeblack@google.com threadContexts.push_back(tc); 11412853Sgabeblack@google.com thread->kernelStats = NULL; 11512853Sgabeblack@google.com // Thread should never be null after this 11612853Sgabeblack@google.com assert(thread != NULL); 11712853Sgabeblack@google.com} 11812853Sgabeblack@google.com 11912853Sgabeblack@google.comvoid 12012853Sgabeblack@google.comCheckerCPU::setIcachePort(MasterPort *icache_port) 12112853Sgabeblack@google.com{ 12212853Sgabeblack@google.com icachePort = icache_port; 12312853Sgabeblack@google.com} 12412853Sgabeblack@google.com 12512853Sgabeblack@google.comvoid 12612853Sgabeblack@google.comCheckerCPU::setDcachePort(MasterPort *dcache_port) 12712853Sgabeblack@google.com{ 12812853Sgabeblack@google.com dcachePort = dcache_port; 12912853Sgabeblack@google.com} 13012853Sgabeblack@google.com 13112853Sgabeblack@google.comvoid 13212853Sgabeblack@google.comCheckerCPU::serialize(ostream &os) const 13312853Sgabeblack@google.com{ 13412853Sgabeblack@google.com} 13512853Sgabeblack@google.com 13612853Sgabeblack@google.comvoid 13712853Sgabeblack@google.comCheckerCPU::unserialize(CheckpointIn &cp) 13812853Sgabeblack@google.com{ 13912853Sgabeblack@google.com} 14012853Sgabeblack@google.com 14112853Sgabeblack@google.comFault 14212853Sgabeblack@google.comCheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags) 14312853Sgabeblack@google.com{ 14412853Sgabeblack@google.com Fault fault = NoFault; 14512853Sgabeblack@google.com int fullSize = size; 14612853Sgabeblack@google.com Addr secondAddr = roundDown(addr + size - 1, cacheLineSize()); 14712853Sgabeblack@google.com bool checked_flags = false; 14812853Sgabeblack@google.com bool flags_match = true; 14912853Sgabeblack@google.com Addr pAddr = 0x0; 15012853Sgabeblack@google.com 15112853Sgabeblack@google.com 15212853Sgabeblack@google.com if (secondAddr > addr) 15312853Sgabeblack@google.com size = secondAddr - addr; 15412853Sgabeblack@google.com 15512853Sgabeblack@google.com // Need to account for multiple accesses like the Atomic and TimingSimple 15612853Sgabeblack@google.com while (1) { 15712853Sgabeblack@google.com memReq = new Request(0, addr, size, flags, masterId, 15812853Sgabeblack@google.com thread->pcState().instAddr(), tc->contextId(), 0); 15912853Sgabeblack@google.com 16012853Sgabeblack@google.com // translate to physical address 16112853Sgabeblack@google.com fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read); 16212853Sgabeblack@google.com 16312853Sgabeblack@google.com if (!checked_flags && fault == NoFault && unverifiedReq) { 16412853Sgabeblack@google.com flags_match = checkFlags(unverifiedReq, memReq->getVaddr(), 16512853Sgabeblack@google.com memReq->getPaddr(), memReq->getFlags()); 16612853Sgabeblack@google.com pAddr = memReq->getPaddr(); 16712853Sgabeblack@google.com checked_flags = true; 16812853Sgabeblack@google.com } 16912853Sgabeblack@google.com 17012853Sgabeblack@google.com // Now do the access 17112853Sgabeblack@google.com if (fault == NoFault && 17212853Sgabeblack@google.com !memReq->getFlags().isSet(Request::NO_ACCESS)) { 17312853Sgabeblack@google.com PacketPtr pkt = Packet::createRead(memReq); 17412853Sgabeblack@google.com 17512853Sgabeblack@google.com pkt->dataStatic(data); 17612853Sgabeblack@google.com 17712853Sgabeblack@google.com if (!(memReq->isUncacheable() || memReq->isMmappedIpr())) { 17812853Sgabeblack@google.com // Access memory to see if we have the same data 17912853Sgabeblack@google.com dcachePort->sendFunctional(pkt); 18012853Sgabeblack@google.com } else { 18112853Sgabeblack@google.com // Assume the data is correct if it's an uncached access 18212853Sgabeblack@google.com memcpy(data, unverifiedMemData, size); 18312853Sgabeblack@google.com } 18412853Sgabeblack@google.com 18512853Sgabeblack@google.com delete memReq; 18612853Sgabeblack@google.com memReq = NULL; 18712853Sgabeblack@google.com delete pkt; 18812853Sgabeblack@google.com } 18912853Sgabeblack@google.com 19012853Sgabeblack@google.com if (fault != NoFault) { 19112853Sgabeblack@google.com if (memReq->isPrefetch()) { 19212853Sgabeblack@google.com fault = NoFault; 19312853Sgabeblack@google.com } 19412853Sgabeblack@google.com delete memReq; 19512853Sgabeblack@google.com memReq = NULL; 19612853Sgabeblack@google.com break; 19712853Sgabeblack@google.com } 19812853Sgabeblack@google.com 19912853Sgabeblack@google.com if (memReq != NULL) { 20012853Sgabeblack@google.com delete memReq; 20112853Sgabeblack@google.com } 20212853Sgabeblack@google.com 20312853Sgabeblack@google.com //If we don't need to access a second cache line, stop now. 20412853Sgabeblack@google.com if (secondAddr <= addr) 20512853Sgabeblack@google.com { 20612853Sgabeblack@google.com break; 20712853Sgabeblack@google.com } 20812853Sgabeblack@google.com 20912853Sgabeblack@google.com // Setup for accessing next cache line 21012853Sgabeblack@google.com data += size; 21112853Sgabeblack@google.com unverifiedMemData += size; 21212853Sgabeblack@google.com size = addr + fullSize - secondAddr; 21312853Sgabeblack@google.com addr = secondAddr; 21412853Sgabeblack@google.com } 21512853Sgabeblack@google.com 21612853Sgabeblack@google.com if (!flags_match) { 21712853Sgabeblack@google.com warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n", 21812853Sgabeblack@google.com curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(), 21912853Sgabeblack@google.com unverifiedReq->getFlags(), addr, pAddr, flags); 22012853Sgabeblack@google.com handleError(); 22112853Sgabeblack@google.com } 22212853Sgabeblack@google.com 22312853Sgabeblack@google.com return fault; 22412853Sgabeblack@google.com} 22512853Sgabeblack@google.com 22612853Sgabeblack@google.comFault 22712853Sgabeblack@google.comCheckerCPU::writeMem(uint8_t *data, unsigned size, 22812853Sgabeblack@google.com Addr addr, unsigned flags, uint64_t *res) 22912853Sgabeblack@google.com{ 23012853Sgabeblack@google.com Fault fault = NoFault; 23112853Sgabeblack@google.com bool checked_flags = false; 23212853Sgabeblack@google.com bool flags_match = true; 23312853Sgabeblack@google.com Addr pAddr = 0x0; 23412853Sgabeblack@google.com static uint8_t zero_data[64] = {}; 23512853Sgabeblack@google.com 23612853Sgabeblack@google.com int fullSize = size; 23712853Sgabeblack@google.com 23812853Sgabeblack@google.com Addr secondAddr = roundDown(addr + size - 1, cacheLineSize()); 23912853Sgabeblack@google.com 24012853Sgabeblack@google.com if (secondAddr > addr) 24112853Sgabeblack@google.com size = secondAddr - addr; 24212853Sgabeblack@google.com 24312853Sgabeblack@google.com // Need to account for a multiple access like Atomic and Timing CPUs 24412853Sgabeblack@google.com while (1) { 24512853Sgabeblack@google.com memReq = new Request(0, addr, size, flags, masterId, 24612853Sgabeblack@google.com thread->pcState().instAddr(), tc->contextId(), 0); 24712853Sgabeblack@google.com 24812853Sgabeblack@google.com // translate to physical address 24912853Sgabeblack@google.com fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write); 25012853Sgabeblack@google.com 25112853Sgabeblack@google.com if (!checked_flags && fault == NoFault && unverifiedReq) { 25212853Sgabeblack@google.com flags_match = checkFlags(unverifiedReq, memReq->getVaddr(), 25312853Sgabeblack@google.com memReq->getPaddr(), memReq->getFlags()); 25412853Sgabeblack@google.com pAddr = memReq->getPaddr(); 25512853Sgabeblack@google.com checked_flags = true; 25612853Sgabeblack@google.com } 25712853Sgabeblack@google.com 25812853Sgabeblack@google.com /* 25912853Sgabeblack@google.com * We don't actually check memory for the store because there 26012853Sgabeblack@google.com * is no guarantee it has left the lsq yet, and therefore we 26112853Sgabeblack@google.com * can't verify the memory on stores without lsq snooping 26212853Sgabeblack@google.com * enabled. This is left as future work for the Checker: LSQ snooping 26312853Sgabeblack@google.com * and memory validation after stores have committed. 26412853Sgabeblack@google.com */ 26512853Sgabeblack@google.com bool was_prefetch = memReq->isPrefetch(); 26612853Sgabeblack@google.com 26712853Sgabeblack@google.com delete memReq; 26812853Sgabeblack@google.com 26912853Sgabeblack@google.com //If we don't need to access a second cache line, stop now. 27012853Sgabeblack@google.com if (fault != NoFault || secondAddr <= addr) 27112853Sgabeblack@google.com { 27212853Sgabeblack@google.com if (fault != NoFault && was_prefetch) { 27312853Sgabeblack@google.com fault = NoFault; 27412853Sgabeblack@google.com } 27512853Sgabeblack@google.com break; 27612853Sgabeblack@google.com } 27712853Sgabeblack@google.com 27812853Sgabeblack@google.com //Update size and access address 27912853Sgabeblack@google.com size = addr + fullSize - secondAddr; 28012853Sgabeblack@google.com //And access the right address. 28112853Sgabeblack@google.com addr = secondAddr; 28212853Sgabeblack@google.com } 28312853Sgabeblack@google.com 28412853Sgabeblack@google.com if (!flags_match) { 28512853Sgabeblack@google.com warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n", 28612853Sgabeblack@google.com curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(), 28712853Sgabeblack@google.com unverifiedReq->getFlags(), addr, pAddr, flags); 28812853Sgabeblack@google.com handleError(); 28912853Sgabeblack@google.com } 29012853Sgabeblack@google.com 29112853Sgabeblack@google.com // Assume the result was the same as the one passed in. This checker 29212853Sgabeblack@google.com // doesn't check if the SC should succeed or fail, it just checks the 29312853Sgabeblack@google.com // value. 29412853Sgabeblack@google.com if (unverifiedReq && res && unverifiedReq->extraDataValid()) 29512853Sgabeblack@google.com *res = unverifiedReq->getExtraData(); 29612853Sgabeblack@google.com 29712853Sgabeblack@google.com // Entire purpose here is to make sure we are getting the 29812853Sgabeblack@google.com // same data to send to the mem system as the CPU did. 29912853Sgabeblack@google.com // Cannot check this is actually what went to memory because 30012853Sgabeblack@google.com // there stores can be in ld/st queue or coherent operations 30112853Sgabeblack@google.com // overwriting values. 30212853Sgabeblack@google.com bool extraData = false; 30312853Sgabeblack@google.com if (unverifiedReq) { 30412853Sgabeblack@google.com extraData = unverifiedReq->extraDataValid() ? 30512853Sgabeblack@google.com unverifiedReq->getExtraData() : true; 30612853Sgabeblack@google.com } 30712853Sgabeblack@google.com 30812853Sgabeblack@google.com // If the request is to ZERO a cache block, there is no data to check 30912853Sgabeblack@google.com // against, but it's all zero. We need something to compare to, so use a 31012853Sgabeblack@google.com // const set of zeros. 31112853Sgabeblack@google.com if (flags & Request::CACHE_BLOCK_ZERO) { 31212853Sgabeblack@google.com assert(!data); 31312853Sgabeblack@google.com assert(sizeof(zero_data) <= fullSize); 31412853Sgabeblack@google.com data = zero_data; 31512853Sgabeblack@google.com } 31612853Sgabeblack@google.com 31712853Sgabeblack@google.com if (unverifiedReq && unverifiedMemData && 31812853Sgabeblack@google.com memcmp(data, unverifiedMemData, fullSize) && extraData) { 31912853Sgabeblack@google.com warn("%lli: Store value does not match value sent to memory! " 32012853Sgabeblack@google.com "data: %#x inst_data: %#x", curTick(), data, 32112853Sgabeblack@google.com unverifiedMemData); 32212853Sgabeblack@google.com handleError(); 32312853Sgabeblack@google.com } 32412853Sgabeblack@google.com 32512853Sgabeblack@google.com return fault; 32612853Sgabeblack@google.com} 32712853Sgabeblack@google.com 32812853Sgabeblack@google.comAddr 32912853Sgabeblack@google.comCheckerCPU::dbg_vtophys(Addr addr) 33012853Sgabeblack@google.com{ 33112853Sgabeblack@google.com return vtophys(tc, addr); 33212853Sgabeblack@google.com} 33312853Sgabeblack@google.com 33412853Sgabeblack@google.com/** 33512853Sgabeblack@google.com * Checks if the flags set by the Checker and Checkee match. 33612853Sgabeblack@google.com */ 33712853Sgabeblack@google.combool 33812853Sgabeblack@google.comCheckerCPU::checkFlags(Request *unverified_req, Addr vAddr, 33912853Sgabeblack@google.com Addr pAddr, int flags) 34012853Sgabeblack@google.com{ 34112853Sgabeblack@google.com Addr unverifiedVAddr = unverified_req->getVaddr(); 34212853Sgabeblack@google.com Addr unverifiedPAddr = unverified_req->getPaddr(); 34312853Sgabeblack@google.com int unverifiedFlags = unverified_req->getFlags(); 34412853Sgabeblack@google.com 34512853Sgabeblack@google.com if (unverifiedVAddr != vAddr || 34612853Sgabeblack@google.com unverifiedPAddr != pAddr || 34712853Sgabeblack@google.com unverifiedFlags != flags) { 34812853Sgabeblack@google.com return false; 34912853Sgabeblack@google.com } 35012853Sgabeblack@google.com 35112853Sgabeblack@google.com return true; 35212853Sgabeblack@google.com} 35312853Sgabeblack@google.com 35412853Sgabeblack@google.comvoid 35512853Sgabeblack@google.comCheckerCPU::dumpAndExit() 35612853Sgabeblack@google.com{ 35712853Sgabeblack@google.com warn("%lli: Checker PC:%s", 35812853Sgabeblack@google.com curTick(), thread->pcState()); 35912853Sgabeblack@google.com panic("Checker found an error!"); 36012853Sgabeblack@google.com} 36112853Sgabeblack@google.com