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