// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include "common/common_funcs.h" #include "common/common_types.h" #include "core/arm/arm_interface.h" #include "core/arm/nce/arm_nce_asm_definitions.h" #ifdef __linux__ #include #include #include #endif namespace Core { class ArmNce; class System; struct HostContext { alignas(16) std::array host_saved_regs{}; alignas(16) std::array host_saved_vregs{}; u64 host_sp{}; void* host_tpidr_el0{}; }; struct GuestContext { std::array cpu_registers{}; u64 sp{}; u64 pc{}; u32 fpcr{}; u32 fpsr{}; std::array vector_registers{}; u32 pstate{}; alignas(16) HostContext host_ctx{}; u64 tpidrro_el0{}; u64 tpidr_el0{}; std::atomic esr_el1{}; u32 nzcv{}; u32 svc{}; System* system{}; ArmNce* parent{}; }; class KernelContext { public: #if defined(__linux__) KernelContext(void* ptr_) : ptr(static_cast(ptr_)), fpsimd{GetFloatingPointState(ptr)} {} u64* pc() { // u64 (unsigned long) does not equal unsigned long long // thank you gcc return reinterpret_cast(&ptr->pc); } u64* sp() { return reinterpret_cast(&ptr->sp); } u64* regs() { return reinterpret_cast(&ptr->regs); } u128* vregs() { // returns __uint128, u128 is a std::array return reinterpret_cast(&fpsimd->vregs); } u32* fpcr() { return &fpsimd->fpcr; } u32* fpsr() { return &fpsimd->fpsr; } u32* pstate() { // only first 32 bits are used return reinterpret_cast(&ptr->pstate); } #elif defined(__APPLE__) KernelContext(void* ptr) : ptr(static_cast(ptr)) {} u64* pc() { return &(*ptr)->__ss.__pc; } u64* sp() { return &(*ptr)->__ss.__sp; } u64* regs() { return (*ptr)->__ss.__x; } u128* vregs() { // .__v returns __uint128, u128 is an std::array return reinterpret_cast((*ptr)->__ns.__v); } u32* fpcr() { return &(*ptr)->__ns.__fpcr; } u32* fpsr() { return &(*ptr)->__ns.__fpsr; } u32* pstate() { return &(*ptr)->__ss.__cpsr; } #endif private: mcontext_t* ptr; #ifdef __linux__ fpsimd_context* fpsimd; fpsimd_context* GetFloatingPointState(mcontext_t* host_ctx) { _aarch64_ctx* header = reinterpret_cast<_aarch64_ctx*>(&host_ctx->__reserved); while (header->magic != FPSIMD_MAGIC) { header = reinterpret_cast<_aarch64_ctx*>(reinterpret_cast(header) + header->size); } return reinterpret_cast(header); } #endif }; // Verify assembly offsets. static_assert(offsetof(GuestContext, sp) == GuestContextSp); static_assert(offsetof(GuestContext, host_ctx) == GuestContextHostContext); static_assert(offsetof(HostContext, host_sp) == HostContextSpTpidrEl0); static_assert(offsetof(HostContext, host_tpidr_el0) - 8 == HostContextSpTpidrEl0); static_assert(offsetof(HostContext, host_tpidr_el0) == HostContextTpidrEl0); static_assert(offsetof(HostContext, host_saved_regs) == HostContextRegs); static_assert(offsetof(HostContext, host_saved_vregs) == HostContextVregs); #ifdef TARGET_OS_MAC // ensure that fp and lr are next to the rest of the x registers so they can be accessed like an array static_assert(offsetof(_STRUCT_ARM_THREAD_STATE64, __sp) - offsetof(_STRUCT_ARM_THREAD_STATE64, __x) == sizeof(u64) * 31); #endif } // namespace Core