gem5  v20.1.0.0
proxy_ptr.test.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Google, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met: redistributions of source code must retain the above copyright
7  * notice, this list of conditions and the following disclaimer;
8  * redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in the
10  * documentation and/or other materials provided with the distribution;
11  * neither the name of the copyright holders nor the names of its
12  * contributors may be used to endorse or promote products derived from
13  * this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <gtest/gtest.h>
29 
30 #include <vector>
31 
32 #include "sim/proxy_ptr.hh"
33 
34 struct Access
35 {
36  bool read;
39 
40  Access(bool _read, Addr _addr, Addr _size) :
41  read(_read), addr(_addr), size(_size)
42  {}
43 
44  bool
45  operator == (const Access &other) const
46  {
47  return read == other.read &&
48  addr == other.addr &&
49  size == other.size;
50  }
51 
52  bool
53  operator != (const Access &other) const
54  {
55  return !(*this == other);
56  }
57 };
58 
60 
62 {
63  public:
66 
67  BackingStore(Addr _base, size_t _size) : store(_size, 0), base(_base) {}
68 
69  void
71  {
72  panic_if(addr < base || addr + size > base + store.size(),
73  "Range [%#x,%#x) outside of [%#x,%#x).",
74  addr, addr + size, base, base + store.size());
75  }
76 
77  mutable Accesses accesses;
78 
79  ::testing::AssertionResult
80  expect_access(size_t idx, const Access &other) const
81  {
82  if (idx >= accesses.size()) {
83  return ::testing::AssertionFailure() << "index " << idx <<
84  " out of bounds";
85  }
86 
87  if (accesses[idx] != other) {
88  return ::testing::AssertionFailure() << "access[" << idx <<
89  "] was " << accesses[idx] << ", expected " << other;
90  }
91  return ::testing::AssertionSuccess();
92  }
93 
94  ::testing::AssertionResult
96  {
97  if (accesses.size() != expected.size()) {
98  return ::testing::AssertionFailure() <<
99  "Wrong number of accesses, was " << accesses.size() <<
100  " expected " << expected.size();
101  }
102 
103  auto failure = ::testing::AssertionFailure();
104  bool success = true;
105  if (accesses.size() == expected.size()) {
106  for (size_t idx = 0; idx < expected.size(); idx++) {
107  auto result = expect_access(idx, expected[idx]);
108  if (!result) {
109  failure << result.message();
110  success = false;
111  }
112  }
113  }
114 
115  if (!success)
116  return failure;
117  else
118  return ::testing::AssertionSuccess();
119  }
120 
121  void
122  writeBlob(Addr ptr, const void *data, int size)
123  {
124  rangeCheck(ptr, size);
125  accesses.emplace_back(false, ptr, size);
126  memcpy(store.data() + (ptr - base), data, size);
127  }
128 
129  void
130  readBlob(Addr ptr, void *data, int size)
131  {
132  rangeCheck(ptr, size);
133  accesses.emplace_back(true, ptr, size);
134  memcpy(data, store.data() + (ptr - base), size);
135  }
136 };
137 
138 ::testing::AssertionResult
139 accessed(const char *expr1, const char *expr2,
140  const BackingStore &store, const Accesses &expected)
141 {
142  return store.expect_accesses(expected);
143 }
144 
145 #define EXPECT_ACCESSES(store, ...) \
146  do { \
147  Accesses expected({__VA_ARGS__}); \
148  EXPECT_PRED_FORMAT2(accessed, store, expected); \
149  store.accesses.clear(); \
150  } while (false)
151 
152 std::ostream &
153 operator << (std::ostream &os, const Access &access)
154 {
155  ccprintf(os, "%s(%#x, %d)", access.read ? "read" : "write",
156  access.addr, access.size);
157  return os;
158 }
159 
161 {
162  public:
164 
165  TestProxy(BackingStore &_store) : store(_store) {}
166  // Sneaky constructor for testing GuestABI integration.
168 
169  void
170  writeBlob(Addr ptr, const void *data, int size)
171  {
172  store.writeBlob(ptr, data, size);
173  }
174 
175  void
176  readBlob(Addr ptr, void *data, int size)
177  {
178  store.readBlob(ptr, data, size);
179  }
180 };
181 
182 template <typename T>
184 
185 template <typename T>
187 
188 TEST(ProxyPtr, Clean)
189 {
190  BackingStore store(0x1000, 0x1000);
191 
192  EXPECT_ACCESSES(store);
193 
194  {
195  ConstTestPtr<uint32_t> test_ptr(0x1100, store);
196 
197  EXPECT_ACCESSES(store, { true, test_ptr.addr(), sizeof(uint32_t) });
198  }
199 
200  EXPECT_ACCESSES(store);
201 
202  {
203  TestPtr<uint32_t> test_ptr(0x1100, store);
204 
205  EXPECT_ACCESSES(store, { true, test_ptr.addr(), sizeof(uint32_t) });
206  }
207 
208  EXPECT_ACCESSES(store);
209 }
210 
211 TEST(ProxyPtr, Dirty)
212 {
213  BackingStore store(0x1000, 0x1100);
214 
215  EXPECT_ACCESSES(store);
216 
217  {
218  TestPtr<uint32_t> test_ptr(0x1100, store);
219 
220  *test_ptr = 0xa5a5a5a5;
221 
222  EXPECT_ACCESSES(store, { true, test_ptr.addr(), sizeof(uint32_t) });
223  }
224 
225  EXPECT_ACCESSES(store, { false, 0x1100, sizeof(uint32_t) });
226  EXPECT_EQ(store.store[0x100], 0xa5);
227  EXPECT_EQ(store.store[0x101], 0xa5);
228  EXPECT_EQ(store.store[0x102], 0xa5);
229  EXPECT_EQ(store.store[0x103], 0xa5);
230 }
231 
232 
233 TEST(ProxyPtr, LoadAndFlush)
234 {
235  BackingStore store(0x1000, 0x1100);
236 
237  store.store[0x100] = 0xa5;
238  store.store[0x101] = 0xa5;
239  store.store[0x102] = 0xa5;
240  store.store[0x103] = 0xa5;
241 
242  TestPtr<uint32_t> test_ptr(0x1100, store);
243 
244  // Check that the backing store is unmodified.
245  EXPECT_EQ(store.store[0x100], 0xa5);
246  EXPECT_EQ(store.store[0x101], 0xa5);
247  EXPECT_EQ(store.store[0x102], 0xa5);
248  EXPECT_EQ(store.store[0x103], 0xa5);
249 
250  // Change the value in our local buffered copy.
251  *test_ptr = 0x5a5a5a5a;
252 
253  // Verify that the backing store hasn't been changed.
254  EXPECT_EQ(store.store[0x100], 0xa5);
255  EXPECT_EQ(store.store[0x101], 0xa5);
256  EXPECT_EQ(store.store[0x102], 0xa5);
257  EXPECT_EQ(store.store[0x103], 0xa5);
258 
259  // Flush out our modifications.
260  test_ptr.flush();
261 
262  // Verify that they've been written back to the store.
263  EXPECT_EQ(store.store[0x100], 0x5a);
264  EXPECT_EQ(store.store[0x101], 0x5a);
265  EXPECT_EQ(store.store[0x102], 0x5a);
266  EXPECT_EQ(store.store[0x103], 0x5a);
267 
268  // Update the store and try to flush again.
269  store.store[0x100] = 0xaa;
270  test_ptr.flush();
271 
272  // Verify that no flush happened, since our ptr was "clean".
273  EXPECT_EQ(store.store[0x100], 0xaa);
274 
275  // Force a flush.
276  test_ptr.flush(true);
277 
278  // Verify that the flush happened even though the ptr was "clean".
279  EXPECT_EQ(store.store[0x100], 0x5a);
280 
281  // Update the store.
282  store.store[0x100] = 0xa5;
283  store.store[0x101] = 0xa5;
284  store.store[0x102] = 0xa5;
285  store.store[0x103] = 0xa5;
286 
287  // Verify that our local copy hasn't changed.
288  EXPECT_EQ(*(const uint32_t *)test_ptr, 0x5a5a5a5a);
289 
290  // Reload the pointer from the store.
291  test_ptr.load();
292  EXPECT_EQ(*(const uint32_t *)test_ptr, 0xa5a5a5a5);
293 }
294 
295 TEST(ProxyPtr, ConstOperators)
296 {
297  bool is_same;
298 
299  BackingStore store(0x1000, 0x1000);
300 
301  const Addr addr1 = 0x1100;
302  const Addr addr2 = 0x1200;
303 
304  using PtrType = uint32_t;
305 
306  ConstTestPtr<PtrType> test_ptr1(addr1, store);
307  EXPECT_EQ(test_ptr1.addr(), addr1);
308 
309  ConstTestPtr<PtrType> test_ptr2(addr2, store);
310  EXPECT_EQ(test_ptr2.addr(), addr2);
311 
312  // Pointer +/- integer.
313  auto next_ptr = test_ptr1 + 2;
314  EXPECT_EQ(next_ptr.addr(), addr1 + 2 * sizeof(PtrType));
315 
316  auto reverse_next_ptr = 2 + test_ptr1;
317  EXPECT_EQ(reverse_next_ptr.addr(), addr1 + 2 * sizeof(PtrType));
318 
319  auto prev_ptr = test_ptr1 - 2;
320  EXPECT_EQ(prev_ptr.addr(), addr1 - 2 * sizeof(PtrType));
321 
322  // Pointer-pointer subtraction.
323  auto diff = test_ptr2 - test_ptr1;
324  EXPECT_EQ(diff, (addr2 - addr1) / sizeof(PtrType));
325 
326  // Assignment.
327  ConstTestPtr<PtrType> target(addr2, store);
328  EXPECT_EQ(target.addr(), addr2);
329 
330  target = test_ptr1;
331  EXPECT_EQ(target.addr(), addr1);
332 
333  // Conversions.
334  EXPECT_TRUE(test_ptr1);
335  ConstTestPtr<PtrType> null(0, store);
336  EXPECT_FALSE(null);
337 
338  EXPECT_NE((const PtrType *)test_ptr1, nullptr);
339  EXPECT_EQ((const PtrType *)null, nullptr);
340 
341  // Dereferences.
342  is_same = std::is_same<decltype(*test_ptr1), const PtrType &>::value;
343  EXPECT_TRUE(is_same);
344 
345  store.store[0x100] = 0x55;
346  store.store[0x101] = 0x55;
347  store.store[0x102] = 0x55;
348  store.store[0x103] = 0x55;
349 
350  // Force an update since we changed the backing store behind our ptrs back.
351  test_ptr1.load();
352 
353  EXPECT_EQ(*test_ptr1, 0x55555555);
354 
355  store.store[0x100] = 0x11;
356  store.store[0x101] = 0x22;
357  store.store[0x102] = 0x33;
358  store.store[0x103] = 0x44;
359 
360  struct TestStruct
361  {
362  uint8_t a;
363  uint8_t b;
364  uint8_t c;
365  uint8_t d;
366  };
367 
368  ConstTestPtr<TestStruct> struct_ptr(addr1, store);
369  EXPECT_EQ(struct_ptr->a, 0x11);
370  EXPECT_EQ(struct_ptr->b, 0x22);
371  EXPECT_EQ(struct_ptr->c, 0x33);
372  EXPECT_EQ(struct_ptr->d, 0x44);
373 
374  is_same = std::is_same<decltype((struct_ptr->a)), const uint8_t &>::value;
375  EXPECT_TRUE(is_same);
376 }
377 
378 TEST(ProxyPtr, NonConstOperators)
379 {
380  bool is_same;
381 
382  BackingStore store(0x1000, 0x1000);
383 
384  const Addr addr1 = 0x1100;
385  const Addr addr2 = 0x1200;
386 
387  using PtrType = uint32_t;
388 
389  TestPtr<PtrType> test_ptr1(addr1, store);
390  EXPECT_EQ(test_ptr1.addr(), addr1);
391 
392  TestPtr<PtrType> test_ptr2(addr2, store);
393  EXPECT_EQ(test_ptr2.addr(), addr2);
394 
395  // Pointer +/- integer.
396  auto next_ptr = test_ptr1 + 2;
397  EXPECT_EQ(next_ptr.addr(), addr1 + 2 * sizeof(PtrType));
398 
399  auto reverse_next_ptr = 2 + test_ptr1;
400  EXPECT_EQ(reverse_next_ptr.addr(), addr1 + 2 * sizeof(PtrType));
401 
402  auto prev_ptr = test_ptr1 - 2;
403  EXPECT_EQ(prev_ptr.addr(), addr1 - 2 * sizeof(PtrType));
404 
405  // Pointer-pointer subtraction.
406  auto diff = test_ptr2 - test_ptr1;
407  EXPECT_EQ(diff, (addr2 - addr1) / sizeof(PtrType));
408 
409  // Assignment.
410  TestPtr<PtrType> target(addr2, store);
411  EXPECT_EQ(target.addr(), addr2);
412 
413  target = test_ptr1;
414  EXPECT_EQ(target.addr(), addr1);
415 
416  // Conversions.
417  EXPECT_TRUE(test_ptr1);
418  TestPtr<PtrType> null(0, store);
419  EXPECT_FALSE(null);
420 
421  EXPECT_NE((PtrType *)test_ptr1, nullptr);
422  EXPECT_EQ((PtrType *)null, nullptr);
423  EXPECT_NE((const PtrType *)test_ptr1, nullptr);
424  EXPECT_EQ((const PtrType *)null, nullptr);
425 
426  // Dereferences.
427  is_same = std::is_same<decltype(*test_ptr1), PtrType &>::value;
428  EXPECT_TRUE(is_same);
429 
430  // Flush test_ptr1, which has been conservatively marked as dirty.
431  test_ptr1.flush();
432 
433  store.store[0x100] = 0x55;
434  store.store[0x101] = 0x55;
435  store.store[0x102] = 0x55;
436  store.store[0x103] = 0x55;
437 
438  // Force an update since we changed the backing store behind our ptrs back.
439  test_ptr1.load();
440 
441  EXPECT_EQ(*test_ptr1, 0x55555555);
442 
443  store.store[0x100] = 0x11;
444  store.store[0x101] = 0x22;
445  store.store[0x102] = 0x33;
446  store.store[0x103] = 0x44;
447 
448  struct TestStruct
449  {
450  uint8_t a;
451  uint8_t b;
452  uint8_t c;
453  uint8_t d;
454  };
455 
456  TestPtr<TestStruct> struct_ptr(addr1, store);
457  EXPECT_EQ(struct_ptr->a, 0x11);
458  EXPECT_EQ(struct_ptr->b, 0x22);
459  EXPECT_EQ(struct_ptr->c, 0x33);
460  EXPECT_EQ(struct_ptr->d, 0x44);
461 
462  is_same = std::is_same<decltype((struct_ptr->a)), uint8_t &>::value;
463  EXPECT_TRUE(is_same);
464 }
465 
466 struct TestABI
467 {
468  using State = int;
469 };
470 
471 namespace GuestABI
472 {
473 
474 template <>
476 {
477  static Addr
478  get(ThreadContext *tc, typename TestABI::State &state)
479  {
480  return 0x1000;
481  }
482 };
483 
484 }
485 
486 bool abiCalled = false;
487 bool abiCalledConst = false;
488 
489 void
491 {
492  abiCalled = true;
493  EXPECT_EQ(ptr.addr(), 0x1000);
494 }
495 
496 void
498 {
499  abiCalledConst = true;
500  EXPECT_EQ(ptr.addr(), 0x1000);
501 }
502 
504 {
505  BackingStore store(0x1000, 0x1000);
506 
509 
510  invokeSimcall<TestABI>((ThreadContext *)&store, abiTestFunc);
511 
514 
515  invokeSimcall<TestABI>((ThreadContext *)&store, abiTestFuncConst);
516 
519 }
GuestABI::Argument< TestABI, Addr >::get
static Addr get(ThreadContext *tc, typename TestABI::State &state)
Definition: proxy_ptr.test.cc:478
TEST
TEST(ProxyPtr, Clean)
Definition: proxy_ptr.test.cc:188
X86ISA::os
Bitfield< 17 > os
Definition: misc.hh:803
TestProxy::readBlob
void readBlob(Addr ptr, void *data, int size)
Definition: proxy_ptr.test.cc:176
data
const char data[]
Definition: circlebuf.test.cc:42
ConstProxyPtr
Definition: proxy_ptr.hh:106
BackingStore::expect_access
::testing::AssertionResult expect_access(size_t idx, const Access &other) const
Definition: proxy_ptr.test.cc:80
BackingStore
Definition: proxy_ptr.test.cc:61
ProxyPtr
Definition: proxy_ptr.hh:236
Access::Access
Access(bool _read, Addr _addr, Addr _size)
Definition: proxy_ptr.test.cc:40
ProxyPtr::flush
void flush(bool force=false)
Definition: proxy_ptr.hh:262
BackingStore::expect_accesses
::testing::AssertionResult expect_accesses(Accesses expected) const
Definition: proxy_ptr.test.cc:95
BackingStore::BackingStore
BackingStore(Addr _base, size_t _size)
Definition: proxy_ptr.test.cc:67
std::vector< Access >
proxy_ptr.hh
TestProxy::TestProxy
TestProxy(BackingStore &_store)
Definition: proxy_ptr.test.cc:165
TestProxy::store
BackingStore & store
Definition: proxy_ptr.test.cc:163
EXPECT_EQ
#define EXPECT_EQ(lhs, rhs)
A macro which verifies that lhs and rhs are equal to each other.
Definition: unittest.hh:110
Access
Definition: proxy_ptr.test.cc:34
EXPECT_FALSE
#define EXPECT_FALSE(expr)
A macro which verifies that expr evaluates to false.
Definition: unittest.hh:106
BackingStore::writeBlob
void writeBlob(Addr ptr, const void *data, int size)
Definition: proxy_ptr.test.cc:122
Access::operator!=
bool operator!=(const Access &other) const
Definition: proxy_ptr.test.cc:53
ArmISA::a
Bitfield< 8 > a
Definition: miscregs_types.hh:62
ThreadContext
ThreadContext is the external interface to all thread state for anything outside of the CPU.
Definition: thread_context.hh:88
GuestABI
Definition: aapcs32.hh:66
operator<<
std::ostream & operator<<(std::ostream &os, const Access &access)
Definition: proxy_ptr.test.cc:153
ArmISA::d
Bitfield< 9 > d
Definition: miscregs_types.hh:60
EXPECT_TRUE
#define EXPECT_TRUE(expr)
A macro which verifies that expr evaluates to true.
Definition: unittest.hh:103
GuestABI::Argument
Definition: definition.hh:93
TestProxy::TestProxy
TestProxy(ThreadContext *tc)
Definition: proxy_ptr.test.cc:167
BackingStore::accesses
Accesses accesses
Definition: proxy_ptr.test.cc:77
EXPECT_ACCESSES
#define EXPECT_ACCESSES(store,...)
Definition: proxy_ptr.test.cc:145
ConstProxyPtr::addr
Addr addr() const
Definition: proxy_ptr.hh:170
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
abiTestFuncConst
void abiTestFuncConst(ThreadContext *tc, ConstTestPtr< uint8_t > ptr)
Definition: proxy_ptr.test.cc:497
Access::addr
Addr addr
Definition: proxy_ptr.test.cc:37
TestProxy::writeBlob
void writeBlob(Addr ptr, const void *data, int size)
Definition: proxy_ptr.test.cc:170
abiTestFunc
void abiTestFunc(ThreadContext *tc, TestPtr< uint8_t > ptr)
Definition: proxy_ptr.test.cc:490
panic_if
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:197
Access::operator==
bool operator==(const Access &other) const
Definition: proxy_ptr.test.cc:45
TestABI::State
int State
Definition: proxy_ptr.test.cc:468
ArmISA::b
Bitfield< 7 > b
Definition: miscregs_types.hh:376
abiCalled
bool abiCalled
Definition: proxy_ptr.test.cc:486
Access::size
Addr size
Definition: proxy_ptr.test.cc:38
addr
ip6_addr_t addr
Definition: inet.hh:423
ccprintf
void ccprintf(cp::Print &print)
Definition: cprintf.hh:127
TestProxy
Definition: proxy_ptr.test.cc:160
accessed
::testing::AssertionResult accessed(const char *expr1, const char *expr2, const BackingStore &store, const Accesses &expected)
Definition: proxy_ptr.test.cc:139
ArmISA::c
Bitfield< 29 > c
Definition: miscregs_types.hh:50
BackingStore::store
std::vector< uint8_t > store
Definition: proxy_ptr.test.cc:64
Access::read
bool read
Definition: proxy_ptr.test.cc:36
BackingStore::readBlob
void readBlob(Addr ptr, void *data, int size)
Definition: proxy_ptr.test.cc:130
TestABI
Definition: proxy_ptr.test.cc:466
abiCalledConst
bool abiCalledConst
Definition: proxy_ptr.test.cc:487
BackingStore::base
Addr base
Definition: proxy_ptr.test.cc:65
BackingStore::rangeCheck
void rangeCheck(Addr addr, Addr size)
Definition: proxy_ptr.test.cc:70
expected
std::vector< SwitchingFiber * > expected({ &a, &b, &a, &a, &a, &b, &c, &a, &c, &c, &c })

Generated on Wed Sep 30 2020 14:02:14 for gem5 by doxygen 1.8.17