mem_checker_monitor.cc revision 11284:b3926db25371
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 <memory>
43
44#include "base/output.hh"
45#include "base/trace.hh"
46#include "debug/MemCheckerMonitor.hh"
47#include "mem/mem_checker_monitor.hh"
48
49using namespace std;
50
51MemCheckerMonitor::MemCheckerMonitor(Params* params)
52    : MemObject(params),
53      masterPort(name() + "-master", *this),
54      slavePort(name() + "-slave", *this),
55      warnOnly(params->warn_only),
56      memchecker(params->memchecker)
57{}
58
59MemCheckerMonitor::~MemCheckerMonitor()
60{}
61
62MemCheckerMonitor*
63MemCheckerMonitorParams::create()
64{
65    return new MemCheckerMonitor(this);
66}
67
68void
69MemCheckerMonitor::init()
70{
71    // make sure both sides of the monitor are connected
72    if (!slavePort.isConnected() || !masterPort.isConnected())
73        fatal("Communication monitor is not connected on both sides.\n");
74}
75
76BaseMasterPort&
77MemCheckerMonitor::getMasterPort(const std::string& if_name, PortID idx)
78{
79    if (if_name == "master" || if_name == "mem_side") {
80        return masterPort;
81    } else {
82        return MemObject::getMasterPort(if_name, idx);
83    }
84}
85
86BaseSlavePort&
87MemCheckerMonitor::getSlavePort(const std::string& if_name, PortID idx)
88{
89    if (if_name == "slave" || if_name == "cpu_side") {
90        return slavePort;
91    } else {
92        return MemObject::getSlavePort(if_name, idx);
93    }
94}
95
96void
97MemCheckerMonitor::recvFunctional(PacketPtr pkt)
98{
99    Addr addr = pkt->getAddr();
100    unsigned size = pkt->getSize();
101
102    // Conservatively reset this address-range. Alternatively we could try to
103    // update the values seen by the memchecker, however, there may be other
104    // reads/writes to these location from other devices we do not see.
105    memchecker->reset(addr, size);
106
107    masterPort.sendFunctional(pkt);
108
109    DPRINTF(MemCheckerMonitor,
110            "Forwarded functional access: addr = %#llx, size = %d\n",
111            addr, size);
112}
113
114void
115MemCheckerMonitor::recvFunctionalSnoop(PacketPtr pkt)
116{
117    Addr addr = pkt->getAddr();
118    unsigned size = pkt->getSize();
119
120    // See above.
121    memchecker->reset(addr, size);
122
123    slavePort.sendFunctionalSnoop(pkt);
124
125    DPRINTF(MemCheckerMonitor,
126            "Received functional snoop: addr = %#llx, size = %d\n",
127            addr, size);
128}
129
130Tick
131MemCheckerMonitor::recvAtomic(PacketPtr pkt)
132{
133    assert(false && "Atomic not supported");
134    return masterPort.sendAtomic(pkt);
135}
136
137Tick
138MemCheckerMonitor::recvAtomicSnoop(PacketPtr pkt)
139{
140    assert(false && "Atomic not supported");
141    return slavePort.sendAtomicSnoop(pkt);
142}
143
144bool
145MemCheckerMonitor::recvTimingReq(PacketPtr pkt)
146{
147    // should always see a request
148    assert(pkt->isRequest());
149
150    // Store relevant fields of packet, because packet may be modified
151    // or even deleted when sendTiming() is called.
152    //
153    // For reads we are only interested in real reads, and not prefetches, as
154    // it is not guaranteed that the prefetch returns any useful data.
155    bool is_read = pkt->isRead() && !pkt->req->isPrefetch();
156    bool is_write = pkt->isWrite();
157    unsigned size = pkt->getSize();
158    Addr addr = pkt->getAddr();
159    bool expects_response = pkt->needsResponse() && !pkt->cacheResponding();
160    std::unique_ptr<uint8_t> pkt_data;
161    MemCheckerMonitorSenderState* state = NULL;
162
163    if (expects_response && is_write) {
164        // On receipt of a request, only need to allocate pkt_data if this is a
165        // write. For reads, we have no data yet, so it doesn't make sense to
166        // allocate.
167        pkt_data.reset(new uint8_t[size]);
168        memcpy(pkt_data.get(), pkt->getConstPtr<uint8_t*>(), size);
169    }
170
171    // If a cache miss is served by a cache, a monitor near the memory
172    // would see a request which needs a response, but this response
173    // would not come back from the memory. Therefore
174    // we additionally have to check the inhibit flag.
175    if (expects_response && (is_read || is_write)) {
176        state = new MemCheckerMonitorSenderState(0);
177        pkt->pushSenderState(state);
178    }
179
180    // Attempt to send the packet
181    bool successful = masterPort.sendTimingReq(pkt);
182
183    // If not successful, restore the sender state
184    if (!successful && expects_response && (is_read || is_write)) {
185        delete pkt->popSenderState();
186    }
187
188    if (successful && expects_response) {
189        if (is_read) {
190            MemChecker::Serial serial = memchecker->startRead(curTick(),
191                                                              addr,
192                                                              size);
193
194            // At the time where we push the sender-state, we do not yet know
195            // the serial the MemChecker class will assign to this request. We
196            // cannot call startRead at the time we push the sender-state, as
197            // the masterPort may not be successful in executing sendTimingReq,
198            // and in case of a failure, we must not modify the state of the
199            // MemChecker.
200            //
201            // Once we know that sendTimingReq was successful, we can set the
202            // serial of the newly constructed sender-state. This is legal, as
203            // we know that nobody else will touch nor is responsible for
204            // deletion of our sender-state.
205            state->serial = serial;
206
207            DPRINTF(MemCheckerMonitor,
208                    "Forwarded read request: serial = %d, addr = %#llx, "
209                    "size = %d\n",
210                    serial, addr, size);
211        } else if (is_write) {
212            MemChecker::Serial serial = memchecker->startWrite(curTick(),
213                                                               addr,
214                                                               size,
215                                                               pkt_data.get());
216
217            state->serial = serial;
218
219            DPRINTF(MemCheckerMonitor,
220                    "Forwarded write request: serial = %d, addr = %#llx, "
221                    "size = %d\n",
222                    serial, addr, size);
223        } else {
224            DPRINTF(MemCheckerMonitor,
225                    "Forwarded non read/write request: addr = %#llx\n", addr);
226        }
227    } else if (successful) {
228        DPRINTF(MemCheckerMonitor,
229                "Forwarded request marked for cache response: addr = %#llx\n",
230                addr);
231    }
232
233    return successful;
234}
235
236bool
237MemCheckerMonitor::recvTimingResp(PacketPtr pkt)
238{
239    // should always see responses
240    assert(pkt->isResponse());
241
242    // Store relevant fields of packet, because packet may be modified
243    // or even deleted when sendTiming() is called.
244    bool is_read = pkt->isRead() && !pkt->req->isPrefetch();
245    bool is_write = pkt->isWrite();
246    bool is_failed_LLSC = pkt->isLLSC() && pkt->req->getExtraData() == 0;
247    unsigned size = pkt->getSize();
248    Addr addr = pkt->getAddr();
249    std::unique_ptr<uint8_t> pkt_data;
250    MemCheckerMonitorSenderState* received_state = NULL;
251
252    if (is_read) {
253        // On receipt of a response, only need to allocate pkt_data if this is
254        // a read. For writes, we have already given the MemChecker the data on
255        // the request, so it doesn't make sense to allocate on write.
256        pkt_data.reset(new uint8_t[size]);
257        memcpy(pkt_data.get(), pkt->getConstPtr<uint8_t*>(), size);
258    }
259
260    if (is_read || is_write) {
261        received_state =
262            dynamic_cast<MemCheckerMonitorSenderState*>(pkt->senderState);
263
264        // Restore initial sender state
265        panic_if(received_state == NULL,
266                 "Monitor got a response without monitor sender state\n");
267
268        // Restore the state
269        pkt->senderState = received_state->predecessor;
270    }
271
272    // Attempt to send the packet
273    bool successful = slavePort.sendTimingResp(pkt);
274
275    // If packet successfully send, complete transaction in MemChecker
276    // instance, and delete sender state, otherwise restore state.
277    if (successful) {
278        if (is_read) {
279            DPRINTF(MemCheckerMonitor,
280                    "Received read response: serial = %d, addr = %#llx, "
281                    "size = %d\n",
282                    received_state->serial, addr, size);
283
284            bool result = memchecker->completeRead(received_state->serial,
285                                                   curTick(),
286                                                   addr,
287                                                   size,
288                                                   pkt_data.get());
289
290            if (!result) {
291                warn("%s: read of %#llx @ cycle %d failed:\n%s\n",
292                     name(),
293                     addr, curTick(),
294                     memchecker->getErrorMessage().c_str());
295
296                panic_if(!warnOnly, "MemChecker violation!");
297            }
298
299            delete received_state;
300        } else if (is_write) {
301            DPRINTF(MemCheckerMonitor,
302                    "Received write response: serial = %d, addr = %#llx, "
303                    "size = %d\n",
304                    received_state->serial, addr, size);
305
306            if (is_failed_LLSC) {
307                // The write was not successful, let MemChecker know.
308                memchecker->abortWrite(received_state->serial,
309                                       addr,
310                                       size);
311            } else {
312                memchecker->completeWrite(received_state->serial,
313                                          curTick(),
314                                          addr,
315                                          size);
316            }
317
318            delete received_state;
319        } else {
320            DPRINTF(MemCheckerMonitor,
321                    "Received non read/write response: addr = %#llx\n", addr);
322        }
323    } else if (is_read || is_write) {
324        // Don't delete anything and let the packet look like we
325        // did not touch it
326        pkt->senderState = received_state;
327    }
328
329    return successful;
330}
331
332void
333MemCheckerMonitor::recvTimingSnoopReq(PacketPtr pkt)
334{
335    slavePort.sendTimingSnoopReq(pkt);
336}
337
338bool
339MemCheckerMonitor::recvTimingSnoopResp(PacketPtr pkt)
340{
341    return masterPort.sendTimingSnoopResp(pkt);
342}
343
344bool
345MemCheckerMonitor::isSnooping() const
346{
347    // check if the connected master port is snooping
348    return slavePort.isSnooping();
349}
350
351AddrRangeList
352MemCheckerMonitor::getAddrRanges() const
353{
354    // get the address ranges of the connected slave port
355    return masterPort.getAddrRanges();
356}
357
358void
359MemCheckerMonitor::recvReqRetry()
360{
361    slavePort.sendRetryReq();
362}
363
364void
365MemCheckerMonitor::recvRespRetry()
366{
367    masterPort.sendRetryResp();
368}
369
370void
371MemCheckerMonitor::recvRangeChange()
372{
373    slavePort.sendRangeChange();
374}
375