summaryrefslogtreecommitdiff
path: root/src/core/arm/arm_interface.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/arm/arm_interface.h')
-rw-r--r--src/core/arm/arm_interface.h221
1 files changed, 49 insertions, 172 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index a9d9ac09d..806c7c9e9 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -12,20 +12,20 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/hardware_properties.h" 13#include "core/hardware_properties.h"
14 14
15#include "core/hle/kernel/svc_types.h"
16
15namespace Common { 17namespace Common {
16struct PageTable; 18struct PageTable;
17} 19}
18 20
19namespace Kernel { 21namespace Kernel {
20enum class VMAPermission : u8;
21enum class DebugWatchpointType : u8; 22enum class DebugWatchpointType : u8;
22struct DebugWatchpoint; 23struct DebugWatchpoint;
24class KThread;
25class KProcess;
23} // namespace Kernel 26} // namespace Kernel
24 27
25namespace Core { 28namespace Core {
26class System;
27class CPUInterruptHandler;
28
29using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>; 29using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>;
30 30
31// NOTE: these values match the HaltReason enum in Dynarmic 31// NOTE: these values match the HaltReason enum in Dynarmic
@@ -40,197 +40,74 @@ enum class HaltReason : u64 {
40DECLARE_ENUM_FLAG_OPERATORS(HaltReason); 40DECLARE_ENUM_FLAG_OPERATORS(HaltReason);
41 41
42enum class Architecture { 42enum class Architecture {
43 Aarch32, 43 AArch64,
44 Aarch64, 44 AArch32,
45}; 45};
46 46
47/// Generic ARMv8 CPU interface 47/// Generic ARMv8 CPU interface
48class ARM_Interface { 48class ArmInterface {
49public: 49public:
50 YUZU_NON_COPYABLE(ARM_Interface); 50 YUZU_NON_COPYABLE(ArmInterface);
51 YUZU_NON_MOVEABLE(ARM_Interface); 51 YUZU_NON_MOVEABLE(ArmInterface);
52 52
53 explicit ARM_Interface(System& system_, bool uses_wall_clock_) 53 explicit ArmInterface(bool uses_wall_clock) : m_uses_wall_clock{uses_wall_clock} {}
54 : system{system_}, uses_wall_clock{uses_wall_clock_} {} 54 virtual ~ArmInterface() = default;
55 virtual ~ARM_Interface() = default; 55
56 56 // Perform any backend-specific initialization.
57 struct ThreadContext32 {
58 std::array<u32, 16> cpu_registers{};
59 std::array<u32, 64> extension_registers{};
60 u32 cpsr{};
61 u32 fpscr{};
62 u32 fpexc{};
63 u32 tpidr{};
64 };
65 // Internally within the kernel, it expects the AArch32 version of the
66 // thread context to be 344 bytes in size.
67 static_assert(sizeof(ThreadContext32) == 0x150);
68
69 struct ThreadContext64 {
70 std::array<u64, 31> cpu_registers{};
71 u64 sp{};
72 u64 pc{};
73 u32 pstate{};
74 std::array<u8, 4> padding{};
75 std::array<u128, 32> vector_registers{};
76 u32 fpcr{};
77 u32 fpsr{};
78 u64 tpidr{};
79 };
80 // Internally within the kernel, it expects the AArch64 version of the
81 // thread context to be 800 bytes in size.
82 static_assert(sizeof(ThreadContext64) == 0x320);
83
84 /// Perform any backend-specific initialization.
85 virtual void Initialize() {} 57 virtual void Initialize() {}
86 58
87 /// Runs the CPU until an event happens 59 // Runs the CPU until an event happens.
88 void Run(); 60 virtual HaltReason RunThread(Kernel::KThread* thread) = 0;
89 61
90 /// Clear all instruction cache 62 // Runs the CPU for one instruction or until an event happens.
63 virtual HaltReason StepThread(Kernel::KThread* thread) = 0;
64
65 // Admits a backend-specific mechanism to lock the thread context.
66 virtual void LockThread(Kernel::KThread* thread) {}
67 virtual void UnlockThread(Kernel::KThread* thread) {}
68
69 // Clear the entire instruction cache for this CPU.
91 virtual void ClearInstructionCache() = 0; 70 virtual void ClearInstructionCache() = 0;
92 71
93 /** 72 // Clear a range of the instruction cache for this CPU.
94 * Clear instruction cache range
95 * @param addr Start address of the cache range to clear
96 * @param size Size of the cache range to clear, starting at addr
97 */
98 virtual void InvalidateCacheRange(u64 addr, std::size_t size) = 0; 73 virtual void InvalidateCacheRange(u64 addr, std::size_t size) = 0;
99 74
100 /** 75 // Get the current architecture.
101 * Notifies CPU emulation that the current page table has changed. 76 // This returns AArch64 when PSTATE.nRW == 0 and AArch32 when PSTATE.nRW == 1.
102 * @param new_page_table The new page table.
103 * @param new_address_space_size_in_bits The new usable size of the address space in bits.
104 * This can be either 32, 36, or 39 on official software.
105 */
106 virtual void PageTableChanged(Common::PageTable& new_page_table,
107 std::size_t new_address_space_size_in_bits) = 0;
108
109 /**
110 * Set the Program Counter to an address
111 * @param addr Address to set PC to
112 */
113 virtual void SetPC(u64 addr) = 0;
114
115 /*
116 * Get the current Program Counter
117 * @return Returns current PC
118 */
119 virtual u64 GetPC() const = 0;
120
121 /**
122 * Get the current Stack Pointer
123 * @return Returns current SP
124 */
125 virtual u64 GetSP() const = 0;
126
127 /**
128 * Get an ARM register
129 * @param index Register index
130 * @return Returns the value in the register
131 */
132 virtual u64 GetReg(int index) const = 0;
133
134 /**
135 * Set an ARM register
136 * @param index Register index
137 * @param value Value to set register to
138 */
139 virtual void SetReg(int index, u64 value) = 0;
140
141 /**
142 * Gets the value of a specified vector register.
143 *
144 * @param index The index of the vector register.
145 * @return the value within the vector register.
146 */
147 virtual u128 GetVectorReg(int index) const = 0;
148
149 /**
150 * Sets a given value into a vector register.
151 *
152 * @param index The index of the vector register.
153 * @param value The new value to place in the register.
154 */
155 virtual void SetVectorReg(int index, u128 value) = 0;
156
157 /**
158 * Get the current PSTATE register
159 * @return Returns the value of the PSTATE register
160 */
161 virtual u32 GetPSTATE() const = 0;
162
163 /**
164 * Set the current PSTATE register
165 * @param pstate Value to set PSTATE to
166 */
167 virtual void SetPSTATE(u32 pstate) = 0;
168
169 virtual u64 GetTlsAddress() const = 0;
170
171 virtual void SetTlsAddress(u64 address) = 0;
172
173 /**
174 * Gets the value within the TPIDR_EL0 (read/write software thread ID) register.
175 *
176 * @return the value within the register.
177 */
178 virtual u64 GetTPIDR_EL0() const = 0;
179
180 /**
181 * Sets a new value within the TPIDR_EL0 (read/write software thread ID) register.
182 *
183 * @param value The new value to place in the register.
184 */
185 virtual void SetTPIDR_EL0(u64 value) = 0;
186
187 virtual Architecture GetArchitecture() const = 0; 77 virtual Architecture GetArchitecture() const = 0;
188 virtual void SaveContext(ThreadContext32& ctx) const = 0;
189 virtual void SaveContext(ThreadContext64& ctx) const = 0;
190 virtual void LoadContext(const ThreadContext32& ctx) = 0;
191 virtual void LoadContext(const ThreadContext64& ctx) = 0;
192 void LoadWatchpointArray(const WatchpointArray* wp);
193 78
194 /// Clears the exclusive monitor's state. 79 // Context accessors.
195 virtual void ClearExclusiveState() = 0; 80 // These should not be called if the CPU is running.
81 virtual void GetContext(Kernel::Svc::ThreadContext& ctx) const = 0;
82 virtual void SetContext(const Kernel::Svc::ThreadContext& ctx) = 0;
83 virtual void SetTpidrroEl0(u64 value) = 0;
196 84
197 /// Signal an interrupt and ask the core to halt as soon as possible. 85 virtual void GetSvcArguments(std::span<uint64_t, 8> args) const = 0;
198 virtual void SignalInterrupt() = 0; 86 virtual void SetSvcArguments(std::span<const uint64_t, 8> args) = 0;
87 virtual u32 GetSvcNumber() const = 0;
199 88
200 /// Clear a previous interrupt. 89 void SetWatchpointArray(const WatchpointArray* watchpoints) {
201 virtual void ClearInterrupt() = 0; 90 m_watchpoints = watchpoints;
91 }
202 92
203 struct BacktraceEntry { 93 // Signal an interrupt for execution to halt as soon as possible.
204 std::string module; 94 // It is safe to call this if the CPU is not running.
205 u64 address; 95 virtual void SignalInterrupt(Kernel::KThread* thread) = 0;
206 u64 original_address;
207 u64 offset;
208 std::string name;
209 };
210 96
211 static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, 97 // Stack trace generation.
212 const ThreadContext32& ctx); 98 void LogBacktrace(const Kernel::KProcess* process) const;
213 static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system,
214 const ThreadContext64& ctx);
215 99
216 std::vector<BacktraceEntry> GetBacktrace() const; 100 // Debug functionality.
217 void LogBacktrace() const; 101 virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
102 virtual void RewindBreakpointInstruction() = 0;
218 103
219protected: 104protected:
220 /// System context that this ARM interface is running under.
221 System& system;
222 const WatchpointArray* watchpoints;
223 bool uses_wall_clock;
224
225 static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out);
226 const Kernel::DebugWatchpoint* MatchingWatchpoint( 105 const Kernel::DebugWatchpoint* MatchingWatchpoint(
227 u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const; 106 u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const;
228 107
229 virtual HaltReason RunJit() = 0; 108protected:
230 virtual HaltReason StepJit() = 0; 109 const WatchpointArray* m_watchpoints{};
231 virtual u32 GetSvcNumber() const = 0; 110 bool m_uses_wall_clock{};
232 virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
233 virtual void RewindBreakpointInstruction() = 0;
234}; 111};
235 112
236} // namespace Core 113} // namespace Core