mem_checker_monitor.cc revision 12637:bfc3cb9c7e6c
12810SN/A/* 212728Snikos.nikoleris@arm.com * Copyright (c) 2012-2014 ARM Limited 39796Sprakash.ramrakhyani@arm.com * All rights reserved 49796Sprakash.ramrakhyani@arm.com * 59796Sprakash.ramrakhyani@arm.com * The license below extends only to copyright in the software and shall 69796Sprakash.ramrakhyani@arm.com * not be construed as granting a license to any other intellectual 79796Sprakash.ramrakhyani@arm.com * property including but not limited to intellectual property relating 89796Sprakash.ramrakhyani@arm.com * to a hardware implementation of the functionality of the software 99796Sprakash.ramrakhyani@arm.com * licensed hereunder. You may use the software subject to the license 109796Sprakash.ramrakhyani@arm.com * terms below provided that you ensure that this notice is replicated 119796Sprakash.ramrakhyani@arm.com * unmodified and in its entirety in all distributions of the software, 129796Sprakash.ramrakhyani@arm.com * modified or unmodified, in source code or in binary form. 139796Sprakash.ramrakhyani@arm.com * 142810SN/A * Redistribution and use in source and binary forms, with or without 152810SN/A * modification, are permitted provided that the following conditions are 162810SN/A * met: redistributions of source code must retain the above copyright 172810SN/A * notice, this list of conditions and the following disclaimer; 182810SN/A * redistributions in binary form must reproduce the above copyright 192810SN/A * notice, this list of conditions and the following disclaimer in the 202810SN/A * documentation and/or other materials provided with the distribution; 212810SN/A * neither the name of the copyright holders nor the names of its 222810SN/A * contributors may be used to endorse or promote products derived from 232810SN/A * this software without specific prior written permission. 242810SN/A * 252810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 362810SN/A * 372810SN/A * Authors: Thomas Grass 382810SN/A * Andreas Hansson 392810SN/A * Marco Elver 402810SN/A */ 412810SN/A 422810SN/A#include "mem/mem_checker_monitor.hh" 432810SN/A 442810SN/A#include <memory> 452810SN/A 462810SN/A#include "base/output.hh" 472810SN/A#include "base/trace.hh" 482810SN/A#include "debug/MemCheckerMonitor.hh" 4911486Snikos.nikoleris@arm.com 5011486Snikos.nikoleris@arm.comMemCheckerMonitor::MemCheckerMonitor(Params* params) 5112727Snikos.nikoleris@arm.com : MemObject(params), 5212727Snikos.nikoleris@arm.com masterPort(name() + "-master", *this), 5312727Snikos.nikoleris@arm.com slavePort(name() + "-slave", *this), 5413225Sodanrc@yahoo.com.br warnOnly(params->warn_only), 5513219Sodanrc@yahoo.com.br memchecker(params->memchecker) 5612727Snikos.nikoleris@arm.com{} 5712727Snikos.nikoleris@arm.com 582810SN/AMemCheckerMonitor::~MemCheckerMonitor() 5912727Snikos.nikoleris@arm.com{} 602810SN/A 619796Sprakash.ramrakhyani@arm.comMemCheckerMonitor* 6211893Snikos.nikoleris@arm.comMemCheckerMonitorParams::create() 6313418Sodanrc@yahoo.com.br{ 6413419Sodanrc@yahoo.com.br return new MemCheckerMonitor(this); 6512513Sodanrc@yahoo.com.br} 6612629Sodanrc@yahoo.com.br 6712629Sodanrc@yahoo.com.brvoid 689796Sprakash.ramrakhyani@arm.comMemCheckerMonitor::init() 699796Sprakash.ramrakhyani@arm.com{ 709796Sprakash.ramrakhyani@arm.com // make sure both sides of the monitor are connected 7113219Sodanrc@yahoo.com.br if (!slavePort.isConnected() || !masterPort.isConnected()) 7213219Sodanrc@yahoo.com.br fatal("Communication monitor is not connected on both sides.\n"); 7313217Sodanrc@yahoo.com.br} 7413219Sodanrc@yahoo.com.br 7513217Sodanrc@yahoo.com.brBaseMasterPort& 7613217Sodanrc@yahoo.com.brMemCheckerMonitor::getMasterPort(const std::string& if_name, PortID idx) 7713217Sodanrc@yahoo.com.br{ 7813217Sodanrc@yahoo.com.br if (if_name == "master" || if_name == "mem_side") { 7913217Sodanrc@yahoo.com.br return masterPort; 8013217Sodanrc@yahoo.com.br } else { 8113217Sodanrc@yahoo.com.br return MemObject::getMasterPort(if_name, idx); 8213217Sodanrc@yahoo.com.br } 8313219Sodanrc@yahoo.com.br} 8413219Sodanrc@yahoo.com.br 8513219Sodanrc@yahoo.com.brBaseSlavePort& 8613217Sodanrc@yahoo.com.brMemCheckerMonitor::getSlavePort(const std::string& if_name, PortID idx) 8713217Sodanrc@yahoo.com.br{ 8813219Sodanrc@yahoo.com.br if (if_name == "slave" || if_name == "cpu_side") { 8913217Sodanrc@yahoo.com.br return slavePort; 9013217Sodanrc@yahoo.com.br } else { 9113217Sodanrc@yahoo.com.br return MemObject::getSlavePort(if_name, idx); 9213217Sodanrc@yahoo.com.br } 9313217Sodanrc@yahoo.com.br} 9413217Sodanrc@yahoo.com.br 9513217Sodanrc@yahoo.com.brvoid 9613217Sodanrc@yahoo.com.brMemCheckerMonitor::recvFunctional(PacketPtr pkt) 9713217Sodanrc@yahoo.com.br{ 9813217Sodanrc@yahoo.com.br Addr addr = pkt->getAddr(); 9913217Sodanrc@yahoo.com.br unsigned size = pkt->getSize(); 1002810SN/A 10113752Sodanrc@yahoo.com.br // Conservatively reset this address-range. Alternatively we could try to 10212636Sodanrc@yahoo.com.br // update the values seen by the memchecker, however, there may be other 10312722Snikos.nikoleris@arm.com // reads/writes to these location from other devices we do not see. 10412722Snikos.nikoleris@arm.com memchecker->reset(addr, size); 10512636Sodanrc@yahoo.com.br 10612636Sodanrc@yahoo.com.br masterPort.sendFunctional(pkt); 10713752Sodanrc@yahoo.com.br 10812636Sodanrc@yahoo.com.br DPRINTF(MemCheckerMonitor, 10913752Sodanrc@yahoo.com.br "Forwarded functional access: addr = %#llx, size = %d\n", 11013752Sodanrc@yahoo.com.br addr, size); 11113752Sodanrc@yahoo.com.br} 11212636Sodanrc@yahoo.com.br 11312691Sodanrc@yahoo.com.brvoid 11413752Sodanrc@yahoo.com.brMemCheckerMonitor::recvFunctionalSnoop(PacketPtr pkt) 11513752Sodanrc@yahoo.com.br{ 11612636Sodanrc@yahoo.com.br Addr addr = pkt->getAddr(); 11713215Sodanrc@yahoo.com.br unsigned size = pkt->getSize(); 11812703Snikos.nikoleris@arm.com 11912703Snikos.nikoleris@arm.com // See above. 12012703Snikos.nikoleris@arm.com memchecker->reset(addr, size); 12112703Snikos.nikoleris@arm.com 12212703Snikos.nikoleris@arm.com slavePort.sendFunctionalSnoop(pkt); 12312636Sodanrc@yahoo.com.br 12412636Sodanrc@yahoo.com.br DPRINTF(MemCheckerMonitor, 12512636Sodanrc@yahoo.com.br "Received functional snoop: addr = %#llx, size = %d\n", 12612636Sodanrc@yahoo.com.br addr, size); 12712636Sodanrc@yahoo.com.br} 12813219Sodanrc@yahoo.com.br 12913219Sodanrc@yahoo.com.brTick 13013219Sodanrc@yahoo.com.brMemCheckerMonitor::recvAtomic(PacketPtr pkt) 13113219Sodanrc@yahoo.com.br{ 13213219Sodanrc@yahoo.com.br assert(false && "Atomic not supported"); 13313219Sodanrc@yahoo.com.br return masterPort.sendAtomic(pkt); 13412636Sodanrc@yahoo.com.br} 13512728Snikos.nikoleris@arm.com 13612728Snikos.nikoleris@arm.comTick 13712728Snikos.nikoleris@arm.comMemCheckerMonitor::recvAtomicSnoop(PacketPtr pkt) 13812728Snikos.nikoleris@arm.com{ 13912728Snikos.nikoleris@arm.com assert(false && "Atomic not supported"); 14012728Snikos.nikoleris@arm.com return slavePort.sendAtomicSnoop(pkt); 14112728Snikos.nikoleris@arm.com} 14212728Snikos.nikoleris@arm.com 14312728Snikos.nikoleris@arm.combool 14412728Snikos.nikoleris@arm.comMemCheckerMonitor::recvTimingReq(PacketPtr pkt) 14512728Snikos.nikoleris@arm.com{ 14612728Snikos.nikoleris@arm.com // should always see a request 14712728Snikos.nikoleris@arm.com assert(pkt->isRequest()); 14812728Snikos.nikoleris@arm.com 14912728Snikos.nikoleris@arm.com // Store relevant fields of packet, because packet may be modified 15012728Snikos.nikoleris@arm.com // or even deleted when sendTiming() is called. 15112728Snikos.nikoleris@arm.com // 15212728Snikos.nikoleris@arm.com // For reads we are only interested in real reads, and not prefetches, as 15312728Snikos.nikoleris@arm.com // it is not guaranteed that the prefetch returns any useful data. 15412728Snikos.nikoleris@arm.com bool is_read = pkt->isRead() && !pkt->req->isPrefetch(); 15512728Snikos.nikoleris@arm.com bool is_write = pkt->isWrite(); 15612728Snikos.nikoleris@arm.com unsigned size = pkt->getSize(); 15712728Snikos.nikoleris@arm.com Addr addr = pkt->getAddr(); 15812728Snikos.nikoleris@arm.com bool expects_response = pkt->needsResponse() && !pkt->cacheResponding(); 15912728Snikos.nikoleris@arm.com std::unique_ptr<uint8_t[]> pkt_data; 16012728Snikos.nikoleris@arm.com MemCheckerMonitorSenderState* state = NULL; 16112728Snikos.nikoleris@arm.com 16212728Snikos.nikoleris@arm.com if (expects_response && is_write) { 16312728Snikos.nikoleris@arm.com // On receipt of a request, only need to allocate pkt_data if this is a 16412728Snikos.nikoleris@arm.com // write. For reads, we have no data yet, so it doesn't make sense to 16512728Snikos.nikoleris@arm.com // allocate. 16612728Snikos.nikoleris@arm.com pkt_data.reset(new uint8_t[size]); 16712728Snikos.nikoleris@arm.com memcpy(pkt_data.get(), pkt->getConstPtr<uint8_t*>(), size); 16812728Snikos.nikoleris@arm.com } 16912728Snikos.nikoleris@arm.com 17012728Snikos.nikoleris@arm.com // If a cache miss is served by a cache, a monitor near the memory 17112728Snikos.nikoleris@arm.com // would see a request which needs a response, but this response 17212728Snikos.nikoleris@arm.com // would not come back from the memory. Therefore 17312728Snikos.nikoleris@arm.com // we additionally have to check the inhibit flag. 17412728Snikos.nikoleris@arm.com if (expects_response && (is_read || is_write)) { 17512728Snikos.nikoleris@arm.com state = new MemCheckerMonitorSenderState(0); 17612728Snikos.nikoleris@arm.com pkt->pushSenderState(state); 17712728Snikos.nikoleris@arm.com } 17812728Snikos.nikoleris@arm.com 17912728Snikos.nikoleris@arm.com // Attempt to send the packet 18012728Snikos.nikoleris@arm.com bool successful = masterPort.sendTimingReq(pkt); 18112728Snikos.nikoleris@arm.com 18212728Snikos.nikoleris@arm.com // If not successful, restore the sender state 18312728Snikos.nikoleris@arm.com if (!successful && expects_response && (is_read || is_write)) { 18412728Snikos.nikoleris@arm.com delete pkt->popSenderState(); 18512728Snikos.nikoleris@arm.com } 18612728Snikos.nikoleris@arm.com 18712728Snikos.nikoleris@arm.com if (successful && expects_response) { 18812728Snikos.nikoleris@arm.com if (is_read) { 18912728Snikos.nikoleris@arm.com MemChecker::Serial serial = memchecker->startRead(curTick(), 19012728Snikos.nikoleris@arm.com addr, 19112728Snikos.nikoleris@arm.com size); 19212728Snikos.nikoleris@arm.com 19312728Snikos.nikoleris@arm.com // At the time where we push the sender-state, we do not yet know 19413222Sodanrc@yahoo.com.br // the serial the MemChecker class will assign to this request. We 19512728Snikos.nikoleris@arm.com // cannot call startRead at the time we push the sender-state, as 19612728Snikos.nikoleris@arm.com // the masterPort may not be successful in executing sendTimingReq, 19712728Snikos.nikoleris@arm.com // and in case of a failure, we must not modify the state of the 19812728Snikos.nikoleris@arm.com // MemChecker. 19912728Snikos.nikoleris@arm.com // 20012728Snikos.nikoleris@arm.com // Once we know that sendTimingReq was successful, we can set the 20112728Snikos.nikoleris@arm.com // serial of the newly constructed sender-state. This is legal, as 20212728Snikos.nikoleris@arm.com // we know that nobody else will touch nor is responsible for 20312728Snikos.nikoleris@arm.com // deletion of our sender-state. 20412728Snikos.nikoleris@arm.com state->serial = serial; 2059796Sprakash.ramrakhyani@arm.com 2062810SN/A DPRINTF(MemCheckerMonitor, 20711522Sstephan.diestelhorst@arm.com "Forwarded read request: serial = %d, addr = %#llx, " 20811522Sstephan.diestelhorst@arm.com "size = %d\n", 2092810SN/A serial, addr, size); 21011522Sstephan.diestelhorst@arm.com } else if (is_write) { 2112810SN/A MemChecker::Serial serial = memchecker->startWrite(curTick(), 2129796Sprakash.ramrakhyani@arm.com addr, 2132810SN/A size, 2142810SN/A pkt_data.get()); 2152810SN/A 2162810SN/A state->serial = serial; 2179796Sprakash.ramrakhyani@arm.com 2182810SN/A DPRINTF(MemCheckerMonitor, 2192810SN/A "Forwarded write request: serial = %d, addr = %#llx, " 2202810SN/A "size = %d\n", 2212810SN/A serial, addr, size); 2229796Sprakash.ramrakhyani@arm.com } else { 2232810SN/A DPRINTF(MemCheckerMonitor, 2242810SN/A "Forwarded non read/write request: addr = %#llx\n", addr); 2252810SN/A } 2262810SN/A } else if (successful) { 2279796Sprakash.ramrakhyani@arm.com DPRINTF(MemCheckerMonitor, 2282810SN/A "Forwarded request marked for cache response: addr = %#llx\n", 2292810SN/A addr); 2302810SN/A } 2312810SN/A 2322810SN/A return successful; 2332810SN/A} 2349796Sprakash.ramrakhyani@arm.com 2352810SN/Abool 2362810SN/AMemCheckerMonitor::recvTimingResp(PacketPtr pkt) 2372810SN/A{ 2386978SLisa.Hsu@amd.com // should always see responses 23913419Sodanrc@yahoo.com.br assert(pkt->isResponse()); 2409796Sprakash.ramrakhyani@arm.com 2418833Sdam.sunwoo@arm.com // Store relevant fields of packet, because packet may be modified 2426978SLisa.Hsu@amd.com // or even deleted when sendTiming() is called. 2436978SLisa.Hsu@amd.com bool is_read = pkt->isRead() && !pkt->req->isPrefetch(); 24413419Sodanrc@yahoo.com.br bool is_write = pkt->isWrite(); 24513419Sodanrc@yahoo.com.br bool is_failed_LLSC = pkt->isLLSC() && pkt->req->getExtraData() == 0; 2468833Sdam.sunwoo@arm.com unsigned size = pkt->getSize(); 2476978SLisa.Hsu@amd.com Addr addr = pkt->getAddr(); 2486978SLisa.Hsu@amd.com std::unique_ptr<uint8_t[]> pkt_data; 2499796Sprakash.ramrakhyani@arm.com MemCheckerMonitorSenderState* received_state = NULL; 2506978SLisa.Hsu@amd.com 2518833Sdam.sunwoo@arm.com if (is_read) { 2526978SLisa.Hsu@amd.com // On receipt of a response, only need to allocate pkt_data if this is 25313419Sodanrc@yahoo.com.br // a read. For writes, we have already given the MemChecker the data on 25413419Sodanrc@yahoo.com.br // the request, so it doesn't make sense to allocate on write. 2558833Sdam.sunwoo@arm.com pkt_data.reset(new uint8_t[size]); 2566978SLisa.Hsu@amd.com memcpy(pkt_data.get(), pkt->getConstPtr<uint8_t*>(), size); 2576978SLisa.Hsu@amd.com } 2586978SLisa.Hsu@amd.com 25910024Sdam.sunwoo@arm.com if (is_read || is_write) { 26010024Sdam.sunwoo@arm.com received_state = 26110024Sdam.sunwoo@arm.com dynamic_cast<MemCheckerMonitorSenderState*>(pkt->senderState); 26210024Sdam.sunwoo@arm.com 26310024Sdam.sunwoo@arm.com // Restore initial sender state 26410024Sdam.sunwoo@arm.com panic_if(received_state == NULL, 26510024Sdam.sunwoo@arm.com "Monitor got a response without monitor sender state\n"); 26610024Sdam.sunwoo@arm.com 26710024Sdam.sunwoo@arm.com // Restore the state 26810024Sdam.sunwoo@arm.com pkt->senderState = received_state->predecessor; 26910024Sdam.sunwoo@arm.com } 27010024Sdam.sunwoo@arm.com 27110024Sdam.sunwoo@arm.com // Attempt to send the packet 27210024Sdam.sunwoo@arm.com bool successful = slavePort.sendTimingResp(pkt); 27310024Sdam.sunwoo@arm.com 27410024Sdam.sunwoo@arm.com // If packet successfully send, complete transaction in MemChecker 27510024Sdam.sunwoo@arm.com // instance, and delete sender state, otherwise restore state. 27610024Sdam.sunwoo@arm.com if (successful) { 27710024Sdam.sunwoo@arm.com if (is_read) { 27810024Sdam.sunwoo@arm.com DPRINTF(MemCheckerMonitor, 27910024Sdam.sunwoo@arm.com "Received read response: serial = %d, addr = %#llx, " 28010024Sdam.sunwoo@arm.com "size = %d\n", 28110025Stimothy.jones@arm.com received_state->serial, addr, size); 28210025Stimothy.jones@arm.com 28310025Stimothy.jones@arm.com bool result = memchecker->completeRead(received_state->serial, 28410025Stimothy.jones@arm.com curTick(), 28510025Stimothy.jones@arm.com addr, 28610025Stimothy.jones@arm.com size, 28710025Stimothy.jones@arm.com pkt_data.get()); 28810025Stimothy.jones@arm.com 28910025Stimothy.jones@arm.com if (!result) { 29010025Stimothy.jones@arm.com warn("%s: read of %#llx @ cycle %d failed:\n%s\n", 29110024Sdam.sunwoo@arm.com name(), 2922810SN/A addr, curTick(), 2932810SN/A memchecker->getErrorMessage().c_str()); 294 295 panic_if(!warnOnly, "MemChecker violation!"); 296 } 297 298 delete received_state; 299 } else if (is_write) { 300 DPRINTF(MemCheckerMonitor, 301 "Received write response: serial = %d, addr = %#llx, " 302 "size = %d\n", 303 received_state->serial, addr, size); 304 305 if (is_failed_LLSC) { 306 // The write was not successful, let MemChecker know. 307 memchecker->abortWrite(received_state->serial, 308 addr, 309 size); 310 } else { 311 memchecker->completeWrite(received_state->serial, 312 curTick(), 313 addr, 314 size); 315 } 316 317 delete received_state; 318 } else { 319 DPRINTF(MemCheckerMonitor, 320 "Received non read/write response: addr = %#llx\n", addr); 321 } 322 } else if (is_read || is_write) { 323 // Don't delete anything and let the packet look like we 324 // did not touch it 325 pkt->senderState = received_state; 326 } 327 328 return successful; 329} 330 331void 332MemCheckerMonitor::recvTimingSnoopReq(PacketPtr pkt) 333{ 334 slavePort.sendTimingSnoopReq(pkt); 335} 336 337bool 338MemCheckerMonitor::recvTimingSnoopResp(PacketPtr pkt) 339{ 340 return masterPort.sendTimingSnoopResp(pkt); 341} 342 343bool 344MemCheckerMonitor::isSnooping() const 345{ 346 // check if the connected master port is snooping 347 return slavePort.isSnooping(); 348} 349 350AddrRangeList 351MemCheckerMonitor::getAddrRanges() const 352{ 353 // get the address ranges of the connected slave port 354 return masterPort.getAddrRanges(); 355} 356 357void 358MemCheckerMonitor::recvReqRetry() 359{ 360 slavePort.sendRetryReq(); 361} 362 363void 364MemCheckerMonitor::recvRespRetry() 365{ 366 masterPort.sendRetryResp(); 367} 368 369void 370MemCheckerMonitor::recvRangeChange() 371{ 372 slavePort.sendRangeChange(); 373} 374