• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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