2 * Copyright (c) 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.
43 #include "mem/mem_checker.hh"
46 MemChecker::WriteCluster::startWrite(MemChecker::Serial serial
, Tick _start
,
49 assert(!isComplete());
51 if (start
== TICK_FUTURE
) {
52 // Initialize a fresh write cluster
55 chatty_assert(start
<= _start
, "WriteClusters must filled in order!");
59 if (complete
!= TICK_FUTURE
) {
60 // Reopen a closed write cluster
61 assert(_start
< complete
); // should open a new write cluster, instead;
62 // also somewhat fishy wrt causality / ordering of calls vs time
63 // progression TODO: Check me!
64 complete
= TICK_FUTURE
;
67 // Create new transaction, and denote completion time to be in the future.
68 writes
.insert(std::make_pair(serial
,
69 MemChecker::Transaction(serial
, _start
, TICK_FUTURE
, data
)));
73 MemChecker::WriteCluster::completeWrite(MemChecker::Serial serial
, Tick _complete
)
75 auto it
= writes
.find(serial
);
77 if (it
== writes
.end()) {
78 warn("Could not locate write transaction: serial = %d, complete = %d\n",
83 // Record completion time of the write
84 assert(it
->second
.complete
== TICK_FUTURE
);
85 it
->second
.complete
= _complete
;
87 // Update max completion time for the cluster
88 if (completeMax
< _complete
) {
89 completeMax
= _complete
;
92 if (--numIncomplete
== 0) {
93 // All writes have completed, this cluster is now complete and will be
94 // assigned the max of completion tick values among all writes.
96 // Note that we cannot simply keep updating complete, because that would
97 // count the cluster as closed already. Instead, we keep TICK_FUTURE
98 // until all writes have completed.
99 complete
= completeMax
;
104 MemChecker::WriteCluster::abortWrite(MemChecker::Serial serial
)
106 if (!writes
.erase(serial
)) {
107 warn("Could not locate write transaction: serial = %d\n", serial
);
111 if (--numIncomplete
== 0 && !writes
.empty()) {
112 // This write cluster is now complete, and we can assign the current
113 // completeMax value.
114 complete
= completeMax
;
117 // Note: this WriteCluster is in pristine state if this was the only
118 // write present; the cluster will get reused through
119 // getIncompleteWriteCluster().
123 MemChecker::ByteTracker::startRead(MemChecker::Serial serial
, Tick start
)
125 outstandingReads
.insert(std::make_pair(serial
,
126 MemChecker::Transaction(serial
, start
, TICK_FUTURE
)));
130 MemChecker::ByteTracker::inExpectedData(Tick start
, Tick complete
, uint8_t data
)
132 _lastExpectedData
.clear();
134 bool wc_overlap
= true;
136 // Find the last value read from the location
137 const Transaction
& last_obs
=
138 *lastCompletedTransaction(&readObservations
, start
);
139 bool last_obs_valid
= (last_obs
.complete
!= TICK_INITIAL
);
141 // Scan backwards through the write clusters to find the closest younger
142 // preceding & overlapping writes.
143 for (auto cluster
= writeClusters
.rbegin();
144 cluster
!= writeClusters
.rend() && wc_overlap
; ++cluster
) {
145 for (const auto& addr_write
: cluster
->writes
) {
146 const Transaction
& write
= addr_write
.second
;
148 if (write
.complete
< last_obs
.start
) {
149 // If this write transaction completed before the last
150 // observation, we ignore it as the last_observation has the
155 if (write
.data
== data
) {
156 // Found a match, end search.
160 // Record possible, but non-matching data for debugging
161 _lastExpectedData
.push_back(write
.data
);
163 if (write
.complete
> start
) {
164 // This write overlapped with the transaction we want to check
165 // -> continue checking the overlapping write cluster
169 // This write cluster has writes that have completed before the
170 // checked transaction. There is no need to check an earlier
171 // write-cluster -> set the exit condition for the outer loop
174 if (last_obs
.complete
< write
.start
) {
175 // We found a write which started after the last observed read,
176 // therefore we can not longer consider the value seen by the
177 // last observation as a valid expected value.
179 // Once all writes have been iterated through, we can check if
180 // the last observation is still valid to compare against.
181 last_obs_valid
= false;
186 // We have not found any matching write, so far; check other sources of
188 if (last_obs_valid
) {
189 // The last observation is not outdated according to the writes we have
191 assert(last_obs
.complete
<= start
);
192 if (last_obs
.data
== data
) {
193 // Matched data from last observation -> all good
196 // Record non-matching, but possible value
197 _lastExpectedData
.push_back(last_obs
.data
);
199 // We have not seen any valid observation, and the only writes
200 // observed are overlapping, so anything (in particular the
201 // initialisation value) goes
202 // NOTE: We can overlap with multiple write clusters, here
203 if (!writeClusters
.empty() && wc_overlap
) {
204 // ensure that all write clusters really overlap this read
205 assert(writeClusters
.begin()->start
< complete
&&
206 writeClusters
.rbegin()->complete
> start
);
211 if (_lastExpectedData
.empty()) {
212 assert(last_obs
.complete
== TICK_INITIAL
);
213 // We have not found any possible (non-matching data). Can happen in
214 // initial system state
215 DPRINTF(MemChecker
, "no last observation nor write! start = %d, "\
216 "complete = %d, data = %#x\n", start
, complete
, data
);
223 MemChecker::ByteTracker::completeRead(MemChecker::Serial serial
,
224 Tick complete
, uint8_t data
)
226 auto it
= outstandingReads
.find(serial
);
228 if (it
== outstandingReads
.end()) {
229 // Can happen if concurrent with reset_address_range
230 warn("Could not locate read transaction: serial = %d, complete = %d\n",
235 Tick start
= it
->second
.start
;
236 outstandingReads
.erase(it
);
239 const bool result
= inExpectedData(start
, complete
, data
);
241 readObservations
.emplace_back(serial
, start
, complete
, data
);
247 MemChecker::WriteCluster
*
248 MemChecker::ByteTracker::getIncompleteWriteCluster()
250 if (writeClusters
.empty() || writeClusters
.back().isComplete()) {
251 writeClusters
.emplace_back();
254 return &writeClusters
.back();
258 MemChecker::ByteTracker::startWrite(MemChecker::Serial serial
, Tick start
,
261 getIncompleteWriteCluster()->startWrite(serial
, start
, data
);
265 MemChecker::ByteTracker::completeWrite(MemChecker::Serial serial
, Tick complete
)
267 getIncompleteWriteCluster()->completeWrite(serial
, complete
);
272 MemChecker::ByteTracker::abortWrite(MemChecker::Serial serial
)
274 getIncompleteWriteCluster()->abortWrite(serial
);
278 MemChecker::ByteTracker::pruneTransactions()
280 // Obtain tick of first outstanding read. If there are no outstanding
281 // reads, we use curTick(), i.e. we will remove all readObservation except
282 // the most recent one.
283 const Tick before
= outstandingReads
.empty() ? curTick() :
284 outstandingReads
.begin()->second
.start
;
286 // Pruning of readObservations
287 readObservations
.erase(readObservations
.begin(),
288 lastCompletedTransaction(&readObservations
, before
));
290 // Pruning of writeClusters
291 if (!writeClusters
.empty()) {
292 writeClusters
.erase(writeClusters
.begin(),
293 lastCompletedTransaction(&writeClusters
, before
));
298 MemChecker::completeRead(MemChecker::Serial serial
, Tick complete
,
299 Addr addr
, size_t size
, uint8_t *data
)
304 "completing read: serial = %d, complete = %d, "
305 "addr = %#llx, size = %d\n", serial
, complete
, addr
, size
);
307 for (size_t i
= 0; i
< size
; ++i
) {
308 ByteTracker
*tracker
= getByteTracker(addr
+ i
);
310 if (!tracker
->completeRead(serial
, complete
, data
[i
])) {
311 // Generate error message, and aggregate all failures for the bytes
312 // considered in this transaction in one message.
317 errorMessage
+= "\n";
320 errorMessage
+= csprintf(" Read transaction for address %#llx "
321 "failed: received %#x, expected ",
322 (unsigned long long)(addr
+ i
), data
[i
]);
324 for (size_t j
= 0; j
< tracker
->lastExpectedData().size(); ++j
) {
327 tracker
->lastExpectedData()[j
],
328 (j
== tracker
->lastExpectedData().size() - 1)
335 DPRINTF(MemChecker
, "read of %#llx @ cycle %d failed:\n%s\n", addr
,
336 complete
, errorMessage
);
343 MemChecker::reset(Addr addr
, size_t size
)
345 for (size_t i
= 0; i
< size
; ++i
) {
346 byte_trackers
.erase(addr
+ i
);
351 MemCheckerParams::create()
353 return new MemChecker(this);