mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-25 05:00:43 +01:00
Implements initial 32bit syscall support
This adds the initial 32bit syscalls for testing. No where near complete
This commit is contained in:
1 parent
667e514262
commit
10087f7757
10 files changed
+362
-3
No files matched your search
+4
@@ -78,6 +78,10 @@ set (SRCS
|
||||
Interface/HLE/FileManagement.cpp
|
||||
Interface/HLE/EmulatedFiles/EmulatedFiles.cpp
|
||||
Interface/HLE/Syscalls.cpp
|
||||
Interface/HLE/x32/Syscalls.cpp
|
||||
Interface/HLE/x32/FD.cpp
|
||||
Interface/HLE/x32/Memory.cpp
|
||||
Interface/HLE/x32/Thread.cpp
|
||||
Interface/HLE/x64/Syscalls.cpp
|
||||
Interface/HLE/Syscalls/EPoll.cpp
|
||||
Interface/HLE/Syscalls/FD.cpp
|
||||
|
||||
+4
-3
@@ -4,6 +4,7 @@
|
||||
#include "Interface/Core/InternalThreadState.h"
|
||||
#include "Interface/HLE/Syscalls.h"
|
||||
#include "Interface/HLE/x64/Syscalls.h"
|
||||
#include "Interface/HLE/x32/Syscalls.h"
|
||||
|
||||
#include "LogManager.h"
|
||||
|
||||
@@ -147,9 +148,9 @@ SyscallHandler *CreateHandler(Context::OperatingMode Mode, FEXCore::Context::Con
|
||||
if (Mode == Context::MODE_64BIT) {
|
||||
return FEXCore::HLE::x64::CreateHandler(ctx);
|
||||
}
|
||||
|
||||
LogMan::Msg::A("Don't yet handle 32bit syscalls");
|
||||
return nullptr;
|
||||
else {
|
||||
return FEXCore::HLE::x32::CreateHandler(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t HandleSyscall(SyscallHandler *Handler, FEXCore::Core::InternalThreadState *Thread, FEXCore::HLE::SyscallArguments *Args) {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "Interface/HLE/Syscalls.h"
|
||||
#include "Interface/HLE/x32/FD.h"
|
||||
#include "Interface/Context/Context.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct InternalThreadState;
|
||||
}
|
||||
|
||||
namespace FEXCore::HLE::x32 {
|
||||
uint32_t Writev(FEXCore::Core::InternalThreadState *Thread, int fd, const struct iovec_32 *iov, int iovcnt) {
|
||||
std::vector<iovec> Host_iovec(iovcnt);
|
||||
for (int i = 0; i < iovcnt; ++i) {
|
||||
Host_iovec[i].iov_base = reinterpret_cast<void*>(iov[i].iov_base);
|
||||
Host_iovec[i].iov_len = iov[i].iov_len;
|
||||
}
|
||||
uint64_t Result = ::writev(fd, &Host_iovec.at(0), iovcnt);
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "Interface/HLE/Syscalls.h"
|
||||
|
||||
#include <poll.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct InternalThreadState;
|
||||
}
|
||||
|
||||
namespace FEXCore::HLE::x32 {
|
||||
struct iovec_32 {
|
||||
uint32_t iov_base;
|
||||
uint32_t iov_len;
|
||||
};
|
||||
|
||||
uint32_t Writev(FEXCore::Core::InternalThreadState *Thread, int fd, const struct iovec_32 *iov, int iovcnt);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "Interface/HLE/Syscalls.h"
|
||||
#include "Interface/Context/Context.h"
|
||||
#include "Interface/Core/InternalThreadState.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct InternalThreadState;
|
||||
}
|
||||
|
||||
#define MEM_PASSTHROUGH
|
||||
namespace FEXCore::HLE::x32 {
|
||||
uint32_t Mmap(FEXCore::Core::InternalThreadState *Thread, void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
|
||||
#ifdef MAP_32BIT
|
||||
uint64_t Result = reinterpret_cast<uint64_t>(::mmap(addr, length, prot, flags, fd, offset));
|
||||
SYSCALL_ERRNO();
|
||||
#endif
|
||||
|
||||
#ifdef MEM_PASSTHROUGH
|
||||
if (!(flags & MAP_FIXED)) {
|
||||
uint64_t Result = reinterpret_cast<uint64_t>(::mmap(addr, length, prot, flags, fd, offset));
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
else {
|
||||
// Okay, MAP_32BIT doesn't exist here
|
||||
// We need to spin through the lower 32bit and try and find a free address
|
||||
// In the future we should definitely use a bitmap allocator to understand where we can place pages
|
||||
|
||||
// Skip the first page since we can never allocate that
|
||||
static uint64_t StartingPage = Core::PAGE_SIZE;
|
||||
constexpr uint64_t Max4GB = 0x1'0000'0000;
|
||||
flags |= MAP_FIXED_NOREPLACE;
|
||||
uint64_t Result{};
|
||||
for (; StartingPage < Max4GB; StartingPage += Core::PAGE_SIZE) {
|
||||
Result = reinterpret_cast<uint64_t>(::mmap(reinterpret_cast<void*>(StartingPage), length, prot, flags, fd, offset));
|
||||
if (Result != ~0ULL) {
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
// If we get here then we are out of memory
|
||||
return -ENOMEM;
|
||||
}
|
||||
#else
|
||||
return Thread->CTX->SyscallHandler->HandleMMAP(Thread, addr, length, prot, flags, fd, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct InternalThreadState;
|
||||
}
|
||||
|
||||
namespace FEXCore::HLE::x32 {
|
||||
uint32_t Mmap(FEXCore::Core::InternalThreadState *Thread, void *addr, size_t length, int prot, int flags, int fd, off_t offset);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
#include "Interface/Context/Context.h"
|
||||
|
||||
#include "Interface/HLE/Syscalls.h"
|
||||
#include "Interface/HLE/x32/Syscalls.h"
|
||||
#include "Interface/HLE/x32/FD.h"
|
||||
#include "Interface/HLE/x32/Memory.h"
|
||||
#include "Interface/HLE/x32/Thread.h"
|
||||
|
||||
#include "Interface/HLE/Syscalls/EPoll.h"
|
||||
#include "Interface/HLE/Syscalls/FD.h"
|
||||
#include "Interface/HLE/Syscalls/FS.h"
|
||||
#include "Interface/HLE/Syscalls/Info.h"
|
||||
#include "Interface/HLE/Syscalls/Ioctl.h"
|
||||
#include "Interface/HLE/Syscalls/Memory.h"
|
||||
#include "Interface/HLE/Syscalls/Numa.h"
|
||||
#include "Interface/HLE/Syscalls/Sched.h"
|
||||
#include "Interface/HLE/Syscalls/Semaphore.h"
|
||||
#include "Interface/HLE/Syscalls/SHM.h"
|
||||
#include "Interface/HLE/Syscalls/Signals.h"
|
||||
#include "Interface/HLE/Syscalls/Socket.h"
|
||||
#include "Interface/HLE/Syscalls/Thread.h"
|
||||
#include "Interface/HLE/Syscalls/Time.h"
|
||||
#include "Interface/HLE/Syscalls/Timer.h"
|
||||
|
||||
#include "LogManager.h"
|
||||
|
||||
namespace {
|
||||
uint64_t Unimplemented(FEXCore::Core::InternalThreadState *Thread) {
|
||||
LogMan::Msg::A("Unhandled system call");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t NopSuccess(FEXCore::Core::InternalThreadState *Thread) {
|
||||
return 0;
|
||||
}
|
||||
uint64_t NopFail(FEXCore::Core::InternalThreadState *Thread) {
|
||||
return -1ULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace FEXCore::HLE::x32 {
|
||||
|
||||
class x32SyscallHandler final : public FEXCore::SyscallHandler {
|
||||
public:
|
||||
x32SyscallHandler(FEXCore::Context::Context *ctx);
|
||||
|
||||
// In the case that the syscall doesn't hit the optimized path then we still need to go here
|
||||
uint64_t HandleSyscall(FEXCore::Core::InternalThreadState *Thread, FEXCore::HLE::SyscallArguments *Args) override;
|
||||
|
||||
#ifdef DEBUG_STRACE
|
||||
void Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void RegisterSyscallHandlers();
|
||||
};
|
||||
|
||||
#ifdef DEBUG_STRACE
|
||||
void x32SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret) {
|
||||
}
|
||||
#endif
|
||||
|
||||
x32SyscallHandler::x32SyscallHandler(FEXCore::Context::Context *ctx)
|
||||
: SyscallHandler {ctx} {
|
||||
RegisterSyscallHandlers();
|
||||
}
|
||||
|
||||
void x32SyscallHandler::RegisterSyscallHandlers() {
|
||||
Definitions.resize(FEXCore::HLE::x32::SYSCALL_MAX);
|
||||
auto cvt = [](auto in) {
|
||||
union {
|
||||
decltype(in) val;
|
||||
void *raw;
|
||||
} raw;
|
||||
raw.val = in;
|
||||
return raw.raw;
|
||||
};
|
||||
|
||||
// Clear all definitions
|
||||
for (auto &Def : Definitions) {
|
||||
Def.NumArgs = 255;
|
||||
Def.Ptr = cvt(&Unimplemented);
|
||||
}
|
||||
|
||||
const std::vector<std::tuple<uint16_t, void*, uint8_t>> Syscalls = {
|
||||
{SYSCALL_READ, cvt(&FEXCore::HLE::Read), 3},
|
||||
{SYSCALL_EXIT, cvt(&FEXCore::HLE::Exit), 1},
|
||||
{SYSCALL_WRITE, cvt(&FEXCore::HLE::Write), 3},
|
||||
{SYSCALL_CLOSE, cvt(&FEXCore::HLE::Close), 1},
|
||||
{SYSCALL_ACCESS, cvt(&FEXCore::HLE::Access), 2},
|
||||
{SYSCALL_BRK, cvt(&FEXCore::HLE::Brk), 1},
|
||||
{SYSCALL_WRITEV, cvt(&FEXCore::HLE::x32::Writev), 3},
|
||||
{SYSCALL_MMAP2, cvt(&FEXCore::HLE::x32::Mmap), 6},
|
||||
{SYSCALL_GETUID32, cvt(&FEXCore::HLE::Getuid), 0},
|
||||
{SYSCALL_GETGID32, cvt(&FEXCore::HLE::Getgid), 0},
|
||||
{SYSCALL_GETEUID32, cvt(&FEXCore::HLE::Geteuid), 0},
|
||||
{SYSCALL_GETEGID32, cvt(&FEXCore::HLE::Getegid), 0},
|
||||
{SYSCALL_FCNTL64, cvt(&FEXCore::HLE::Fcntl), 3},
|
||||
{SYSCALL_SET_THREAD_AREA, cvt(&FEXCore::HLE::x32::Set_thread_area), 1},
|
||||
{SYSCALL_EXIT_GROUP, cvt(&FEXCore::HLE::Exit_group), 1},
|
||||
{SYSCALL_ARCH_PRCTL, cvt(&FEXCore::HLE::Arch_Prctl), 2},
|
||||
{SYSCALL_OPENAT, cvt(&FEXCore::HLE::Openat), 4},
|
||||
};
|
||||
|
||||
// Set all the new definitions
|
||||
for (auto &Syscall : Syscalls) {
|
||||
auto &Def = Definitions.at(std::get<0>(Syscall));
|
||||
LogMan::Throw::A(Def.Ptr == cvt(&Unimplemented), "Oops overwriting sysall problem");
|
||||
Def.Ptr = std::get<1>(Syscall);
|
||||
Def.NumArgs = std::get<2>(Syscall);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t x32SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Thread, FEXCore::HLE::SyscallArguments *Args) {
|
||||
auto &Def = Definitions[Args->Argument[0]];
|
||||
//LogMan::Msg::D(">>>>>Syscall: %d", Args->Argument[0]);
|
||||
switch (Def.NumArgs) {
|
||||
case 0: return std::invoke(Def.Ptr0, Thread);
|
||||
case 1: return std::invoke(Def.Ptr1, Thread, Args->Argument[1]);
|
||||
case 2: return std::invoke(Def.Ptr2, Thread, Args->Argument[1], Args->Argument[2]);
|
||||
case 3: return std::invoke(Def.Ptr3, Thread, Args->Argument[1], Args->Argument[2], Args->Argument[3]);
|
||||
case 4: return std::invoke(Def.Ptr4, Thread, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4]);
|
||||
case 5: return std::invoke(Def.Ptr5, Thread, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5]);
|
||||
case 6: return std::invoke(Def.Ptr6, Thread, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5], Args->Argument[6]);
|
||||
default: break;
|
||||
}
|
||||
|
||||
LogMan::Msg::A("Unhandled syscall: %d", Args->Argument[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FEXCore::SyscallHandler *CreateHandler(FEXCore::Context::Context *ctx) {
|
||||
return new x32SyscallHandler(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "Interface/HLE/FileManagement.h"
|
||||
#include <FEXCore/HLE/SyscallHandler.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct InternalThreadState;
|
||||
}
|
||||
|
||||
namespace FEXCore {
|
||||
class SyscallHandler;
|
||||
}
|
||||
|
||||
namespace FEXCore::HLE::x32 {
|
||||
|
||||
///< Enum containing all supported x86 linux syscalls that we support
|
||||
enum Syscalls {
|
||||
SYSCALL_EXIT = 1,
|
||||
SYSCALL_READ = 3,
|
||||
SYSCALL_WRITE = 4,
|
||||
SYSCALL_CLOSE = 6,
|
||||
SYSCALL_ACCESS = 33,
|
||||
SYSCALL_BRK = 45,
|
||||
SYSCALL_WRITEV = 146,
|
||||
SYSCALL_MMAP2 = 192,
|
||||
SYSCALL_GETUID32 = 199,
|
||||
SYSCALL_GETGID32 = 200,
|
||||
SYSCALL_GETEUID32 = 201,
|
||||
SYSCALL_GETEGID32 = 202,
|
||||
SYSCALL_SETREUID32 = 203,
|
||||
SYSCALL_SETREGID32 = 204,
|
||||
SYSCALL_FCNTL64 = 221,
|
||||
SYSCALL_SET_THREAD_AREA = 243,
|
||||
SYSCALL_EXIT_GROUP = 252,
|
||||
SYSCALL_OPENAT = 295,
|
||||
SYSCALL_ARCH_PRCTL = 384,
|
||||
SYSCALL_MAX = 512,
|
||||
};
|
||||
|
||||
FEXCore::SyscallHandler *CreateHandler(FEXCore::Context::Context *ctx);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "Interface/Context/Context.h"
|
||||
#include "Interface/Core/InternalThreadState.h"
|
||||
#include "Interface/HLE/Syscalls.h"
|
||||
#include "Interface/HLE/x32/Thread.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace FEXCore::HLE::x32 {
|
||||
uint32_t Set_thread_area(FEXCore::Core::InternalThreadState *Thread, struct user_desc *u_info) {
|
||||
LogMan::Msg::D("Set_thread_area");
|
||||
LogMan::Msg::D("\tentry_number: %d", u_info->entry_number);
|
||||
LogMan::Msg::D("\tbase_addr: 0x%x", u_info->base_addr);
|
||||
LogMan::Msg::D("\tlimit: 0x%x", u_info->limit);
|
||||
LogMan::Msg::D("\tseg_32bit: %d", u_info->seg_32bit);
|
||||
LogMan::Msg::D("\tcontents: %d", u_info->contents);
|
||||
LogMan::Msg::D("\tread_exec_only: %d", u_info->read_exec_only);
|
||||
LogMan::Msg::D("\tlimit_in_pages: %d", u_info->limit_in_pages);
|
||||
LogMan::Msg::D("\tseg_not_present: %d", u_info->seg_not_present);
|
||||
LogMan::Msg::D("\tuseable: %d", u_info->useable);
|
||||
|
||||
static bool Initialized = false;
|
||||
if (Initialized == true) {
|
||||
LogMan::Msg::A("Trying to load a new GDT");
|
||||
}
|
||||
if (u_info->entry_number == -1) {
|
||||
u_info->entry_number = 12; // Sure?
|
||||
Initialized = true;
|
||||
}
|
||||
// Now we need to update the thread's GDT to handle this change
|
||||
auto GDT = &Thread->State.State.gdt[u_info->entry_number];
|
||||
GDT->base = u_info->base_addr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct InternalThreadState;
|
||||
}
|
||||
|
||||
namespace FEXCore::HLE::x32 {
|
||||
// We must define this ourselves since it doesn't exist on non-x86 platforms
|
||||
struct user_desc {
|
||||
uint32_t entry_number;
|
||||
uint32_t base_addr;
|
||||
uint32_t limit;
|
||||
uint32_t seg_32bit : 1;
|
||||
uint32_t contents : 2;
|
||||
uint32_t read_exec_only : 1;
|
||||
uint32_t limit_in_pages : 1;
|
||||
uint32_t seg_not_present : 1;
|
||||
uint32_t useable : 1;
|
||||
};
|
||||
|
||||
uint32_t Set_thread_area(FEXCore::Core::InternalThreadState *Thread, struct user_desc *u_info);
|
||||
}
|
||||
Reference in new issue
Block a user