From 45c87c7e6e841c11def43e5ab25160006dab6d77 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 28 Nov 2023 14:30:39 -0500 Subject: core: refactor emulated cpu core activation --- src/core/arm/arm_interface.h | 221 ++++++++++--------------------------------- 1 file changed, 49 insertions(+), 172 deletions(-) (limited to 'src/core/arm/arm_interface.h') 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 @@ #include "common/common_types.h" #include "core/hardware_properties.h" +#include "core/hle/kernel/svc_types.h" + namespace Common { struct PageTable; } namespace Kernel { -enum class VMAPermission : u8; enum class DebugWatchpointType : u8; struct DebugWatchpoint; +class KThread; +class KProcess; } // namespace Kernel namespace Core { -class System; -class CPUInterruptHandler; - using WatchpointArray = std::array; // NOTE: these values match the HaltReason enum in Dynarmic @@ -40,197 +40,74 @@ enum class HaltReason : u64 { DECLARE_ENUM_FLAG_OPERATORS(HaltReason); enum class Architecture { - Aarch32, - Aarch64, + AArch64, + AArch32, }; /// Generic ARMv8 CPU interface -class ARM_Interface { +class ArmInterface { public: - YUZU_NON_COPYABLE(ARM_Interface); - YUZU_NON_MOVEABLE(ARM_Interface); - - explicit ARM_Interface(System& system_, bool uses_wall_clock_) - : system{system_}, uses_wall_clock{uses_wall_clock_} {} - virtual ~ARM_Interface() = default; - - struct ThreadContext32 { - std::array cpu_registers{}; - std::array extension_registers{}; - u32 cpsr{}; - u32 fpscr{}; - u32 fpexc{}; - u32 tpidr{}; - }; - // Internally within the kernel, it expects the AArch32 version of the - // thread context to be 344 bytes in size. - static_assert(sizeof(ThreadContext32) == 0x150); - - struct ThreadContext64 { - std::array cpu_registers{}; - u64 sp{}; - u64 pc{}; - u32 pstate{}; - std::array padding{}; - std::array vector_registers{}; - u32 fpcr{}; - u32 fpsr{}; - u64 tpidr{}; - }; - // Internally within the kernel, it expects the AArch64 version of the - // thread context to be 800 bytes in size. - static_assert(sizeof(ThreadContext64) == 0x320); - - /// Perform any backend-specific initialization. + YUZU_NON_COPYABLE(ArmInterface); + YUZU_NON_MOVEABLE(ArmInterface); + + explicit ArmInterface(bool uses_wall_clock) : m_uses_wall_clock{uses_wall_clock} {} + virtual ~ArmInterface() = default; + + // Perform any backend-specific initialization. virtual void Initialize() {} - /// Runs the CPU until an event happens - void Run(); + // Runs the CPU until an event happens. + virtual HaltReason RunThread(Kernel::KThread* thread) = 0; - /// Clear all instruction cache + // Runs the CPU for one instruction or until an event happens. + virtual HaltReason StepThread(Kernel::KThread* thread) = 0; + + // Admits a backend-specific mechanism to lock the thread context. + virtual void LockThread(Kernel::KThread* thread) {} + virtual void UnlockThread(Kernel::KThread* thread) {} + + // Clear the entire instruction cache for this CPU. virtual void ClearInstructionCache() = 0; - /** - * Clear instruction cache range - * @param addr Start address of the cache range to clear - * @param size Size of the cache range to clear, starting at addr - */ + // Clear a range of the instruction cache for this CPU. virtual void InvalidateCacheRange(u64 addr, std::size_t size) = 0; - /** - * Notifies CPU emulation that the current page table has changed. - * @param new_page_table The new page table. - * @param new_address_space_size_in_bits The new usable size of the address space in bits. - * This can be either 32, 36, or 39 on official software. - */ - virtual void PageTableChanged(Common::PageTable& new_page_table, - std::size_t new_address_space_size_in_bits) = 0; - - /** - * Set the Program Counter to an address - * @param addr Address to set PC to - */ - virtual void SetPC(u64 addr) = 0; - - /* - * Get the current Program Counter - * @return Returns current PC - */ - virtual u64 GetPC() const = 0; - - /** - * Get the current Stack Pointer - * @return Returns current SP - */ - virtual u64 GetSP() const = 0; - - /** - * Get an ARM register - * @param index Register index - * @return Returns the value in the register - */ - virtual u64 GetReg(int index) const = 0; - - /** - * Set an ARM register - * @param index Register index - * @param value Value to set register to - */ - virtual void SetReg(int index, u64 value) = 0; - - /** - * Gets the value of a specified vector register. - * - * @param index The index of the vector register. - * @return the value within the vector register. - */ - virtual u128 GetVectorReg(int index) const = 0; - - /** - * Sets a given value into a vector register. - * - * @param index The index of the vector register. - * @param value The new value to place in the register. - */ - virtual void SetVectorReg(int index, u128 value) = 0; - - /** - * Get the current PSTATE register - * @return Returns the value of the PSTATE register - */ - virtual u32 GetPSTATE() const = 0; - - /** - * Set the current PSTATE register - * @param pstate Value to set PSTATE to - */ - virtual void SetPSTATE(u32 pstate) = 0; - - virtual u64 GetTlsAddress() const = 0; - - virtual void SetTlsAddress(u64 address) = 0; - - /** - * Gets the value within the TPIDR_EL0 (read/write software thread ID) register. - * - * @return the value within the register. - */ - virtual u64 GetTPIDR_EL0() const = 0; - - /** - * Sets a new value within the TPIDR_EL0 (read/write software thread ID) register. - * - * @param value The new value to place in the register. - */ - virtual void SetTPIDR_EL0(u64 value) = 0; - + // Get the current architecture. + // This returns AArch64 when PSTATE.nRW == 0 and AArch32 when PSTATE.nRW == 1. virtual Architecture GetArchitecture() const = 0; - virtual void SaveContext(ThreadContext32& ctx) const = 0; - virtual void SaveContext(ThreadContext64& ctx) const = 0; - virtual void LoadContext(const ThreadContext32& ctx) = 0; - virtual void LoadContext(const ThreadContext64& ctx) = 0; - void LoadWatchpointArray(const WatchpointArray* wp); - /// Clears the exclusive monitor's state. - virtual void ClearExclusiveState() = 0; + // Context accessors. + // These should not be called if the CPU is running. + virtual void GetContext(Kernel::Svc::ThreadContext& ctx) const = 0; + virtual void SetContext(const Kernel::Svc::ThreadContext& ctx) = 0; + virtual void SetTpidrroEl0(u64 value) = 0; - /// Signal an interrupt and ask the core to halt as soon as possible. - virtual void SignalInterrupt() = 0; + virtual void GetSvcArguments(std::span args) const = 0; + virtual void SetSvcArguments(std::span args) = 0; + virtual u32 GetSvcNumber() const = 0; - /// Clear a previous interrupt. - virtual void ClearInterrupt() = 0; + void SetWatchpointArray(const WatchpointArray* watchpoints) { + m_watchpoints = watchpoints; + } - struct BacktraceEntry { - std::string module; - u64 address; - u64 original_address; - u64 offset; - std::string name; - }; + // Signal an interrupt for execution to halt as soon as possible. + // It is safe to call this if the CPU is not running. + virtual void SignalInterrupt(Kernel::KThread* thread) = 0; - static std::vector GetBacktraceFromContext(System& system, - const ThreadContext32& ctx); - static std::vector GetBacktraceFromContext(System& system, - const ThreadContext64& ctx); + // Stack trace generation. + void LogBacktrace(const Kernel::KProcess* process) const; - std::vector GetBacktrace() const; - void LogBacktrace() const; + // Debug functionality. + virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0; + virtual void RewindBreakpointInstruction() = 0; protected: - /// System context that this ARM interface is running under. - System& system; - const WatchpointArray* watchpoints; - bool uses_wall_clock; - - static void SymbolicateBacktrace(Core::System& system, std::vector& out); const Kernel::DebugWatchpoint* MatchingWatchpoint( u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const; - virtual HaltReason RunJit() = 0; - virtual HaltReason StepJit() = 0; - virtual u32 GetSvcNumber() const = 0; - virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0; - virtual void RewindBreakpointInstruction() = 0; +protected: + const WatchpointArray* m_watchpoints{}; + bool m_uses_wall_clock{}; }; } // namespace Core -- cgit v1.2.3