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 #ifndef BERBERIS_GUEST_STATE_GUEST_STATE_ARCH_H_
18 #define BERBERIS_GUEST_STATE_GUEST_STATE_ARCH_H_
19
20 #include <array>
21 #include <atomic>
22 #include <cstdint>
23 #include <type_traits>
24
25 #include "berberis/base/config.h"
26 #include "berberis/base/dependent_false.h"
27 #include "berberis/base/macros.h"
28 #include "berberis/guest_state/guest_addr.h"
29 #include "berberis/guest_state/guest_state_opaque.h"
30 #include "native_bridge_support/riscv64/guest_state/guest_state_cpu_state.h"
31
32 namespace berberis {
33
34 enum class CsrName {
35 kFFlags = 0b00'00'0000'0001,
36 kFrm = 0b00'00'0000'0010,
37 kFCsr = 0b00'00'0000'0011,
38 kVstart = 0b00'00'0000'1000,
39 kVxsat = 0b00'00'0000'1001,
40 kVxrm = 0b00'00'0000'1010,
41 kVcsr = 0b00'00'0000'1111,
42 kCycle = 0b11'00'0000'0000,
43 kVl = 0b11'00'0010'0000,
44 kVtype = 0b11'00'0010'0001,
45 kVlenb = 0b11'00'0010'0010,
46 kMaxValue = 0b11'11'1111'1111,
47 };
48
49 // Only for CSRs listed below helper defines would be defined.
50 // Define BERBERIS_RISV64_PROCESS_CSR before use. It would receive three arguments:
51 // • CamelCaseName, suitable for functions and enums.
52 // • snake_case_name, suitable for fields of data structures.
53 // • mask value, suitable for masking operations during write to register.
54 #define BERBERIS_RISV64_PROCESS_SUPPORTED_CSRS \
55 BERBERIS_RISV64_PROCESS_CSR(Frm, frm, 0b111) \
56 BERBERIS_RISV64_PROCESS_CSR(Vstart, vstart, 0b01111111) \
57 BERBERIS_RISV64_PROCESS_CSR(Vcsr, vcsr, 0b111) \
58 BERBERIS_RISV64_PROCESS_CSR(Vl, vl, 0b11111111) \
59 BERBERIS_RISV64_PROCESS_CSR( \
60 Vtype, \
61 vtype, \
62 0b1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1'1'111'111)
63 // Only CSRs listed below will be processed. All others are treated as undefined instruction.
64 // Define BERBERIS_RISV64_PROCESS_CSR before use. It would receive three arguments (see above).
65 // Define BERBERIS_RISV64_PROCESS_NOSTORAGE_CSR. It would receive one argument.
66 #define BERBERIS_RISV64_PROCESS_ALL_SUPPORTED_CSRS \
67 BERBERIS_RISV64_PROCESS_SUPPORTED_CSRS \
68 BERBERIS_RISV64_PROCESS_NOSTORAGE_CSR(FCsr), BERBERIS_RISV64_PROCESS_NOSTORAGE_CSR(FFlags), \
69 BERBERIS_RISV64_PROCESS_NOSTORAGE_CSR(Vxsat), BERBERIS_RISV64_PROCESS_NOSTORAGE_CSR(Vxrm), \
70 BERBERIS_RISV64_PROCESS_NOSTORAGE_CSR(Cycle), BERBERIS_RISV64_PROCESS_NOSTORAGE_CSR(Vlenb)
71
72 static_assert(std::is_standard_layout_v<CPUState>);
73
74 constexpr uint32_t kNumGuestRegs = std::size(CPUState{}.x);
75 constexpr uint32_t kNumGuestFpRegs = std::size(CPUState{}.f);
76
77 template <uint8_t kIndex>
GetXReg(const CPUState & state)78 inline uint64_t GetXReg(const CPUState& state) {
79 static_assert(kIndex > 0);
80 static_assert(kIndex < std::size(CPUState{}.x));
81 return state.x[kIndex];
82 }
83
84 template <uint8_t kIndex>
85 inline void SetXReg(CPUState& state, uint64_t val) {
86 static_assert(kIndex > 0);
87 static_assert(kIndex < std::size(CPUState{}.x));
88 state.x[kIndex] = val;
89 }
90
91 template <uint8_t kIndex>
92 inline uint64_t GetFReg(const CPUState& state) {
93 static_assert((kIndex) < std::size(CPUState{}.f));
94 return state.f[kIndex];
95 }
96
97 template <uint8_t kIndex>
98 inline void SetFReg(CPUState& state, uint64_t val) {
99 static_assert((kIndex) < std::size(CPUState{}.f));
100 state.f[kIndex] = val;
101 }
102
103 enum class RegisterType {
104 kReg,
105 kFpReg,
106 };
107
108 template <RegisterType register_type, uint8_t kIndex>
109 inline auto GetReg(const CPUState& state) {
110 if constexpr (register_type == RegisterType::kReg) {
111 return GetXReg<kIndex>(state);
112 } else if constexpr (register_type == RegisterType::kFpReg) {
113 return GetFReg<kIndex>(state);
114 } else {
115 static_assert(kDependentValueFalse<register_type>, "Unsupported register type");
116 }
117 }
118
119 template <RegisterType register_type, uint8_t kIndex, typename Register>
120 inline auto SetReg(CPUState& state, Register val) {
121 if constexpr (register_type == RegisterType::kReg) {
122 return SetXReg<kIndex>(state, val);
123 } else if constexpr (register_type == RegisterType::kFpReg) {
124 return SetFReg<kIndex>(state, val);
125 } else {
126 static_assert(kDependentValueFalse<register_type>, "Unsupported register type");
127 }
128 }
129
130 class GuestThread;
131
132 struct ThreadState {
133 CPUState cpu;
134
135 // Scratch space for x87 use and MXCSR.
136 // These operations can only read/write values from memory for historical reasons.
137 alignas(config::kScratchAreaAlign) uint8_t intrinsics_scratch_area[config::kScratchAreaSize];
138
139 // Guest thread pointer.
140 GuestThread* thread;
141
142 // Keep pending signals status here for fast checking in generated code.
143 // Uses enum values from PendingSignalsStatus.
144 // TODO(b/28058920): Refactor into GuestThread.
145 std::atomic<uint_least8_t> pending_signals_status;
146
147 GuestThreadResidence residence;
148
149 // Arbitrary per-thread data added by instrumentation.
150 void* instrument_data;
151
152 // TODO(b/329463428): Consider removing this pointer and not having ThreadState and
153 // NativeBridgeGuestStateHeader in the same mapping. The latter possibly managed by GuestThread.
154 void* thread_state_storage;
155 };
156
157 template <CsrName>
158 class CsrField;
159
160 #define BERBERIS_RISV64_PROCESS_CSR(EnumName, field_name, field_mask) \
161 template <> \
162 class CsrField<CsrName::k##EnumName> { \
163 public: \
164 using Type = decltype(std::declval<CPUState>().field_name); \
165 static constexpr Type(CPUState::*Addr) = &CPUState::field_name; \
166 static constexpr size_t kOffset = offsetof(ThreadState, cpu.field_name); \
167 static constexpr Type kMask{field_mask}; \
168 };
169
170 BERBERIS_RISV64_PROCESS_SUPPORTED_CSRS
171 #undef BERBERIS_RISV64_PROCESS_CSR
172
173 template <CsrName kName>
174 using CsrFieldType = typename CsrField<kName>::Type;
175
176 template <CsrName kName>
177 inline constexpr CsrFieldType<kName>(CPUState::*CsrFieldAddr) = CsrField<kName>::Addr;
178
179 template <CsrName... kName, typename Processor>
180 bool ProcessCsrNameAsTemplateParameterImpl(CsrName name, Processor& processor) {
181 return ((kName == name ? processor.template operator()<kName>(), true : false) || ...);
182 }
183
184 template <CsrName kName>
185 inline constexpr size_t kCsrFieldOffset = CsrField<kName>::kOffset;
186
187 template <CsrName kName>
188 inline constexpr CsrFieldType<kName> kCsrMask = CsrField<kName>::kMask;
189
190 inline constexpr bool CsrWritable(CsrName name) {
191 return (static_cast<typename std::underlying_type_t<CsrName>>(name) & 0b11'00'0000'0000) !=
192 0b11'00'0000'0000;
193 }
194
195 template <typename Processor>
196 bool ProcessCsrNameAsTemplateParameter(CsrName name, Processor& processor) {
197 #define BERBERIS_RISV64_PROCESS_CSR(EnumName, field_name, field_mask) CsrName::k##EnumName,
198 #define BERBERIS_RISV64_PROCESS_NOSTORAGE_CSR(EnumName) CsrName::k##EnumName
199 return ProcessCsrNameAsTemplateParameterImpl<BERBERIS_RISV64_PROCESS_ALL_SUPPORTED_CSRS>(
200 name, processor);
201 #undef BERBERIS_RISV64_PROCESS_NOSTORAGE_CSR
202 #undef BERBERIS_RISV64_PROCESS_CSR
203 }
204
205 #undef BERBERIS_RISV64_PROCESS_ALL_SUPPORTED_CSRS
206 #undef BERBERIS_RISV64_PROCESS_SUPPORTED_CSRS
207
208 // The ABI names come from
209 // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc.
210
211 // Integer register ABI names.
212
213 constexpr uint8_t RA = 1; // Return address - caller saved.
214 constexpr uint8_t SP = 2; // Stack pointer - callee saved.
215 constexpr uint8_t GP = 3; // Global pointer.
216 constexpr uint8_t TP = 4; // Thread pointer.
217 constexpr uint8_t T0 = 5; // Temporary register 0 - caller saved.
218 constexpr uint8_t T1 = 6; // Temporary register 1 - caller saved.
219 constexpr uint8_t T2 = 7; // Temporary register 2 - caller saved.
220 constexpr uint8_t FP = 8; // Frame pointer - callee saved.
221 constexpr uint8_t S0 = 8; // Saved register 0 - callee saved.
222 constexpr uint8_t S1 = 9; // Saved register 1 - callee saved.
223 constexpr uint8_t A0 = 10; // Argument register / return value 0 - caller saved.
224 constexpr uint8_t A1 = 11; // Argument register / return value 1 - caller saved.
225 constexpr uint8_t A2 = 12; // Argument register 2 - caller saved.
226 constexpr uint8_t A3 = 13; // Argument register 3 - caller saved.
227 constexpr uint8_t A4 = 14; // Argument register 4 - caller saved.
228 constexpr uint8_t A5 = 15; // Argument register 5 - caller saved.
229 constexpr uint8_t A6 = 16; // Argument register 6 - caller saved.
230 constexpr uint8_t A7 = 17; // Argument register 7 - caller saved.
231 constexpr uint8_t S2 = 18; // Saved register 2 - callee saved.
232 constexpr uint8_t S3 = 19; // Saved register 3 - callee saved.
233 constexpr uint8_t S4 = 20; // Saved register 4 - callee saved.
234 constexpr uint8_t S5 = 21; // Saved register 5 - callee saved.
235 constexpr uint8_t S6 = 22; // Saved register 6 - callee saved.
236 constexpr uint8_t S7 = 23; // Saved register 7 - callee saved.
237 constexpr uint8_t S8 = 24; // Saved register 8 - callee saved.
238 constexpr uint8_t S9 = 25; // Saved register 9 - callee saved.
239 constexpr uint8_t S10 = 26; // Saved register 10 - callee saved.
240 constexpr uint8_t S11 = 27; // Saved register 11 - callee saved.
241 constexpr uint8_t T3 = 28; // Temporary register 3 - caller saved.
242 constexpr uint8_t T4 = 29; // Temporary register 4 - caller saved.
243 constexpr uint8_t T5 = 30; // Temporary register 5 - caller saved.
244 constexpr uint8_t T6 = 31; // Temporary register 6 - caller saved.
245
246 // Floating point register ABI names.
247
248 constexpr uint8_t FT0 = 0; // FP Temporary register 0 - caller saved.
249 constexpr uint8_t FT1 = 1; // FP Temporary register 1 - caller saved.
250 constexpr uint8_t FT2 = 2; // FP Temporary register 2 - caller saved.
251 constexpr uint8_t FT3 = 3; // FP Temporary register 3 - caller saved.
252 constexpr uint8_t FT4 = 4; // FP Temporary register 4 - caller saved.
253 constexpr uint8_t FT5 = 5; // FP Temporary register 5 - caller saved.
254 constexpr uint8_t FT6 = 6; // FP Temporary register 6 - caller saved.
255 constexpr uint8_t FT7 = 7; // FP Temporary register 7 - caller saved.
256 constexpr uint8_t FS0 = 8; // FP Saved register 0 - callee saved.
257 constexpr uint8_t FS1 = 9; // FP Saved register 1 - callee saved.
258 constexpr uint8_t FA0 = 10; // FP Argument register / return value 0 - caller saved.
259 constexpr uint8_t FA1 = 11; // FP Argument register / return value 1 - caller saved.
260 constexpr uint8_t FA2 = 12; // FP Argument register 2 - caller saved.
261 constexpr uint8_t FA3 = 13; // FP Argument register 3 - caller saved.
262 constexpr uint8_t FA4 = 14; // FP Argument register 4 - caller saved.
263 constexpr uint8_t FA5 = 15; // FP Argument register 5 - caller saved.
264 constexpr uint8_t FA6 = 16; // FP Argument register 6 - caller saved.
265 constexpr uint8_t FA7 = 17; // FP Argument register 7 - caller saved.
266 constexpr uint8_t FS2 = 18; // FP Saved register 2 - calle saved.
267 constexpr uint8_t FS3 = 19; // FP Saved register 3 - callee saved.
268 constexpr uint8_t FS4 = 20; // FP Saved register 4 - callee saved.
269 constexpr uint8_t FS5 = 21; // FP Saved register 5 - callee saved.
270 constexpr uint8_t FS6 = 22; // FP Saved register 6 - callee saved.
271 constexpr uint8_t FS7 = 23; // FP Saved register 7 - callee saved.
272 constexpr uint8_t FS8 = 24; // FP Saved register 8 - callee saved.
273 constexpr uint8_t FS9 = 25; // FP Saved register 9 - callee saved.
274 constexpr uint8_t FS10 = 26; // FP Saved register 10 - callee saved.
275 constexpr uint8_t FS11 = 27; // FP Saved register 11 - callee saved.
276 constexpr uint8_t FT8 = 28; // FP Temporary register 8 - caller saved.
277 constexpr uint8_t FT9 = 29; // FP Temporary register 9 - caller saved.
278 constexpr uint8_t FT10 = 30; // FP Temporary register 10 - caller saved.
279 constexpr uint8_t FT11 = 31; // FP Temporary register 11 - caller saved.
280
281 } // namespace berberis
282
283 #endif // BERBERIS_GUEST_STATE_GUEST_STATE_ARCH_H_
284