2 * Copyright (c) 2012-2014 ARM Limited
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.
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.
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.
38 #include "mem/mem_checker_monitor.hh"
42 #include "base/logging.hh"
43 #include "base/output.hh"
44 #include "base/trace.hh"
45 #include "debug/MemCheckerMonitor.hh"
47 MemCheckerMonitor::MemCheckerMonitor(const Params
¶ms
)
49 memSidePort(name() + "-memSidePort", *this),
50 cpuSidePort(name() + "-cpuSidePort", *this),
51 warnOnly(params
.warn_only
),
52 memchecker(params
.memchecker
)
55 MemCheckerMonitor::~MemCheckerMonitor()
59 MemCheckerMonitor::init()
61 // make sure both sides of the monitor are connected
62 if (!cpuSidePort
.isConnected() || !memSidePort
.isConnected())
63 fatal("Communication monitor is not connected on both sides.\n");
67 MemCheckerMonitor::getPort(const std::string
&if_name
, PortID idx
)
69 if (if_name
== "request" || if_name
== "mem_side_port") {
71 } else if (if_name
== "response" || if_name
== "cpu_side_port") {
74 return SimObject::getPort(if_name
, idx
);
79 MemCheckerMonitor::recvFunctional(PacketPtr pkt
)
81 Addr addr
= pkt
->getAddr();
82 unsigned size
= pkt
->getSize();
84 // Conservatively reset this address-range. Alternatively we could try to
85 // update the values seen by the memchecker, however, there may be other
86 // reads/writes to these location from other devices we do not see.
87 memchecker
->reset(addr
, size
);
89 memSidePort
.sendFunctional(pkt
);
91 DPRINTF(MemCheckerMonitor
,
92 "Forwarded functional access: addr = %#llx, size = %d\n",
97 MemCheckerMonitor::recvFunctionalSnoop(PacketPtr pkt
)
99 Addr addr
= pkt
->getAddr();
100 unsigned size
= pkt
->getSize();
103 memchecker
->reset(addr
, size
);
105 cpuSidePort
.sendFunctionalSnoop(pkt
);
107 DPRINTF(MemCheckerMonitor
,
108 "Received functional snoop: addr = %#llx, size = %d\n",
113 MemCheckerMonitor::recvAtomic(PacketPtr pkt
)
115 panic("Atomic not supported");
119 MemCheckerMonitor::recvAtomicSnoop(PacketPtr pkt
)
121 panic("Atomic not supported");
125 MemCheckerMonitor::recvTimingReq(PacketPtr pkt
)
127 // should always see a request
128 assert(pkt
->isRequest());
130 // Store relevant fields of packet, because packet may be modified
131 // or even deleted when sendTiming() is called.
133 // For reads we are only interested in real reads, and not prefetches, as
134 // it is not guaranteed that the prefetch returns any useful data.
135 bool is_read
= pkt
->isRead() && !pkt
->req
->isPrefetch();
136 bool is_write
= pkt
->isWrite();
137 unsigned size
= pkt
->getSize();
138 Addr addr
= pkt
->getAddr();
139 bool expects_response
= pkt
->needsResponse() && !pkt
->cacheResponding();
140 std::unique_ptr
<uint8_t[]> pkt_data
;
141 MemCheckerMonitorSenderState
* state
= NULL
;
143 if (expects_response
&& is_write
) {
144 // On receipt of a request, only need to allocate pkt_data if this is a
145 // write. For reads, we have no data yet, so it doesn't make sense to
147 pkt_data
.reset(new uint8_t[size
]);
148 pkt
->writeData(pkt_data
.get());
151 // If a cache miss is served by a cache, a monitor near the memory
152 // would see a request which needs a response, but this response
153 // would not come back from the memory. Therefore
154 // we additionally have to check the inhibit flag.
155 if (expects_response
&& (is_read
|| is_write
)) {
156 state
= new MemCheckerMonitorSenderState(0);
157 pkt
->pushSenderState(state
);
160 // Attempt to send the packet
161 bool successful
= memSidePort
.sendTimingReq(pkt
);
163 // If not successful, restore the sender state
164 if (!successful
&& expects_response
&& (is_read
|| is_write
)) {
165 delete pkt
->popSenderState();
168 if (successful
&& expects_response
) {
170 MemChecker::Serial serial
= memchecker
->startRead(curTick(),
174 // At the time where we push the sender-state, we do not yet know
175 // the serial the MemChecker class will assign to this request. We
176 // cannot call startRead at the time we push the sender-state, as
177 // the memSidePort may not be successful in executing
178 // sendTimingReq, and in case of a failure, we must not
179 // modify the state of the MemChecker.
181 // Once we know that sendTimingReq was successful, we can set the
182 // serial of the newly constructed sender-state. This is legal, as
183 // we know that nobody else will touch nor is responsible for
184 // deletion of our sender-state.
185 state
->serial
= serial
;
187 DPRINTF(MemCheckerMonitor
,
188 "Forwarded read request: serial = %d, addr = %#llx, "
191 } else if (is_write
) {
192 MemChecker::Serial serial
= memchecker
->startWrite(curTick(),
197 state
->serial
= serial
;
199 DPRINTF(MemCheckerMonitor
,
200 "Forwarded write request: serial = %d, addr = %#llx, "
204 DPRINTF(MemCheckerMonitor
,
205 "Forwarded non read/write request: addr = %#llx\n", addr
);
207 } else if (successful
) {
208 DPRINTF(MemCheckerMonitor
,
209 "Forwarded request marked for cache response: addr = %#llx\n",
217 MemCheckerMonitor::recvTimingResp(PacketPtr pkt
)
219 // should always see responses
220 assert(pkt
->isResponse());
222 // Store relevant fields of packet, because packet may be modified
223 // or even deleted when sendTiming() is called.
224 bool is_read
= pkt
->isRead() && !pkt
->req
->isPrefetch();
225 bool is_write
= pkt
->isWrite();
226 bool is_failed_LLSC
= pkt
->isLLSC() && pkt
->req
->getExtraData() == 0;
227 unsigned size
= pkt
->getSize();
228 Addr addr
= pkt
->getAddr();
229 std::unique_ptr
<uint8_t[]> pkt_data
;
230 MemCheckerMonitorSenderState
* received_state
= NULL
;
233 // On receipt of a response, only need to allocate pkt_data if this is
234 // a read. For writes, we have already given the MemChecker the data on
235 // the request, so it doesn't make sense to allocate on write.
236 pkt_data
.reset(new uint8_t[size
]);
237 pkt
->writeData(pkt_data
.get());
240 if (is_read
|| is_write
) {
242 dynamic_cast<MemCheckerMonitorSenderState
*>(pkt
->senderState
);
244 // Restore initial sender state
245 panic_if(received_state
== NULL
,
246 "Monitor got a response without monitor sender state\n");
249 pkt
->senderState
= received_state
->predecessor
;
252 // Attempt to send the packet
253 bool successful
= cpuSidePort
.sendTimingResp(pkt
);
255 // If packet successfully send, complete transaction in MemChecker
256 // instance, and delete sender state, otherwise restore state.
259 DPRINTF(MemCheckerMonitor
,
260 "Received read response: serial = %d, addr = %#llx, "
262 received_state
->serial
, addr
, size
);
264 bool result
= memchecker
->completeRead(received_state
->serial
,
271 warn("%s: read of %#llx @ cycle %d failed:\n%s\n",
274 memchecker
->getErrorMessage().c_str());
276 panic_if(!warnOnly
, "MemChecker violation!");
279 delete received_state
;
280 } else if (is_write
) {
281 DPRINTF(MemCheckerMonitor
,
282 "Received write response: serial = %d, addr = %#llx, "
284 received_state
->serial
, addr
, size
);
286 if (is_failed_LLSC
) {
287 // The write was not successful, let MemChecker know.
288 memchecker
->abortWrite(received_state
->serial
,
292 memchecker
->completeWrite(received_state
->serial
,
298 delete received_state
;
300 DPRINTF(MemCheckerMonitor
,
301 "Received non read/write response: addr = %#llx\n", addr
);
303 } else if (is_read
|| is_write
) {
304 // Don't delete anything and let the packet look like we
306 pkt
->senderState
= received_state
;
313 MemCheckerMonitor::recvTimingSnoopReq(PacketPtr pkt
)
315 cpuSidePort
.sendTimingSnoopReq(pkt
);
319 MemCheckerMonitor::recvTimingSnoopResp(PacketPtr pkt
)
321 return memSidePort
.sendTimingSnoopResp(pkt
);
325 MemCheckerMonitor::isSnooping() const
327 // check if the connected memSidePort is snooping
328 return cpuSidePort
.isSnooping();
332 MemCheckerMonitor::getAddrRanges() const
334 // get the address ranges of the connected cpuSidePort
335 return memSidePort
.getAddrRanges();
339 MemCheckerMonitor::recvReqRetry()
341 cpuSidePort
.sendRetryReq();
345 MemCheckerMonitor::recvRespRetry()
347 memSidePort
.sendRetryResp();
351 MemCheckerMonitor::recvRangeChange()
353 cpuSidePort
.sendRangeChange();