Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Linux: Add support for using set_robust_list2 #3966

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ enum Syscalls_Arm64 {
SYSCALL_Arm64_lsm_set_self_attr = 460,
SYSCALL_Arm64_lsm_list_modules = 461,
SYSCALL_Arm64_mseal = 462,
SYSCALL_Arm64_set_robust_list2 = 468, // Subject to change
SYSCALL_Arm64_MAX = 512,

// Unsupported syscalls on this host
Expand Down
4 changes: 4 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ desc: Glue logic, brk allocations
#include <unistd.h>

namespace FEX::HLE {
int set_robust_list2(struct robust_list_head* head, int index, uint32_t flags) {
return ::syscall(SYSCALL_DEF(set_robust_list2), head, index, flags);
}

class SignalDelegator;
SyscallHandler* _SyscallHandler {};

Expand Down
9 changes: 9 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ namespace Core {

namespace FEX::HLE {

enum robust_list_type {
ROBUST_LIST_32BIT = 0,
ROBUST_LIST_64BIT = 1,
};

// TODO: Switch to a kernel version check where used.
constexpr bool ENABLE_ROBUST_LIST2 = true;
int set_robust_list2(struct robust_list_head* head, int index, uint32_t flags);

class SyscallHandler;
class SignalDelegator;
class ThunkHandler;
Expand Down
19 changes: 15 additions & 4 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Passthrough.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,14 @@ void RegisterCommon(FEX::HLE::SyscallHandler* Handler) {
} else {
REGISTER_SYSCALL_IMPL(mseal, UnimplementedSyscallSafe);
}

// Kernel version subject to change
if (Handler->IsHostKernelVersionAtLeast(6, 11, 0)) {
REGISTER_SYSCALL_IMPL_PASS_FLAGS(set_robust_list2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
SyscallPassthrough3<SYSCALL_DEF(set_robust_list2)>);
} else {
REGISTER_SYSCALL_IMPL(set_robust_list2, UnimplementedSyscallSafe);
}
}

namespace x64 {
Expand Down Expand Up @@ -730,10 +738,13 @@ namespace x64 {
SyscallPassthrough6<SYSCALL_DEF(pselect6)>);
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(ppoll, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
SyscallPassthrough5<SYSCALL_DEF(ppoll)>);
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(set_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
SyscallPassthrough2<SYSCALL_DEF(set_robust_list)>);
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(get_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
SyscallPassthrough3<SYSCALL_DEF(get_robust_list)>);
if (!ENABLE_ROBUST_LIST2) {
// Gets handled in x64/Thread.cpp
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(set_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
SyscallPassthrough2<SYSCALL_DEF(set_robust_list)>);
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(get_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
SyscallPassthrough3<SYSCALL_DEF(get_robust_list)>);
}
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sync_file_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
SyscallPassthrough4<SYSCALL_DEF(sync_file_range)>);
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(vmsplice, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
Expand Down
10 changes: 9 additions & 1 deletion Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,15 @@ struct ThreadStateObject : public FEXCore::Allocator::FEXAllocOperators {
std::atomic<uint32_t> TID;
int32_t* set_child_tid {0};
int32_t* clear_child_tid {0};
uint64_t robust_list_head {0};

uint64_t robust_list_head_x64 {0};
uint64_t robust_list_head_x32 {0};

// Robust list index mappings.
// Start off as -1 to allow dynamic slot allocation from the kernel.
int robust_list_index_x64 {-1};
int robust_list_index_x32 {-1};

} ThreadInfo {};

struct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ enum Syscalls_x86 {
SYSCALL_x86_lsm_set_self_attr = 460,
SYSCALL_x86_lsm_list_modules = 461,
SYSCALL_x86_mseal = 462,
SYSCALL_x86_set_robust_list2 = 468, // Subject to change
SYSCALL_x86_MAX = 512,
};
} // namespace FEX::HLE::x32
59 changes: 43 additions & 16 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,30 +179,57 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) {
return 0;
});

REGISTER_SYSCALL_IMPL_X32(set_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, struct robust_list_head* head, size_t len) -> uint64_t {
if (len != 12) {
// Return invalid if the passed in length doesn't match what's expected.
return -EINVAL;
}
if (ENABLE_ROBUST_LIST2) {
REGISTER_SYSCALL_IMPL_X32(set_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, struct robust_list_head* head, size_t len) -> uint64_t {
if (len != 12) {
// Return invalid if the passed in length doesn't match what's expected.
return -EINVAL;
}

auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame);
// Retain the robust list head but don't give it to the kernel
// The kernel would break if it tried parsing a 32bit robust list from a 64bit process
ThreadObject->ThreadInfo.robust_list_head = reinterpret_cast<uint64_t>(head);
return 0;
});
auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame);
int Result = FEX::HLE::set_robust_list2(head, ThreadObject->ThreadInfo.robust_list_index_x32, FEX::HLE::ROBUST_LIST_32BIT);
if (Result != -1) {
// Index is returned back to us.
ThreadObject->ThreadInfo.robust_list_index_x32 = Result;
ThreadObject->ThreadInfo.robust_list_head_x32 = reinterpret_cast<uint64_t>(head);
Result = 0;
}

