mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 08:00:15 +02:00
Merge pull request #4738 from bylaws/peggle
Implement inline SMC handling for linux FEX
This commit is contained in:
5 files changed
+30
-24
No files matched your search
@@ -108,12 +108,8 @@ GdbServer::GdbServer(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator*
|
||||
ThreadObject->GdbInfo = {};
|
||||
ThreadObject->GdbInfo->Signal = Signal;
|
||||
|
||||
ThreadObject->GdbInfo->SignalPC = ArchHelpers::Context::GetPc(ucontext);
|
||||
this->SignalDelegation->SpillSRA(Thread, ucontext, Thread->CurrentFrame->InSyscallInfo);
|
||||
|
||||
memcpy(ThreadObject->GdbInfo->GPRs, ArchHelpers::Context::GetArmGPRs(ucontext), sizeof(ThreadObject->GdbInfo->GPRs));
|
||||
ThreadObject->GdbInfo->PState = ArchHelpers::Context::GetArmPState(ucontext);
|
||||
|
||||
// Let GDB know that we have a signal
|
||||
this->Break(Thread, Signal);
|
||||
|
||||
@@ -304,16 +300,8 @@ GdbServer::GDBContextDefinition GdbServer::GenerateContextDefinition(const FEX::
|
||||
|
||||
// Encode the GDB context definition
|
||||
memcpy(&GDB.gregs[0], &state.gregs[0], sizeof(GDB.gregs));
|
||||
if (ThreadObject->GdbInfo.has_value()) {
|
||||
GDB.rip = CTX->RestoreRIPFromHostPC(ThreadObject->Thread, ThreadObject->GdbInfo->SignalPC);
|
||||
|
||||
const bool WasInJIT = CTX->IsAddressInCodeBuffer(ThreadObject->Thread, ThreadObject->GdbInfo->SignalPC);
|
||||
GDB.eflags = CTX->ReconstructCompactedEFLAGS(ThreadObject->Thread, WasInJIT, const_cast<uint64_t*>(ThreadObject->GdbInfo->GPRs),
|
||||
ThreadObject->GdbInfo->PState);
|
||||
} else {
|
||||
GDB.rip = ThreadObject->Thread->CurrentFrame->State.rip;
|
||||
GDB.eflags = CTX->ReconstructCompactedEFLAGS(ThreadObject->Thread, false, nullptr, 0);
|
||||
}
|
||||
GDB.rip = ThreadObject->Thread->CurrentFrame->State.rip;
|
||||
GDB.eflags = CTX->ReconstructCompactedEFLAGS(ThreadObject->Thread, false, nullptr, 0);
|
||||
|
||||
for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) {
|
||||
memcpy(&GDB.mm[i], &state.mm[i], sizeof(GDB.mm[i]));
|
||||
|
||||
@@ -110,6 +110,8 @@ void SignalDelegator::RegisterHostSignalHandler(int Signal, HostSignalDelegatorF
|
||||
|
||||
void SignalDelegator::SpillSRA(FEXCore::Core::InternalThreadState* Thread, void* ucontext, uint32_t IgnoreMask) {
|
||||
#ifdef _M_ARM_64
|
||||
Thread->CurrentFrame->State.rip = CTX->RestoreRIPFromHostPC(Thread, ArchHelpers::Context::GetPc(ucontext));
|
||||
|
||||
for (size_t i = 0; i < Config.SRAGPRCount; i++) {
|
||||
const uint8_t SRAIdxMap = Config.SRAGPRMapping[i];
|
||||
if (IgnoreMask & (1U << SRAIdxMap)) {
|
||||
@@ -132,6 +134,10 @@ void SignalDelegator::SpillSRA(FEXCore::Core::InternalThreadState* Thread, void*
|
||||
memcpy(&Thread->CurrentFrame->State.xmm.sse.data[i][0], &FPR, sizeof(__uint128_t));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t EFlags =
|
||||
CTX->ReconstructCompactedEFLAGS(Thread, true, ArchHelpers::Context::GetArmGPRs(ucontext), ArchHelpers::Context::GetArmPState(ucontext));
|
||||
CTX->SetFlagsFromCompactedEFLAGS(Thread, EFlags);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -354,11 +360,8 @@ bool SignalDelegator::HandleDispatcherGuestSignal(FEXCore::Core::InternalThreadS
|
||||
// siginfo_t
|
||||
siginfo_t* HostSigInfo = reinterpret_cast<siginfo_t*>(info);
|
||||
|
||||
// Backup where we think the RIP currently is
|
||||
ContextBackup->OriginalRIP = CTX->RestoreRIPFromHostPC(Thread, ArchHelpers::Context::GetPc(ucontext));
|
||||
// Calculate eflags upfront.
|
||||
uint32_t eflags = CTX->ReconstructCompactedEFLAGS(Thread, WasInJIT, ArchHelpers::Context::GetArmGPRs(ucontext),
|
||||
ArchHelpers::Context::GetArmPState(ucontext));
|
||||
ContextBackup->OriginalRIP = Thread->CurrentFrame->State.rip;
|
||||
uint32_t eflags = CTX->ReconstructCompactedEFLAGS(Thread, false, nullptr, 0);
|
||||
|
||||
if (Is64BitMode) {
|
||||
NewGuestSP = SetupFrame_x64(Thread, ContextBackup, Frame, Signal, HostSigInfo, ucontext, GuestAction, GuestStack, NewGuestSP, eflags);
|
||||
|
||||
@@ -15,6 +15,7 @@ $end_info$
|
||||
#include <sys/personality.h>
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/SignalDelegator.h"
|
||||
|
||||
#include <FEXCore/Debug/InternalThreadState.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
@@ -81,6 +82,21 @@ bool SyscallHandler::HandleSegfault(FEXCore::Core::InternalThreadState* Thread,
|
||||
}
|
||||
|
||||
FEXCORE_PROFILE_INSTANT_INCREMENT(Thread, AccumulatedSMCCount, 1);
|
||||
|
||||
auto CTX = Thread->CTX;
|
||||
if (CTX->IsAddressInCodeBuffer(Thread, ArchHelpers::Context::GetPc(ucontext)) && !CTX->IsCurrentBlockSingleInst(Thread) &&
|
||||
CTX->IsAddressInCurrentBlock(Thread, FaultAddress & FEXCore::Utils::FEX_PAGE_MASK, FEXCore::Utils::FEX_PAGE_SIZE)) {
|
||||
// If we are not in a single-instruction block, and the SMC write address could intersect with the current block,
|
||||
// reconstruct the context and repeat the faulting instruction as a single-instruction block so any SMC it performs
|
||||
// is immediately picked up.
|
||||
ThreadObject->SignalInfo.Delegator->SpillSRA(Thread, ucontext, Thread->CurrentFrame->InSyscallInfo & 0xFFFF);
|
||||
|
||||
// Adjust context to return to the dispatcher, reloading SRA from thread state
|
||||
const auto& Config = ThreadObject->SignalInfo.Delegator->GetConfig();
|
||||
ArchHelpers::Context::SetPc(ucontext, Config.AbsoluteLoopTopAddressFillSRA);
|
||||
ArchHelpers::Context::SetArmReg(ucontext, 1, 1); // Set ENTRY_FILL_SRA_SINGLE_INST_REG to force a single step
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,9 +92,6 @@ struct ThreadStateObject : public FEXCore::Allocator::FEXAllocOperators {
|
||||
// GDB signal information
|
||||
struct GdbInfoStruct {
|
||||
int Signal {};
|
||||
uint64_t SignalPC {};
|
||||
uint64_t GPRs[32];
|
||||
uint64_t PState {};
|
||||
};
|
||||
std::optional<GdbInfoStruct> GdbInfo;
|
||||
|
||||
|
||||
@@ -300,9 +300,11 @@ int main(int argc, char** argv, char** const envp) {
|
||||
FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), nullptr, std::move(Allocator));
|
||||
|
||||
auto DoMmap = [&](uint64_t Address, size_t Size) -> void* {
|
||||
void* Result = SyscallHandler->GuestMmap(nullptr, (void*)Address, Size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
|
||||
// Map as R-X, then protect as RWX without informing the frontend to avoid unwanted SMC detection
|
||||
void* Result =
|
||||
SyscallHandler->GuestMmap(nullptr, (void*)Address, Size, PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
|
||||
LOGMAN_THROW_A_FMT(Result == reinterpret_cast<void*>(Address), "Map Memory mmap failed");
|
||||
::mprotect(Result, Size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
return Result;
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user