// SPDX-License-Identifier: MIT #pragma once #include #include #include #include namespace FEX::Windows::CallRetStack { struct CallRetStackInfo { uint64_t AllocationBase; uint64_t AllocationEnd; uint64_t DefaultLocation; }; CallRetStackInfo GetInfoThread(FEXCore::Core::InternalThreadState* Thread) { uint64_t Base = reinterpret_cast(Thread->CallRetStackBase); // Leave some room from the base for the default location to allow for underflows without constant exceptions return {Base - FEXCore::Utils::FEX_PAGE_SIZE, Base + FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE + FEXCore::Utils::FEX_PAGE_SIZE, Base + FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE / 4}; } void InitializeThread(FEXCore::Core::InternalThreadState* Thread) { // Allocate the call-ret stack with guard pages on both sides const void* CallRetStackAlloc = ::VirtualAlloc(nullptr, FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE + 2 * FEXCore::Utils::FEX_PAGE_SIZE, MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS); FEXCore::Allocator::VirtualName("FEXMem_CallRetStacks", CallRetStackAlloc, FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE + 2 * FEXCore::Utils::FEX_PAGE_SIZE); FEXCore::Allocator::VirtualTHPControl(CallRetStackAlloc, FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE + 2 * FEXCore::Utils::FEX_PAGE_SIZE, FEXCore::Allocator::THPControl::Disable); Thread->CallRetStackBase = reinterpret_cast(reinterpret_cast(CallRetStackAlloc) + FEXCore::Utils::FEX_PAGE_SIZE); ::VirtualAlloc(Thread->CallRetStackBase, FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE, MEM_COMMIT, PAGE_READWRITE); Thread->CurrentFrame->State.callret_sp = GetInfoThread(Thread).DefaultLocation; } void DestroyThread(FEXCore::Core::InternalThreadState* Thread) { auto CallRetStackInfo = GetInfoThread(Thread); ::VirtualFree(reinterpret_cast(CallRetStackInfo.AllocationBase), 0, MEM_RELEASE); } bool HandleAccessViolation(FEXCore::Core::InternalThreadState* Thread, uint64_t Address, uint64_t& CallRetSPReg) { auto CallRetStackInfo = GetInfoThread(Thread); if (Address >= CallRetStackInfo.AllocationBase && Address < CallRetStackInfo.AllocationEnd) { LogMan::Msg::DFmt("Call-ret stack inbalance: {:X}", Address); CallRetSPReg = CallRetStackInfo.DefaultLocation; return true; } return false; } } // namespace FEX::Windows::CallRetStack