mem_checker_monitor.cc revision 10612
12292SN/A/* 22292SN/A * Copyright (c) 2012-2014 ARM Limited 32292SN/A * All rights reserved 42292SN/A * 52292SN/A * The license below extends only to copyright in the software and shall 62292SN/A * not be construed as granting a license to any other intellectual 72292SN/A * property including but not limited to intellectual property relating 82292SN/A * to a hardware implementation of the functionality of the software 92292SN/A * licensed hereunder. You may use the software subject to the license 102292SN/A * terms below provided that you ensure that this notice is replicated 112292SN/A * unmodified and in its entirety in all distributions of the software, 122292SN/A * modified or unmodified, in source code or in binary form. 132292SN/A * 142292SN/A * Redistribution and use in source and binary forms, with or without 152292SN/A * modification, are permitted provided that the following conditions are 162292SN/A * met: redistributions of source code must retain the above copyright 172292SN/A * notice, this list of conditions and the following disclaimer; 182292SN/A * redistributions in binary form must reproduce the above copyright 192292SN/A * notice, this list of conditions and the following disclaimer in the 202292SN/A * documentation and/or other materials provided with the distribution; 212292SN/A * neither the name of the copyright holders nor the names of its 222292SN/A * contributors may be used to endorse or promote products derived from 232292SN/A * this software without specific prior written permission. 242292SN/A * 252292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272689Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282689Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292689Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322733Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332733Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342907Sktlim@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 362292SN/A * 372722Sktlim@umich.edu * Authors: Thomas Grass 382669Sktlim@umich.edu * Andreas Hansson 392292SN/A * Marco Elver 402790Sktlim@umich.edu */ 412790Sktlim@umich.edu 422790Sktlim@umich.edu#include <memory> 432790Sktlim@umich.edu 442669Sktlim@umich.edu#include "base/output.hh" 452678Sktlim@umich.edu#include "base/trace.hh" 462678Sktlim@umich.edu#include "debug/MemCheckerMonitor.hh" 472678Sktlim@umich.edu#include "mem/mem_checker_monitor.hh" 482292SN/A 492678Sktlim@umich.eduusing namespace std; 502292SN/A 512292SN/AMemCheckerMonitor::MemCheckerMonitor(Params* params) 522669Sktlim@umich.edu : MemObject(params), 532292SN/A masterPort(name() + "-master", *this), 542678Sktlim@umich.edu slavePort(name() + "-slave", *this), 552292SN/A warnOnly(params->warn_only), 562678Sktlim@umich.edu memchecker(params->memchecker) 572678Sktlim@umich.edu{} 582678Sktlim@umich.edu 592678Sktlim@umich.eduMemCheckerMonitor::~MemCheckerMonitor() 602678Sktlim@umich.edu{} 612292SN/A 622678Sktlim@umich.eduMemCheckerMonitor* 632678Sktlim@umich.eduMemCheckerMonitorParams::create() 642678Sktlim@umich.edu{ 652678Sktlim@umich.edu return new MemCheckerMonitor(this); 662678Sktlim@umich.edu} 672678Sktlim@umich.edu 682292SN/Avoid 692678Sktlim@umich.eduMemCheckerMonitor::init() 702678Sktlim@umich.edu{ 712678Sktlim@umich.edu // make sure both sides of the monitor are connected 722678Sktlim@umich.edu if (!slavePort.isConnected() || !masterPort.isConnected()) 732678Sktlim@umich.edu fatal("Communication monitor is not connected on both sides.\n"); 742678Sktlim@umich.edu} 752678Sktlim@umich.edu 762698Sktlim@umich.eduBaseMasterPort& 772344SN/AMemCheckerMonitor::getMasterPort(const std::string& if_name, PortID idx) 782678Sktlim@umich.edu{ 792678Sktlim@umich.edu if (if_name == "master" || if_name == "mem_side") { 802678Sktlim@umich.edu return masterPort; 812820Sktlim@umich.edu } else { 822678Sktlim@umich.edu return MemObject::getMasterPort(if_name, idx); 832678Sktlim@umich.edu } 842307SN/A} 852678Sktlim@umich.edu 862678Sktlim@umich.eduBaseSlavePort& 872678Sktlim@umich.eduMemCheckerMonitor::getSlavePort(const std::string& if_name, PortID idx) 882678Sktlim@umich.edu{ 892678Sktlim@umich.edu if (if_name == "slave" || if_name == "cpu_side") { 902678Sktlim@umich.edu return slavePort; 912678Sktlim@umich.edu } else { 922678Sktlim@umich.edu return MemObject::getSlavePort(if_name, idx); 932344SN/A } 942307SN/A} 952678Sktlim@umich.edu 962678Sktlim@umich.eduvoid 972292SN/AMemCheckerMonitor::recvFunctional(PacketPtr pkt) 982292SN/A{ 992292SN/A Addr addr = pkt->getAddr(); 1002292SN/A unsigned size = pkt->getSize(); 1012678Sktlim@umich.edu 1022678Sktlim@umich.edu // Conservatively reset this address-range. Alternatively we could try to 1032292SN/A // update the values seen by the memchecker, however, there may be other 1042292SN/A // reads/writes to these location from other devices we do not see. 1052292SN/A memchecker->reset(addr, size); 1062292SN/A 1072292SN/A masterPort.sendFunctional(pkt); 1082292SN/A 1092907Sktlim@umich.edu DPRINTF(MemCheckerMonitor, 1102292SN/A "Forwarded functional access: addr = %#llx, size = %d\n", 1112292SN/A addr, size); 1122292SN/A} 1132292SN/A 1142307SN/Avoid 1152307SN/AMemCheckerMonitor::recvFunctionalSnoop(PacketPtr pkt) 1162907Sktlim@umich.edu{ 1172907Sktlim@umich.edu Addr addr = pkt->getAddr(); 1182292SN/A unsigned size = pkt->getSize(); 1192292SN/A 1202329SN/A // See above. 1212329SN/A memchecker->reset(addr, size); 1222329SN/A 1232292SN/A slavePort.sendFunctionalSnoop(pkt); 1242292SN/A 1252292SN/A DPRINTF(MemCheckerMonitor, 1262292SN/A "Received functional snoop: addr = %#llx, size = %d\n", 1272292SN/A addr, size); 1282292SN/A} 1292292SN/A 1302292SN/ATick 1312292SN/AMemCheckerMonitor::recvAtomic(PacketPtr pkt) 1322292SN/A{ 1332292SN/A assert(false && "Atomic not supported"); 1342329SN/A return masterPort.sendAtomic(pkt); 1352292SN/A} 1362292SN/A 1372292SN/ATick 1382292SN/AMemCheckerMonitor::recvAtomicSnoop(PacketPtr pkt) 1392292SN/A{ 1402669Sktlim@umich.edu assert(false && "Atomic not supported"); 1412733Sktlim@umich.edu return slavePort.sendAtomicSnoop(pkt); 1422669Sktlim@umich.edu} 1432669Sktlim@umich.edu 1442678Sktlim@umich.edubool 1452733Sktlim@umich.eduMemCheckerMonitor::recvTimingReq(PacketPtr pkt) 1462679Sktlim@umich.edu{ 1472679Sktlim@umich.edu // should always see a request 1482679Sktlim@umich.edu assert(pkt->isRequest()); 1492733Sktlim@umich.edu 1502669Sktlim@umich.edu // Store relevant fields of packet, because packet may be modified 1512669Sktlim@umich.edu // or even deleted when sendTiming() is called. 1522669Sktlim@umich.edu // 1532292SN/A // For reads we are only interested in real reads, and not prefetches, as 1542292SN/A // it is not guaranteed that the prefetch returns any useful data. 1552292SN/A bool is_read = pkt->isRead() && !pkt->req->isPrefetch(); 1562292SN/A bool is_write = pkt->isWrite(); 1572292SN/A unsigned size = pkt->getSize(); 1582292SN/A Addr addr = pkt->getAddr(); 1592292SN/A bool expects_response = pkt->needsResponse() && !pkt->memInhibitAsserted(); 1602292SN/A std::unique_ptr<uint8_t> pkt_data; 1612292SN/A MemCheckerMonitorSenderState* state = NULL; 1622292SN/A 1632292SN/A if (expects_response && is_write) { 1642292SN/A // On receipt of a request, only need to allocate pkt_data if this is a 1652727Sktlim@umich.edu // write. For reads, we have no data yet, so it doesn't make sense to 1662727Sktlim@umich.edu // allocate. 1672727Sktlim@umich.edu pkt_data.reset(new uint8_t[size]); 1682727Sktlim@umich.edu memcpy(pkt_data.get(), pkt->getConstPtr<uint8_t*>(), size); 1692727Sktlim@umich.edu } 1702727Sktlim@umich.edu 1712727Sktlim@umich.edu // If a cache miss is served by a cache, a monitor near the memory 1722727Sktlim@umich.edu // would see a request which needs a response, but this response 1732727Sktlim@umich.edu // would be inhibited and not come back from the memory. Therefore 1742727Sktlim@umich.edu // we additionally have to check the inhibit flag. 1752727Sktlim@umich.edu if (expects_response && (is_read || is_write)) { 1762727Sktlim@umich.edu state = new MemCheckerMonitorSenderState(0); 1772727Sktlim@umich.edu pkt->pushSenderState(state); 1782727Sktlim@umich.edu } 1792727Sktlim@umich.edu 1802727Sktlim@umich.edu // Attempt to send the packet (always succeeds for inhibited 1812727Sktlim@umich.edu // packets) 1822727Sktlim@umich.edu bool successful = masterPort.sendTimingReq(pkt); 1832361SN/A 1842361SN/A // If not successful, restore the sender state 1852361SN/A if (!successful && expects_response && (is_read || is_write)) { 1862361SN/A delete pkt->popSenderState(); 1872727Sktlim@umich.edu } 1882727Sktlim@umich.edu 1892727Sktlim@umich.edu if (successful && expects_response) { 1902727Sktlim@umich.edu if (is_read) { 1912727Sktlim@umich.edu MemChecker::Serial serial = memchecker->startRead(curTick(), 1922727Sktlim@umich.edu addr, 1932727Sktlim@umich.edu size); 1942727Sktlim@umich.edu 1952727Sktlim@umich.edu // At the time where we push the sender-state, we do not yet know 1962727Sktlim@umich.edu // the serial the MemChecker class will assign to this request. We 1972727Sktlim@umich.edu // cannot call startRead at the time we push the sender-state, as 1982727Sktlim@umich.edu // the masterPort may not be successful in executing sendTimingReq, 1992727Sktlim@umich.edu // and in case of a failure, we must not modify the state of the 2002727Sktlim@umich.edu // MemChecker. 2012727Sktlim@umich.edu // 2022727Sktlim@umich.edu // Once we know that sendTimingReq was successful, we can set the 2032727Sktlim@umich.edu // serial of the newly constructed sender-state. This is legal, as 2042727Sktlim@umich.edu // we know that nobody else will touch nor is responsible for 2052727Sktlim@umich.edu // deletion of our sender-state. 2062727Sktlim@umich.edu state->serial = serial; 2072727Sktlim@umich.edu 2082727Sktlim@umich.edu DPRINTF(MemCheckerMonitor, 2092727Sktlim@umich.edu "Forwarded read request: serial = %d, addr = %#llx, " 2102292SN/A "size = %d\n", 2112292SN/A serial, addr, size); 2122292SN/A } else if (is_write) { 2132292SN/A MemChecker::Serial serial = memchecker->startWrite(curTick(), 2142292SN/A addr, 2152292SN/A size, 2162292SN/A pkt_data.get()); 2172292SN/A 2182292SN/A state->serial = serial; 2192292SN/A 2202292SN/A DPRINTF(MemCheckerMonitor, 2212292SN/A "Forwarded write request: serial = %d, addr = %#llx, " 2222292SN/A "size = %d\n", 2232292SN/A serial, addr, size); 2242307SN/A } else { 2252307SN/A DPRINTF(MemCheckerMonitor, 2262307SN/A "Forwarded non read/write request: addr = %#llx\n", addr); 2272367SN/A } 2282367SN/A } else if (successful) { 2292307SN/A DPRINTF(MemCheckerMonitor, 2302367SN/A "Forwarded inhibited request: addr = %#llx\n", addr); 2312307SN/A } 2322329SN/A 2332307SN/A return successful; 2342307SN/A} 2352307SN/A 2362307SN/Abool 2372307SN/AMemCheckerMonitor::recvTimingResp(PacketPtr pkt) 2382307SN/A{ 2392307SN/A // should always see responses 2402307SN/A assert(pkt->isResponse()); 2412307SN/A 2422307SN/A // Store relevant fields of packet, because packet may be modified 2432307SN/A // or even deleted when sendTiming() is called. 2442307SN/A bool is_read = pkt->isRead() && !pkt->req->isPrefetch(); 2452307SN/A bool is_write = pkt->isWrite(); 2462307SN/A bool is_failed_LLSC = pkt->isLLSC() && pkt->req->getExtraData() == 0; 2472307SN/A unsigned size = pkt->getSize(); 2482329SN/A Addr addr = pkt->getAddr(); 2492307SN/A std::unique_ptr<uint8_t> pkt_data; 2502307SN/A MemCheckerMonitorSenderState* received_state = NULL; 2512307SN/A 2522307SN/A if (is_read) { 2532307SN/A // On receipt of a response, only need to allocate pkt_data if this is 2542307SN/A // a read. For writes, we have already given the MemChecker the data on 2552307SN/A // the request, so it doesn't make sense to allocate on write. 2562307SN/A pkt_data.reset(new uint8_t[size]); 2572307SN/A memcpy(pkt_data.get(), pkt->getConstPtr<uint8_t*>(), size); 2582307SN/A } 2592292SN/A 2602292SN/A if (is_read || is_write) { 2612329SN/A received_state = 2622329SN/A dynamic_cast<MemCheckerMonitorSenderState*>(pkt->senderState); 2632292SN/A 2642329SN/A // Restore initial sender state 2652329SN/A panic_if(received_state == NULL, 2662292SN/A "Monitor got a response without monitor sender state\n"); 2672292SN/A 2682292SN/A // Restore the state 2692292SN/A pkt->senderState = received_state->predecessor; 2702292SN/A } 2712329SN/A 2722292SN/A // Attempt to send the packet 2732292SN/A bool successful = slavePort.sendTimingResp(pkt); 2742292SN/A 2752292SN/A // If packet successfully send, complete transaction in MemChecker 2762292SN/A // instance, and delete sender state, otherwise restore state. 2772292SN/A if (successful) { 2782292SN/A if (is_read) { 2792292SN/A DPRINTF(MemCheckerMonitor, 2802329SN/A "Received read response: serial = %d, addr = %#llx, " 2812329SN/A "size = %d\n", 2822329SN/A received_state->serial, addr, size); 2832292SN/A 2842292SN/A bool result = memchecker->completeRead(received_state->serial, 2852292SN/A curTick(), 2862292SN/A addr, 2872292SN/A size, 2882329SN/A pkt_data.get()); 2892292SN/A 2902292SN/A if (!result) { 2912292SN/A warn("%s: read of %#llx @ cycle %d failed:\n%s\n", 2922292SN/A name(), 2932292SN/A addr, curTick(), 2942292SN/A memchecker->getErrorMessage().c_str()); 2952292SN/A 2962292SN/A panic_if(!warnOnly, "MemChecker violation!"); 2972292SN/A } 2982292SN/A 2992292SN/A delete received_state; 3002292SN/A } else if (is_write) { 3012292SN/A DPRINTF(MemCheckerMonitor, 3022292SN/A "Received write response: serial = %d, addr = %#llx, " 3032292SN/A "size = %d\n", 3042292SN/A received_state->serial, addr, size); 3052292SN/A 3062292SN/A if (is_failed_LLSC) { 3072292SN/A // The write was not successful, let MemChecker know. 3082292SN/A memchecker->abortWrite(received_state->serial, 3092292SN/A addr, 3102292SN/A size); 3112292SN/A } else { 3122292SN/A memchecker->completeWrite(received_state->serial, 3132329SN/A curTick(), 3142329SN/A addr, 3152292SN/A size); 3162292SN/A } 3172292SN/A 3182292SN/A delete received_state; 3192292SN/A } else { 3202292SN/A DPRINTF(MemCheckerMonitor, 3212292SN/A "Received non read/write response: addr = %#llx\n", addr); 3222292SN/A } 3232292SN/A } else if (is_read || is_write) { 3242292SN/A // Don't delete anything and let the packet look like we 3252292SN/A // did not touch it 3262292SN/A pkt->senderState = received_state; 3272292SN/A } 3282292SN/A 3292292SN/A return successful; 3302292SN/A} 3312292SN/A 3322292SN/Avoid 3332292SN/AMemCheckerMonitor::recvTimingSnoopReq(PacketPtr pkt) 3342292SN/A{ 3352292SN/A slavePort.sendTimingSnoopReq(pkt); 3362292SN/A} 3372292SN/A 3382292SN/Abool 3392292SN/AMemCheckerMonitor::recvTimingSnoopResp(PacketPtr pkt) 3402292SN/A{ 3412292SN/A return masterPort.sendTimingSnoopResp(pkt); 3422292SN/A} 3432292SN/A 3442292SN/Abool 3452292SN/AMemCheckerMonitor::isSnooping() const 3462292SN/A{ 3472292SN/A // check if the connected master port is snooping 3482292SN/A return slavePort.isSnooping(); 3492292SN/A} 3502292SN/A 3512292SN/AAddrRangeList 3522292SN/AMemCheckerMonitor::getAddrRanges() const 3532292SN/A{ 3542292SN/A // get the address ranges of the connected slave port 3552292SN/A return masterPort.getAddrRanges(); 3562292SN/A} 3572292SN/A 3582292SN/Avoid 3592292SN/AMemCheckerMonitor::recvRetryMaster() 3602292SN/A{ 3612292SN/A slavePort.sendRetry(); 3622292SN/A} 3632292SN/A 3642292SN/Avoid 3652292SN/AMemCheckerMonitor::recvRetrySlave() 3662292SN/A{ 3672292SN/A masterPort.sendRetry(); 3682292SN/A} 3692292SN/A 3702292SN/Avoid 3712292SN/AMemCheckerMonitor::recvRangeChange() 3722292SN/A{ 3732292SN/A slavePort.sendRangeChange(); 3742292SN/A} 3752292SN/A