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