• 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_RISCV64_H_
18 #define BERBERIS_GUEST_STATE_GUEST_STATE_RISCV64_H_
19 
20 #include <cstdint>
21 
22 #include "berberis/base/dependent_false.h"
23 #include "berberis/base/macros.h"
24 #include "berberis/guest_state/guest_addr.h"
25 
26 namespace berberis {
27 
28 struct CPUState {
29   // x1 to x31.
30   uint64_t x[31];
31   // f0 to f31. We are using uint64_t because C++ may change values of NaN when they are passed from
32   // or to function and RISC-V uses NaN-boxing which would make things problematic.
33   uint64_t f[32];
34   // RISC-V has five rounding modes, while x86-64 has only four.
35   //
36   // Extra rounding mode (RMM in RISC-V documentation) is emulated but requires the use of
37   // FE_TOWARDZERO mode for correct work.
38   //
39   // Additionally RISC-V implementation is supposed to support three “illegal” rounding modes and
40   // when they are selected all instructions which use rounding mode trigger “undefined instruction”
41   // exception.
42   //
43   // For simplicity we always keep full rounding mode (3 bits) in the frm field and set host
44   // rounding mode to appropriate one.
45   //
46   // Exceptions, on the other hand, couldn't be stored here efficiently, instead we rely on the fact
47   // that x86-64 implements all five exceptions that RISC-V needs (and more).
48   uint8_t frm : 3;
49   GuestAddr insn_addr;
50 };
51 
52 template <uint8_t kIndex>
GetXReg(const CPUState & state)53 inline uint64_t GetXReg(const CPUState& state) {
54   static_assert(kIndex > 0);
55   static_assert((kIndex - 1) < arraysize(state.x));
56   return state.x[kIndex - 1];
57 }
58 
59 template <uint8_t kIndex>
SetXReg(CPUState & state,uint64_t val)60 inline void SetXReg(CPUState& state, uint64_t val) {
61   static_assert(kIndex > 0);
62   static_assert((kIndex - 1) < arraysize(state.x));
63   state.x[kIndex - 1] = val;
64 }
65 
66 template <uint8_t kIndex>
GetFReg(const CPUState & state)67 inline uint64_t GetFReg(const CPUState& state) {
68   static_assert((kIndex) < arraysize(state.f));
69   return state.f[kIndex];
70 }
71 
72 template <uint8_t kIndex>
SetFReg(CPUState & state,uint64_t val)73 inline void SetFReg(CPUState& state, uint64_t val) {
74   static_assert((kIndex) < arraysize(state.f));
75   state.f[kIndex] = val;
76 }
77 
78 enum class RegisterType {
79   kReg,
80   kFpReg,
81 };
82 
83 template <RegisterType register_type, uint8_t kIndex>
GetReg(const CPUState & state)84 inline auto GetReg(const CPUState& state) {
85   if constexpr (register_type == RegisterType::kReg) {
86     return GetXReg<kIndex>(state);
87   } else if constexpr (register_type == RegisterType::kFpReg) {
88     return GetFReg<kIndex>(state);
89   } else {
90     static_assert(kDependentValueFalse<register_type>, "Unsupported register type");
91   }
92 }
93 
94 template <RegisterType register_type, uint8_t kIndex, typename Register>
SetReg(CPUState & state,Register val)95 inline auto SetReg(CPUState& state, Register val) {
96   if constexpr (register_type == RegisterType::kReg) {
97     return SetXReg<kIndex>(state, val);
98   } else if constexpr (register_type == RegisterType::kFpReg) {
99     return SetFReg<kIndex>(state, val);
100   } else {
101     static_assert(kDependentValueFalse<register_type>, "Unsupported register type");
102   }
103 }
104 
105 struct ThreadState {
106   CPUState cpu;
107 };
108 
109 }  // namespace berberis
110 
111 #endif  // BERBERIS_GUEST_STATE_GUEST_STATE_RISCV64_H_
112