1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "gtest/gtest.h"
18 
19 #include "berberis/guest_state/guest_addr.h"
20 #include "berberis/guest_state/guest_state.h"
21 #include "berberis/runtime_primitives/memory_region_reservation.h"
22 
23 namespace berberis {
24 
25 namespace {
26 
27 static_assert(sizeof(Reservation) >= 8, "Reservation size is too small");
28 
TEST(MemoryRegionReservation,Smoke)29 TEST(MemoryRegionReservation, Smoke) {
30   CPUState cpu{};
31 
32   constexpr uint32_t kTestVal = 0xf1234567;
33 
34   Reservation reservation = kTestVal;
35 
36   GuestAddr addr = ToGuestAddr(&reservation) + sizeof(uint32_t);
37 
38   ASSERT_EQ(0u, MemoryRegionReservation::Load<uint32_t>(&cpu, addr, std::memory_order_seq_cst));
39 
40   ASSERT_EQ(
41       0u,
42       MemoryRegionReservation::Store<uint32_t>(&cpu, addr, kTestVal, std::memory_order_seq_cst));
43 
44   ASSERT_EQ(reservation, (Reservation(kTestVal) << 32) | kTestVal);
45 
46   ASSERT_EQ(
47       1u,
48       MemoryRegionReservation::Store<uint32_t>(&cpu, addr, ~kTestVal, std::memory_order_seq_cst));
49 
50   ASSERT_EQ(reservation, (Reservation(kTestVal) << 32) | kTestVal);
51 }
52 
TEST(MemoryRegionReservation,DoubleLoad)53 TEST(MemoryRegionReservation, DoubleLoad) {
54   CPUState cpu{};
55 
56   constexpr uint32_t kTestVal1 = 0xf1234567;
57   constexpr uint32_t kTestVal2 = 0xdeadbeef;
58 
59   Reservation reservation_1 = kTestVal1;
60   Reservation reservation_2 = kTestVal2;
61 
62   ASSERT_EQ(kTestVal1,
63             MemoryRegionReservation::Load<uint32_t>(
64                 &cpu, ToGuestAddr(&reservation_1), std::memory_order_seq_cst));
65 
66   ASSERT_EQ(kTestVal2,
67             MemoryRegionReservation::Load<uint32_t>(
68                 &cpu, ToGuestAddr(&reservation_2), std::memory_order_seq_cst));
69 
70   ASSERT_EQ(0u,
71             MemoryRegionReservation::Store<uint32_t>(
72                 &cpu, ToGuestAddr(&reservation_2), kTestVal1, std::memory_order_seq_cst));
73 
74   ASSERT_EQ(kTestVal1, reservation_1);
75   ASSERT_EQ(kTestVal1, reservation_2);
76 }
77 
TEST(MemoryRegionReservation,Steal)78 TEST(MemoryRegionReservation, Steal) {
79   CPUState cpu_1{};
80   CPUState cpu_2{};
81 
82   constexpr uint32_t kTestVal1 = 0xf1234567;
83   constexpr uint32_t kTestVal2 = 0xdeadbeef;
84   constexpr uint32_t kTestVal3 = 0xabcdefab;
85 
86   Reservation reservation = kTestVal1;
87 
88   ASSERT_EQ(kTestVal1,
89             MemoryRegionReservation::Load<uint32_t>(
90                 &cpu_1, ToGuestAddr(&reservation), std::memory_order_seq_cst));
91 
92   ASSERT_EQ(kTestVal1,
93             MemoryRegionReservation::Load<uint32_t>(
94                 &cpu_2, ToGuestAddr(&reservation), std::memory_order_seq_cst));
95 
96   ASSERT_EQ(1u,
97             MemoryRegionReservation::Store<uint32_t>(
98                 &cpu_1, ToGuestAddr(&reservation), kTestVal2, std::memory_order_seq_cst));
99 
100   ASSERT_EQ(0u,
101             MemoryRegionReservation::Store<uint32_t>(
102                 &cpu_2, ToGuestAddr(&reservation), kTestVal3, std::memory_order_seq_cst));
103 
104   ASSERT_EQ(kTestVal3, reservation);
105 }
106 
TEST(MemoryRegionReservation,StealEqual)107 TEST(MemoryRegionReservation, StealEqual) {
108   CPUState cpu_1{};
109   CPUState cpu_2{};
110 
111   constexpr uint32_t kTestVal1 = 0xf1234567;
112   constexpr uint32_t kTestVal2 = 0xdeadbeef;
113 
114   Reservation reservation = kTestVal1;
115 
116   ASSERT_EQ(kTestVal1,
117             MemoryRegionReservation::Load<uint32_t>(
118                 &cpu_1, ToGuestAddr(&reservation), std::memory_order_seq_cst));
119 
120   ASSERT_EQ(kTestVal1,
121             MemoryRegionReservation::Load<uint32_t>(
122                 &cpu_2, ToGuestAddr(&reservation), std::memory_order_seq_cst));
123 
124   ASSERT_EQ(0u,
125             MemoryRegionReservation::Store<uint32_t>(
126                 &cpu_2, ToGuestAddr(&reservation), kTestVal1, std::memory_order_seq_cst));
127 
128   ASSERT_EQ(1u,
129             MemoryRegionReservation::Store<uint32_t>(
130                 &cpu_1, ToGuestAddr(&reservation), kTestVal2, std::memory_order_seq_cst));
131 
132   ASSERT_EQ(kTestVal1, reservation);
133 }
134 
135 }  // namespace
136 
137 }  // namespace berberis
138