mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-07 00:00:17 +02:00
We were accidentally allocating some things without this flag and it was causing us to dump memory in to the lower 32-bits on arm64ec. This was causing the game [Below](https://store.steampowered.com/app/250680/BELOW/) to run out of memory to allocate for its LUA JIT and causes it to crash.
54 lines
2.6 KiB
C++
54 lines
2.6 KiB
C++
// SPDX-License-Identifier: MIT
|
|
#pragma once
|
|
|
|
#include <FEXCore/Core/Context.h>
|
|
#include <FEXCore/Utils/Allocator.h>
|
|
#include <FEXCore/Utils/LogManager.h>
|
|
#include <FEXCore/Debug/InternalThreadState.h>
|
|
|
|
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<uint64_t>(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<void*>(reinterpret_cast<uintptr_t>(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<void*>(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
|