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