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