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 "faulty_memory_accesses.h"
18 
19 #include <cstdint>
20 #include <utility>
21 
22 #include "berberis/base/checks.h"
23 #include "berberis/runtime_primitives/recovery_code.h"
24 
25 namespace berberis {
26 
27 namespace {
28 
29 extern "C" FaultyLoadResult FaultyLoad8(const void*);
30 extern "C" FaultyLoadResult FaultyLoad16(const void*);
31 extern "C" FaultyLoadResult FaultyLoad32(const void*);
32 extern "C" FaultyLoadResult FaultyLoad64(const void*);
33 extern "C" char g_faulty_load_recovery;
34 
35 __asm__(
36     R"(
37    .globl FaultyLoad8
38    .balign 16
39 FaultyLoad8:
40    movzbl (%rdi), %eax
41    movl $0, %edx
42    ret
43 
44    .globl FaultyLoad16
45    .balign 16
46 FaultyLoad16:
47    movzwl (%rdi), %eax
48    movl $0, %edx
49    ret
50 
51    .globl FaultyLoad32
52    .balign 16
53 FaultyLoad32:
54    movl (%rdi), %eax
55    movl $0, %edx
56    ret
57 
58    .globl FaultyLoad64
59    .balign 16
60 FaultyLoad64:
61    movq (%rdi), %rax
62    movl $0, %edx
63    ret
64 
65    .globl g_faulty_load_recovery
66 g_faulty_load_recovery:
67    movl $1, %edx
68    ret
69 )");
70 
71 extern "C" bool FaultyStore8(void*, uint64_t);
72 extern "C" bool FaultyStore16(void*, uint64_t);
73 extern "C" bool FaultyStore32(void*, uint64_t);
74 extern "C" bool FaultyStore64(void*, uint64_t);
75 extern "C" char g_faulty_store_recovery;
76 
77 __asm__(
78     R"(
79    .globl FaultyStore8
80    .balign 16
81 FaultyStore8:
82    movb %sil, (%rdi)
83    movl $0, %eax
84    ret
85 
86    .globl FaultyStore16
87    .balign 16
88 FaultyStore16:
89    movw %si, (%rdi)
90    movl $0, %eax
91    ret
92 
93    .globl FaultyStore32
94    .balign 16
95 FaultyStore32:
96    movl %esi, (%rdi)
97    movl $0, %eax
98    ret
99 
100    .globl FaultyStore64
101    .balign 16
102 FaultyStore64:
103    movq %rsi, (%rdi)
104    movl $0, %eax
105    ret
106 
107    .globl g_faulty_store_recovery
108 g_faulty_store_recovery:
109    movl $1, %eax
110    ret
111 )");
112 
113 template <typename FaultyAccessPointer>
MakePairAdapter(FaultyAccessPointer fault_addr,void * recovery_addr)114 std::pair<uintptr_t, uintptr_t> MakePairAdapter(FaultyAccessPointer fault_addr,
115                                                 void* recovery_addr) {
116   return {reinterpret_cast<uintptr_t>(fault_addr), reinterpret_cast<uintptr_t>(recovery_addr)};
117 }
118 
119 }  // namespace
120 
FaultyLoad(const void * addr,uint8_t data_bytes)121 FaultyLoadResult FaultyLoad(const void* addr, uint8_t data_bytes) {
122   CHECK_LE(data_bytes, 8);
123 
124   FaultyLoadResult result;
125   switch (data_bytes) {
126     case 1:
127       result = FaultyLoad8(addr);
128       break;
129     case 2:
130       result = FaultyLoad16(addr);
131       break;
132     case 4:
133       result = FaultyLoad32(addr);
134       break;
135     case 8:
136       result = FaultyLoad64(addr);
137       break;
138     default:
139       LOG_ALWAYS_FATAL("Unexpected FaultyLoad access size");
140   }
141 
142   return result;
143 }
144 
FaultyStore(void * addr,uint8_t data_bytes,uint64_t value)145 bool FaultyStore(void* addr, uint8_t data_bytes, uint64_t value) {
146   CHECK_LE(data_bytes, 8);
147 
148   bool is_fault;
149   switch (data_bytes) {
150     case 1:
151       is_fault = FaultyStore8(addr, value);
152       break;
153     case 2:
154       is_fault = FaultyStore16(addr, value);
155       break;
156     case 4:
157       is_fault = FaultyStore32(addr, value);
158       break;
159     case 8:
160       is_fault = FaultyStore64(addr, value);
161       break;
162     default:
163       LOG_ALWAYS_FATAL("Unexpected FaultyLoad access size");
164   }
165 
166   return is_fault;
167 }
168 
AddFaultyMemoryAccessRecoveryCode()169 void AddFaultyMemoryAccessRecoveryCode() {
170   InitExtraRecoveryCodeUnsafe({
171       MakePairAdapter(&FaultyLoad8, &g_faulty_load_recovery),
172       MakePairAdapter(&FaultyLoad16, &g_faulty_load_recovery),
173       MakePairAdapter(&FaultyLoad32, &g_faulty_load_recovery),
174       MakePairAdapter(&FaultyLoad64, &g_faulty_load_recovery),
175       MakePairAdapter(&FaultyStore8, &g_faulty_store_recovery),
176       MakePairAdapter(&FaultyStore16, &g_faulty_store_recovery),
177       MakePairAdapter(&FaultyStore32, &g_faulty_store_recovery),
178       MakePairAdapter(&FaultyStore64, &g_faulty_store_recovery),
179   });
180 }
181 
FindFaultyMemoryAccessRecoveryAddrForTesting(void * fault_addr)182 void* FindFaultyMemoryAccessRecoveryAddrForTesting(void* fault_addr) {
183   if (fault_addr == &FaultyLoad8 || fault_addr == &FaultyLoad16 || fault_addr == &FaultyLoad32 ||
184       fault_addr == &FaultyLoad64) {
185     return &g_faulty_load_recovery;
186   }
187   if (fault_addr == &FaultyStore8 || fault_addr == &FaultyStore16 || fault_addr == &FaultyStore32 ||
188       fault_addr == &FaultyStore64) {
189     return &g_faulty_store_recovery;
190   }
191   return nullptr;
192 }
193 
194 }  // namespace berberis
195