mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-10 23:00:30 +02:00
The JIT was doing a bunch of additional work where it was saving and restoring registers and then juggling the arguments back in to a stack frame. All of this is nonsensical without the optimization where we could call syscalls inline without a stack frame. Instead remove this optimization entirely and behave like a "generic" syscall path always. The Linux syscall handler now pulls the arguments out of the CPU context directly and stores the result back in to RAX directly as well. This has knock-on effects where technically syscalls are going to be slightly faster because no stack frame setup for the arguments, but additionally we are going to be able to have syscalls be proper serialization points where we can interrupt the syscall and long-jump out without problems. Bumps the DiskCache version again because it causes codegen to change.
117 lines
3.7 KiB
C++
117 lines
3.7 KiB
C++
// SPDX-License-Identifier: MIT
|
|
/*
|
|
$info$
|
|
tags: LinuxSyscalls|syscalls-shared
|
|
$end_info$
|
|
*/
|
|
#pragma once
|
|
|
|
#include <FEXCore/Config/Config.h>
|
|
#include <FEXCore/fextl/list.h>
|
|
#include <FEXCore/Utils/SignalScopeGuards.h>
|
|
#include "LinuxSyscalls/ThreadManager.h"
|
|
|
|
#include <atomic>
|
|
#include <csignal>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <optional>
|
|
|
|
struct sock_fprog;
|
|
struct seccomp_data;
|
|
struct seccomp_notif_sizes;
|
|
|
|
namespace FEXCore::Core {
|
|
struct CpuStateFrame;
|
|
} // namespace FEXCore::Core
|
|
|
|
namespace FEX::HLE {
|
|
|
|
class SignalDelegator;
|
|
class SyscallHandler;
|
|
struct ThreadStateObject;
|
|
struct SyscallArguments;
|
|
|
|
using SeccompFilterFunc = uint64_t (*)(uint32_t Acc, uint32_t Index, uint32_t Tmp, uint32_t Tmp2, void* Data);
|
|
struct SeccompFilterInfo final {
|
|
SeccompFilterFunc Func;
|
|
uint64_t RefCount;
|
|
size_t MappedSize;
|
|
uint32_t FilterInstructions;
|
|
bool ShouldLog;
|
|
};
|
|
|
|
class SeccompEmulator final {
|
|
public:
|
|
SeccompEmulator(FEX::HLE::SyscallHandler* SyscallHandler, FEX::HLE::SignalDelegator* SignalDelegation)
|
|
: SyscallHandler {SyscallHandler}
|
|
, SignalDelegation {SignalDelegation} {}
|
|
|
|
uint64_t Handle(FEXCore::Core::CpuStateFrame* Frame, uint32_t Op, uint32_t flags, void* arg);
|
|
|
|
// Equivalent to prctl(PR_GET_SECCOMP)
|
|
uint64_t GetSeccomp(FEXCore::Core::CpuStateFrame* Frame);
|
|
|
|
void InheritSeccompFilters(FEX::HLE::ThreadStateObject* Parent, FEX::HLE::ThreadStateObject* Child);
|
|
void FreeSeccompFilters(FEX::HLE::ThreadStateObject* Thread);
|
|
|
|
struct ExecuteFilterResult {
|
|
bool EarlyReturn {};
|
|
uint64_t Result;
|
|
};
|
|
ExecuteFilterResult ExecuteFilter(FEXCore::Core::CpuStateFrame* Frame, uint64_t JITPC, FEX::HLE::SyscallArguments* Args);
|
|
|
|
bool HasFilter(FEXCore::Core::CpuStateFrame* Frame) const {
|
|
auto Thread = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame);
|
|
return !Thread->Filters.empty();
|
|
}
|
|
|
|
int GetKillSignal() const {
|
|
return CurrentKillSignal;
|
|
}
|
|
|
|
std::optional<int> SerializeFilters(FEXCore::Core::CpuStateFrame* Frame);
|
|
void DeserializeFilters(FEXCore::Core::CpuStateFrame* Frame, int FD);
|
|
|
|
private:
|
|
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
|
|
FEX_CONFIG_OPT(NeedsSeccomp, NEEDSSECCOMP);
|
|
FEX_CONFIG_OPT(Filename, APP_FILENAME);
|
|
FEX::HLE::SyscallHandler* SyscallHandler;
|
|
FEX::HLE::SignalDelegator* SignalDelegation;
|
|
|
|
int CurrentKillSignal {SIGSYS};
|
|
|
|
// Equivalent to seccomp(SECCOMP_SET_MODE_STRICT, ...);
|
|
uint64_t SetModeStrict(FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, const void* arg);
|
|
// Equivalent to seccomp(SECCOMP_SET_MODE_FILTER, ...);
|
|
uint64_t SetModeFilter(FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, const sock_fprog* prog);
|
|
// Equivalent to seccomp(SECCOMP_GET_ACTION_AVAIL, ...);
|
|
uint64_t GetActionAvail(uint32_t flags, const uint32_t* action);
|
|
// Equivalent to seccomp(SECCOMP_GET_NOTIF_SIZES, ...);
|
|
uint64_t GetNotifSizes(uint32_t flags, struct seccomp_notif_sizes* sizes);
|
|
|
|
// 0 on TSync possible
|
|
/// TID for the first thread that breaks tsync.
|
|
uint64_t CanDoTSync(FEXCore::Core::CpuStateFrame* Frame);
|
|
void TSyncFilters(FEXCore::Core::CpuStateFrame* Frame);
|
|
|
|
static void DumpProgram(const sock_fprog* prog);
|
|
|
|
// Multiple filter instruction count penalty.
|
|
// When multiple filters are installed there is a penalty per filter counted towards the maximum number of instructions.
|
|
constexpr static size_t BPF_MULTIFILTERPENALTY = 4;
|
|
// Maximum number of BPF instructions.
|
|
constexpr static size_t BPF_MAX_INSNS_PER_PATH = 32768;
|
|
uint64_t TotalFilterInstructions {};
|
|
|
|
FEXCore::ForkableUniqueMutex FilterMutex;
|
|
fextl::list<SeccompFilterInfo> Filters {};
|
|
|
|
uint64_t AuditSerialIncrement() {
|
|
return AuditSerial.fetch_add(1);
|
|
}
|
|
std::atomic<uint64_t> AuditSerial {};
|
|
};
|
|
} // namespace FEX::HLE
|