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