mem_checker_monitor.cc revision 11793:ef606668d247
1/*
2 * Copyright (c) 2012-2014 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Thomas Grass
38 *          Andreas Hansson
39 *          Marco Elver
40 */
41
42#include "mem/mem_checker_monitor.hh"
43
44#include <memory>
45
46#include "base/output.hh"
47#include "base/trace.hh"
48#include "debug/MemCheckerMonitor.hh"
49
50using namespace std;
51
52MemCheckerMonitor::MemCheckerMonitor(Params* params)
53    : MemObject(params),
54      masterPort(name() + "-master", *this),
55      slavePort(name() + "-slave", *this),
56      warnOnly(params->warn_only),
57      memchecker(params->memchecker)
58{}
59
60MemCheckerMonitor::~MemCheckerMonitor()
61{}
62
63MemCheckerMonitor*
64MemCheckerMonitorParams::create()
65{
66    return new MemCheckerMonitor(this);
67}
68
69void
70MemCheckerMonitor::init()
71{
72    // make sure both sides of the monitor are connected
73    if (!slavePort.isConnected() || !masterPort.isConnected())
74        fatal("Communication monitor is not connected on both sides.\n");
75}
76
77BaseMasterPort&
78MemCheckerMonitor::getMasterPort(const std::string& if_name, PortID idx)
79{
80    if (if_name == "master" || if_name == "mem_side") {
81        return masterPort;
82    } else {
83        return MemObject::getMasterPort(if_name, idx);
84    }
85}
86
87BaseSlavePort&
88MemCheckerMonitor::getSlavePort(const std::string& if_name, PortID idx)
89{
90    if (if_name == "slave" || if_name == "cpu_side") {
91        return slavePort;
92    } else {
93        return MemObject::getSlavePort(if_name, idx);
94    }
95}
96
97void
98MemCheckerMonitor::recvFunctional(PacketPtr pkt)
99{
100    Addr addr = pkt->getAddr();
101    unsigned size = pkt->getSize();
102
103    // Conservatively reset this address-range. Alternatively we could try to
104    // update the values seen by the memchecker, however, there may be other
105    // reads/writes to these location from other devices we do not see.
106    memchecker->reset(addr, size);
107
108    masterPort.sendFunctional(pkt);
109
110    DPRINTF(MemCheckerMonitor,
111            "Forwarded functional access: addr = %#llx, size = %d\n",
112            addr, size);
113}
114
115void
116MemCheckerMonitor::recvFunctionalSnoop(PacketPtr pkt)
117{
118    Addr addr = pkt->getAddr();
119    unsigned size = pkt->getSize();
120
121    // See above.
122    memchecker->reset(addr, size);
123
124    slavePort.sendFunctionalSnoop(pkt);
125
126    DPRINTF(MemCheckerMonitor,
127            "Received functional snoop: addr = %#llx, size = %d\n",
128            addr, size);
129}
130
131Tick
132MemCheckerMonitor::recvAtomic(PacketPtr pkt)
133{
134    assert(false && "Atomic not supported");
135    return masterPort.sendAtomic(pkt);
136}
137
138Tick
139MemCheckerMonitor::recvAtomicSnoop(PacketPtr pkt)
140{
141    assert(false && "Atomic not supported");
142    return slavePort.sendAtomicSnoop(pkt);
143}
144
145bool
146MemCheckerMonitor::recvTimingReq(PacketPtr pkt)
147{
148    // should always see a request
149    assert(pkt->isRequest());
150
151    // Store relevant fields of packet, because packet may be modified
152    // or even deleted when sendTiming() is called.
153    //
154    // For reads we are only interested in real reads, and not prefetches, as
155    // it is not guaranteed that the prefetch returns any useful data.
156    bool is_read = pkt->isRead() && !pkt->req->isPrefetch();
157    bool is_write = pkt->isWrite();
158    unsigned size = pkt->getSize();
159    Addr addr = pkt->getAddr();
160    bool expects_response = pkt->needsResponse() && !pkt->cacheResponding();
161    std::unique_ptr<uint8_t[]> pkt_data;
162    MemCheckerMonitorSenderState* state = NULL;
163
164    if (expects_response && is_write) {
165        // On receipt of a request, only need to allocate pkt_data if this is a
166        // write. For reads, we have no data yet, so it doesn't make sense to
167        // allocate.
168        pkt_data.reset(new uint8_t[size]);
169        memcpy(pkt_data.get(), pkt->getConstPtr<uint8_t*>(), size);
170    }
171
172    // If a cache miss is served by a cache, a monitor near the memory
173    // would see a request which needs a response, but this response
174    // would not come back from the memory. Therefore
175    // we additionally have to check the inhibit flag.
176    if (expects_response && (is_read || is_write)) {
177        state = new MemCheckerMonitorSenderState(0);
178        pkt->pushSenderState(state);
179    }
180
181    // Attempt to send the packet
182    bool successful = masterPort.sendTimingReq(pkt);
183
184    // If not successful, restore the sender state
185    if (!successful && expects_response && (is_read || is_write)) {
186        delete pkt->popSenderState();
187    }
188
189    if (successful && expects_response) {
190        if (is_read) {
191            MemChecker::Serial serial = memchecker->startRead(curTick(),
192                                                              addr,
193                                                              size);
194
195            // At the time where we push the sender-state, we do not yet know
196            // the serial the MemChecker class will assign to this request. We
197            // cannot call startRead at the time we push the sender-state, as
198            // the masterPort may not be successful in executing sendTimingReq,
199            // and in case of a failure, we must not modify the state of the
200            // MemChecker.
201            //
202            // Once we know that sendTimingReq was successful, we can set the
203            // serial of the newly constructed sender-state. This is legal, as
204            // we know that nobody else will touch nor is responsible for
205            // deletion of our sender-state.
206            state->serial = serial;
207
208            DPRINTF(MemCheckerMonitor,
209                    "Forwarded read request: serial = %d, addr = %#llx, "
210                    "size = %d\n",
211                    serial, addr, size);
212        } else if (is_write) {
213            MemChecker::Serial serial = memchecker->startWrite(curTick(),
214                                                               addr,
215                                                               size,
216                                                               pkt_data.get());
217
218            state->serial = serial;
219
220            DPRINTF(MemCheckerMonitor,
221                    "Forwarded write request: serial = %d, addr = %#llx, "
222                    "size = %d\n",
223                    serial, addr, size);
224        } else {
225            DPRINTF(MemCheckerMonitor,
226                    "Forwarded non read/write request: addr = %#llx\n", addr);
227        }
228    } else if (successful) {
229        DPRINTF(MemCheckerMonitor,
230                "Forwarded request marked for cache response: addr = %#llx\n",
231                addr);
232    }
233
234    return successful;
235}
236
237bool
238MemCheckerMonitor::recvTimingResp(PacketPtr pkt)
239{
240    // should always see responses
241    assert(pkt->isResponse());
242
243    // Store relevant fields of packet, because packet may be modified
244    // or even deleted when sendTiming() is called.
245    bool is_read = pkt->isRead() && !pkt->req->isPrefetch();
246    bool is_write = pkt->isWrite();
247    bool is_failed_LLSC = pkt->isLLSC() && pkt->req->getExtraData() == 0;
248    unsigned size = pkt->getSize();
249    Addr addr = pkt->getAddr();
250    std::unique_ptr<uint8_t[]> pkt_data;
251    MemCheckerMonitorSenderState* received_state = NULL;
252
253    if (is_read) {
254        // On receipt of a response, only need to allocate pkt_data if this is
255        // a read. For writes, we have already given the MemChecker the data on
256        // the request, so it doesn't make sense to allocate on write.
257        pkt_data.reset(new uint8_t[size]);
258        memcpy(pkt_data.get(), pkt->getConstPtr<uint8_t*>(), size);
259    }
260
261    if (is_read || is_write) {
262        received_state =
263            dynamic_cast<MemCheckerMonitorSenderState*>(pkt->senderState);
264
265        // Restore initial sender state
266        panic_if(received_state == NULL,
267                 "Monitor got a response without monitor sender state\n");
268
269        // Restore the state
270        pkt->senderState = received_state->predecessor;
271    }
272
273    // Attempt to send the packet
274    bool successful = slavePort.sendTimingResp(pkt);
275
276    // If packet successfully send, complete transaction in MemChecker
277    // instance, and delete sender state, otherwise restore state.
278    if (successful) {
279        if (is_read) {
280            DPRINTF(MemCheckerMonitor,
281                    "Received read response: serial = %d, addr = %#llx, "
282                    "size = %d\n",
283                    received_state->serial, addr, size);
284
285            bool result = memchecker->completeRead(received_state->serial,
286                                                   curTick(),
287                                                   addr,
288                                                   size,
289                                                   pkt_data.get());
290
291            if (!result) {
292                warn("%s: read of %#llx @ cycle %d failed:\n%s\n",
293                     name(),
294                     addr, curTick(),
295                     memchecker->getErrorMessage().c_str());
296
297                panic_if(!warnOnly, "MemChecker violation!");
298            }
299
300            delete received_state;
301        } else if (is_write) {
302            DPRINTF(MemCheckerMonitor,
303                    "Received write response: serial = %d, addr = %#llx, "
304                    "size = %d\n",
305                    received_state->serial, addr, size);
306
307            if (is_failed_LLSC) {
308                // The write was not successful, let MemChecker know.
309                memchecker->abortWrite(received_state->serial,
310                                       addr,
311                                       size);
312            } else {
313                memchecker->completeWrite(received_state->serial,
314                                          curTick(),
315                                          addr,
316                                          size);
317            }
318
319            delete received_state;
320        } else {
321            DPRINTF(MemCheckerMonitor,
322                    "Received non read/write response: addr = %#llx\n", addr);
323        }
324    } else if (is_read || is_write) {
325        // Don't delete anything and let the packet look like we
326        // did not touch it
327        pkt->senderState = received_state;
328    }
329
330    return successful;
331}
332
333void
334MemCheckerMonitor::recvTimingSnoopReq(PacketPtr pkt)
335{
336    slavePort.sendTimingSnoopReq(pkt);
337}
338
339bool
340MemCheckerMonitor::recvTimingSnoopResp(PacketPtr pkt)
341{
342    return masterPort.sendTimingSnoopResp(pkt);
343}
344
345bool
346MemCheckerMonitor::isSnooping() const
347{
348    // check if the connected master port is snooping
349    return slavePort.isSnooping();
350}
351
352AddrRangeList
353MemCheckerMonitor::getAddrRanges() const
354{
355    // get the address ranges of the connected slave port
356    return masterPort.getAddrRanges();
357}
358
359void
360MemCheckerMonitor::recvReqRetry()
361{
362    slavePort.sendRetryReq();
363}
364
365void
366MemCheckerMonitor::recvRespRetry()
367{
368    masterPort.sendRetryResp();
369}
370
371void
372MemCheckerMonitor::recvRangeChange()
373{
374    slavePort.sendRangeChange();
375}
376