mem_checker_monitor.cc revision 13449:2f7efa89c58b
12SN/A/*
21762SN/A * Copyright (c) 2012-2014 ARM Limited
32SN/A * All rights reserved
42SN/A *
52SN/A * The license below extends only to copyright in the software and shall
62SN/A * not be construed as granting a license to any other intellectual
72SN/A * property including but not limited to intellectual property relating
82SN/A * to a hardware implementation of the functionality of the software
92SN/A * licensed hereunder.  You may use the software subject to the license
102SN/A * terms below provided that you ensure that this notice is replicated
112SN/A * unmodified and in its entirety in all distributions of the software,
122SN/A * modified or unmodified, in source code or in binary form.
132SN/A *
142SN/A * Redistribution and use in source and binary forms, with or without
152SN/A * modification, are permitted provided that the following conditions are
162SN/A * met: redistributions of source code must retain the above copyright
172SN/A * notice, this list of conditions and the following disclaimer;
182SN/A * redistributions in binary form must reproduce the above copyright
192SN/A * notice, this list of conditions and the following disclaimer in the
202SN/A * documentation and/or other materials provided with the distribution;
212SN/A * neither the name of the copyright holders nor the names of its
222SN/A * contributors may be used to endorse or promote products derived from
232SN/A * this software without specific prior written permission.
242SN/A *
252SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282665Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292665Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3211793Sbrandon.potter@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3311793Sbrandon.potter@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
358229Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
364167Sbinkertn@umich.edu *
372SN/A * Authors: Thomas Grass
3812404Sgabeblack@google.com *          Andreas Hansson
3912404Sgabeblack@google.com *          Marco Elver
4012404Sgabeblack@google.com */
4112404Sgabeblack@google.com
4212404Sgabeblack@google.com#include "mem/mem_checker_monitor.hh"
4312404Sgabeblack@google.com
4412404Sgabeblack@google.com#include <memory>
4512404Sgabeblack@google.com
4612404Sgabeblack@google.com#include "base/logging.hh"
4712404Sgabeblack@google.com#include "base/output.hh"
4812404Sgabeblack@google.com#include "base/trace.hh"
4912404Sgabeblack@google.com#include "debug/MemCheckerMonitor.hh"
5012404Sgabeblack@google.com
5112404Sgabeblack@google.comMemCheckerMonitor::MemCheckerMonitor(Params* params)
5212404Sgabeblack@google.com    : MemObject(params),
5312404Sgabeblack@google.com      masterPort(name() + "-master", *this),
5412404Sgabeblack@google.com      slavePort(name() + "-slave", *this),
5512404Sgabeblack@google.com      warnOnly(params->warn_only),
5612404Sgabeblack@google.com      memchecker(params->memchecker)
5712404Sgabeblack@google.com{}
5812404Sgabeblack@google.com
5912404Sgabeblack@google.comMemCheckerMonitor::~MemCheckerMonitor()
6012404Sgabeblack@google.com{}
6112404Sgabeblack@google.com
6212404Sgabeblack@google.comMemCheckerMonitor*
6312404Sgabeblack@google.comMemCheckerMonitorParams::create()
6412404Sgabeblack@google.com{
6512404Sgabeblack@google.com    return new MemCheckerMonitor(this);
6612404Sgabeblack@google.com}
6712404Sgabeblack@google.com
6812404Sgabeblack@google.comvoid
6912404Sgabeblack@google.comMemCheckerMonitor::init()
7012404Sgabeblack@google.com{
712107SN/A    // make sure both sides of the monitor are connected
7212404Sgabeblack@google.com    if (!slavePort.isConnected() || !masterPort.isConnected())
732SN/A        fatal("Communication monitor is not connected on both sides.\n");
745870Snate@binkert.org}
755870Snate@binkert.org
765870Snate@binkert.orgBaseMasterPort&
775870Snate@binkert.orgMemCheckerMonitor::getMasterPort(const std::string& if_name, PortID idx)
785870Snate@binkert.org{
795870Snate@binkert.org    if (if_name == "master" || if_name == "mem_side") {
805870Snate@binkert.org        return masterPort;
815870Snate@binkert.org    } else {
822SN/A        return MemObject::getMasterPort(if_name, idx);
837720Sgblack@eecs.umich.edu    }
847720Sgblack@eecs.umich.edu}
852SN/A
862SN/ABaseSlavePort&
872SN/AMemCheckerMonitor::getSlavePort(const std::string& if_name, PortID idx)
882SN/A{
892SN/A    if (if_name == "slave" || if_name == "cpu_side") {
902SN/A        return slavePort;
912SN/A    } else {
922680Sktlim@umich.edu        return MemObject::getSlavePort(if_name, idx);
932SN/A    }
942SN/A}
952SN/A
962SN/Avoid
972SN/AMemCheckerMonitor::recvFunctional(PacketPtr pkt)
982SN/A{
993271Sgblack@eecs.umich.edu    Addr addr = pkt->getAddr();
1007720Sgblack@eecs.umich.edu    unsigned size = pkt->getSize();
1013271Sgblack@eecs.umich.edu
1024539Sgblack@eecs.umich.edu    // Conservatively reset this address-range. Alternatively we could try to
1035870Snate@binkert.org    // update the values seen by the memchecker, however, there may be other
1043271Sgblack@eecs.umich.edu    // reads/writes to these location from other devices we do not see.
1053271Sgblack@eecs.umich.edu    memchecker->reset(addr, size);
1067720Sgblack@eecs.umich.edu
1077720Sgblack@eecs.umich.edu    masterPort.sendFunctional(pkt);
1085870Snate@binkert.org
1095870Snate@binkert.org    DPRINTF(MemCheckerMonitor,
1105870Snate@binkert.org            "Forwarded functional access: addr = %#llx, size = %d\n",
1115870Snate@binkert.org            addr, size);
1125870Snate@binkert.org}
1135870Snate@binkert.org
1147720Sgblack@eecs.umich.eduvoid
1155870Snate@binkert.orgMemCheckerMonitor::recvFunctionalSnoop(PacketPtr pkt)
1165870Snate@binkert.org{
1175870Snate@binkert.org    Addr addr = pkt->getAddr();
1185870Snate@binkert.org    unsigned size = pkt->getSize();
1195870Snate@binkert.org
1205870Snate@binkert.org    // See above.
1215870Snate@binkert.org    memchecker->reset(addr, size);
1225870Snate@binkert.org
1235870Snate@binkert.org    slavePort.sendFunctionalSnoop(pkt);
1245870Snate@binkert.org
1255870Snate@binkert.org    DPRINTF(MemCheckerMonitor,
1265870Snate@binkert.org            "Received functional snoop: addr = %#llx, size = %d\n",
1275870Snate@binkert.org            addr, size);
1285870Snate@binkert.org}
1295870Snate@binkert.org
13010201SAndrew.Bardsley@arm.comTick
13110201SAndrew.Bardsley@arm.comMemCheckerMonitor::recvAtomic(PacketPtr pkt)
13210201SAndrew.Bardsley@arm.com{
13310201SAndrew.Bardsley@arm.com    panic("Atomic not supported");
13410201SAndrew.Bardsley@arm.com}
13510201SAndrew.Bardsley@arm.com
13610201SAndrew.Bardsley@arm.comTick
13710201SAndrew.Bardsley@arm.comMemCheckerMonitor::recvAtomicSnoop(PacketPtr pkt)
13810201SAndrew.Bardsley@arm.com{
13910201SAndrew.Bardsley@arm.com    panic("Atomic not supported");
14010201SAndrew.Bardsley@arm.com}
14110201SAndrew.Bardsley@arm.com
14210201SAndrew.Bardsley@arm.combool
14310201SAndrew.Bardsley@arm.comMemCheckerMonitor::recvTimingReq(PacketPtr pkt)
14410201SAndrew.Bardsley@arm.com{
14510201SAndrew.Bardsley@arm.com    // should always see a request
14610201SAndrew.Bardsley@arm.com    assert(pkt->isRequest());
147
148    // Store relevant fields of packet, because packet may be modified
149    // or even deleted when sendTiming() is called.
150    //
151    // For reads we are only interested in real reads, and not prefetches, as
152    // it is not guaranteed that the prefetch returns any useful data.
153    bool is_read = pkt->isRead() && !pkt->req->isPrefetch();
154    bool is_write = pkt->isWrite();
155    unsigned size = pkt->getSize();
156    Addr addr = pkt->getAddr();
157    bool expects_response = pkt->needsResponse() && !pkt->cacheResponding();
158    std::unique_ptr<uint8_t[]> pkt_data;
159    MemCheckerMonitorSenderState* state = NULL;
160
161    if (expects_response && is_write) {
162        // On receipt of a request, only need to allocate pkt_data if this is a
163        // write. For reads, we have no data yet, so it doesn't make sense to
164        // allocate.
165        pkt_data.reset(new uint8_t[size]);
166        pkt->writeData(pkt_data.get());
167    }
168
169    // If a cache miss is served by a cache, a monitor near the memory
170    // would see a request which needs a response, but this response
171    // would not come back from the memory. Therefore
172    // we additionally have to check the inhibit flag.
173    if (expects_response && (is_read || is_write)) {
174        state = new MemCheckerMonitorSenderState(0);
175        pkt->pushSenderState(state);
176    }
177
178    // Attempt to send the packet
179    bool successful = masterPort.sendTimingReq(pkt);
180
181    // If not successful, restore the sender state
182    if (!successful && expects_response && (is_read || is_write)) {
183        delete pkt->popSenderState();
184    }
185
186    if (successful && expects_response) {
187        if (is_read) {
188            MemChecker::Serial serial = memchecker->startRead(curTick(),
189                                                              addr,
190                                                              size);
191
192            // At the time where we push the sender-state, we do not yet know
193            // the serial the MemChecker class will assign to this request. We
194            // cannot call startRead at the time we push the sender-state, as
195            // the masterPort may not be successful in executing sendTimingReq,
196            // and in case of a failure, we must not modify the state of the
197            // MemChecker.
198            //
199            // Once we know that sendTimingReq was successful, we can set the
200            // serial of the newly constructed sender-state. This is legal, as
201            // we know that nobody else will touch nor is responsible for
202            // deletion of our sender-state.
203            state->serial = serial;
204
205            DPRINTF(MemCheckerMonitor,
206                    "Forwarded read request: serial = %d, addr = %#llx, "
207                    "size = %d\n",
208                    serial, addr, size);
209        } else if (is_write) {
210            MemChecker::Serial serial = memchecker->startWrite(curTick(),
211                                                               addr,
212                                                               size,
213                                                               pkt_data.get());
214
215            state->serial = serial;
216
217            DPRINTF(MemCheckerMonitor,
218                    "Forwarded write request: serial = %d, addr = %#llx, "
219                    "size = %d\n",
220                    serial, addr, size);
221        } else {
222            DPRINTF(MemCheckerMonitor,
223                    "Forwarded non read/write request: addr = %#llx\n", addr);
224        }
225    } else if (successful) {
226        DPRINTF(MemCheckerMonitor,
227                "Forwarded request marked for cache response: addr = %#llx\n",
228                addr);
229    }
230
231    return successful;
232}
233
234bool
235MemCheckerMonitor::recvTimingResp(PacketPtr pkt)
236{
237    // should always see responses
238    assert(pkt->isResponse());
239
240    // Store relevant fields of packet, because packet may be modified
241    // or even deleted when sendTiming() is called.
242    bool is_read = pkt->isRead() && !pkt->req->isPrefetch();
243    bool is_write = pkt->isWrite();
244    bool is_failed_LLSC = pkt->isLLSC() && pkt->req->getExtraData() == 0;
245    unsigned size = pkt->getSize();
246    Addr addr = pkt->getAddr();
247    std::unique_ptr<uint8_t[]> pkt_data;
248    MemCheckerMonitorSenderState* received_state = NULL;
249
250    if (is_read) {
251        // On receipt of a response, only need to allocate pkt_data if this is
252        // a read. For writes, we have already given the MemChecker the data on
253        // the request, so it doesn't make sense to allocate on write.
254        pkt_data.reset(new uint8_t[size]);
255        pkt->writeData(pkt_data.get());
256    }
257
258    if (is_read || is_write) {
259        received_state =
260            dynamic_cast<MemCheckerMonitorSenderState*>(pkt->senderState);
261
262        // Restore initial sender state
263        panic_if(received_state == NULL,
264                 "Monitor got a response without monitor sender state\n");
265
266        // Restore the state
267        pkt->senderState = received_state->predecessor;
268    }
269
270    // Attempt to send the packet
271    bool successful = slavePort.sendTimingResp(pkt);
272
273    // If packet successfully send, complete transaction in MemChecker
274    // instance, and delete sender state, otherwise restore state.
275    if (successful) {
276        if (is_read) {
277            DPRINTF(MemCheckerMonitor,
278                    "Received read response: serial = %d, addr = %#llx, "
279                    "size = %d\n",
280                    received_state->serial, addr, size);
281
282            bool result = memchecker->completeRead(received_state->serial,
283                                                   curTick(),
284                                                   addr,
285                                                   size,
286                                                   pkt_data.get());
287
288            if (!result) {
289                warn("%s: read of %#llx @ cycle %d failed:\n%s\n",
290                     name(),
291                     addr, curTick(),
292                     memchecker->getErrorMessage().c_str());
293
294                panic_if(!warnOnly, "MemChecker violation!");
295            }
296
297            delete received_state;
298        } else if (is_write) {
299            DPRINTF(MemCheckerMonitor,
300                    "Received write response: serial = %d, addr = %#llx, "
301                    "size = %d\n",
302                    received_state->serial, addr, size);
303
304            if (is_failed_LLSC) {
305                // The write was not successful, let MemChecker know.
306                memchecker->abortWrite(received_state->serial,
307                                       addr,
308                                       size);
309            } else {
310                memchecker->completeWrite(received_state->serial,
311                                          curTick(),
312                                          addr,
313                                          size);
314            }
315
316            delete received_state;
317        } else {
318            DPRINTF(MemCheckerMonitor,
319                    "Received non read/write response: addr = %#llx\n", addr);
320        }
321    } else if (is_read || is_write) {
322        // Don't delete anything and let the packet look like we
323        // did not touch it
324        pkt->senderState = received_state;
325    }
326
327    return successful;
328}
329
330void
331MemCheckerMonitor::recvTimingSnoopReq(PacketPtr pkt)
332{
333    slavePort.sendTimingSnoopReq(pkt);
334}
335
336bool
337MemCheckerMonitor::recvTimingSnoopResp(PacketPtr pkt)
338{
339    return masterPort.sendTimingSnoopResp(pkt);
340}
341
342bool
343MemCheckerMonitor::isSnooping() const
344{
345    // check if the connected master port is snooping
346    return slavePort.isSnooping();
347}
348
349AddrRangeList
350MemCheckerMonitor::getAddrRanges() const
351{
352    // get the address ranges of the connected slave port
353    return masterPort.getAddrRanges();
354}
355
356void
357MemCheckerMonitor::recvReqRetry()
358{
359    slavePort.sendRetryReq();
360}
361
362void
363MemCheckerMonitor::recvRespRetry()
364{
365    masterPort.sendRetryResp();
366}
367
368void
369MemCheckerMonitor::recvRangeChange()
370{
371    slavePort.sendRangeChange();
372}
373