SYSCALL_ERRNO();
});
} else {
REGISTER_SYSCALL_IMPL_X32(set_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, struct robust_list_head* head, size_t len) -> uint64_t {
if (len != 12) {
// Return invalid if the passed in length doesn't match what's expected.
return -EINVAL;
}

auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame);
// Retain the robust list head but don't give it to the kernel
// The kernel would break if it tried parsing a 32bit robust list from a 64bit process
ThreadObject->ThreadInfo.robust_list_head_x32 = static_cast<uint32_t>(reinterpret_cast<uint64_t>(head));
return 0;
});
}

REGISTER_SYSCALL_IMPL_X32(
get_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, int pid, struct robust_list_head** head, uint32_t* len_ptr) -> uint64_t {
FaultSafeUserMemAccess::VerifyIsWritable(head, sizeof(uint32_t));
FaultSafeUserMemAccess::VerifyIsWritable(len_ptr, sizeof(*len_ptr));

auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame);
// Give the robust list back to the application
// Steam specifically checks to make sure the robust list is set
*(uint32_t*)head = (uint32_t)ThreadObject->ThreadInfo.robust_list_head;
*len_ptr = 12;
return 0;

if (pid == 0 || pid == ThreadObject->ThreadInfo.PID) {
FaultSafeUserMemAccess::VerifyIsWritable(head, sizeof(uint32_t));

// Give the robust list back to the application
// Steam specifically checks to make sure the robust list is set
*(uint32_t*)head = (uint32_t)ThreadObject->ThreadInfo.robust_list_head_x32;
*len_ptr = 12;
return 0;
}

return -EPERM;
});

REGISTER_SYSCALL_IMPL_X32(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ enum Syscalls_x64 {
SYSCALL_x64_lsm_set_self_attr = 460,
SYSCALL_x64_lsm_list_modules = 461,
SYSCALL_x64_mseal = 462,
SYSCALL_x64_set_robust_list2 = 468, // Subject to change
SYSCALL_x64_MAX = 512,

// Unsupported syscalls on this host
Expand Down
37 changes: 37 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,42 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) {
auto* const* EnvpPtr = envp ? const_cast<char* const*>(Envp.data()) : nullptr;
return FEX::HLE::ExecveHandler(Frame, pathname, ArgsPtr, EnvpPtr, AtArgs);
}));

if (ENABLE_ROBUST_LIST2) {
REGISTER_SYSCALL_IMPL_X64(set_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, struct robust_list_head* head, size_t len) -> uint64_t {
if (len != sizeof(struct robust_list_head)) {
// Return invalid if the passed in length doesn't match what's expected.
return -EINVAL;
}

auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame);
int Result = FEX::HLE::set_robust_list2(head, ThreadObject->ThreadInfo.robust_list_index_x64, FEX::HLE::ROBUST_LIST_64BIT);
if (Result != -1) {
// Index is returned back to us.
ThreadObject->ThreadInfo.robust_list_index_x64 = Result;
ThreadObject->ThreadInfo.robust_list_head_x64 = reinterpret_cast<uint64_t>(head);
Result = 0;
}

SYSCALL_ERRNO();
});

REGISTER_SYSCALL_IMPL_X64(
get_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, int pid, struct robust_list_head** head, uint32_t* len_ptr) -> uint64_t {
auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame);

if (pid == 0 || pid == ThreadObject->ThreadInfo.PID) {
FaultSafeUserMemAccess::VerifyIsWritable(head, sizeof(uint64_t));

// Give the robust list back to the application
// Steam specifically checks to make sure the robust list is set
*(uint64_t*)head = ThreadObject->ThreadInfo.robust_list_head_x64;
*len_ptr = sizeof(struct robust_list_head);
return 0;
}

return -EPERM;
});
}
}
} // namespace FEX::HLE::x64
Loading