diff --git a/External/FEXCore/Source/Interface/Context/Context.h b/External/FEXCore/Source/Interface/Context/Context.h index b3cbdf56e..3f09d3d11 100644 --- a/External/FEXCore/Source/Interface/Context/Context.h +++ b/External/FEXCore/Source/Interface/Context/Context.h @@ -82,7 +82,7 @@ namespace FEXCore::Context { FEX_CONFIG_OPT(Core, DEFAULTCORE); FEX_CONFIG_OPT(MaxInstPerBlock, MAXBLOCKINST); FEX_CONFIG_OPT(RootFSPath, ROOTFSPATH); - FEX_CONFIG_OPT(ThunkLibsPath, THUNKLIBSPATH); + FEX_CONFIG_OPT(ThunkHostLibsPath, THUNKHOSTLIBSPATH); FEX_CONFIG_OPT(DumpIR, DUMPIR); } Config; diff --git a/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp b/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp index 27fd7b60e..fa169beeb 100644 --- a/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp +++ b/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp @@ -56,7 +56,7 @@ namespace FEXCore { auto Name = Args->Name; auto CallbackThunks = Args->CallbackThunks; - auto SOName = CTX->Config.ThunkLibsPath() + "/" + (const char*)Name + "-host.so"; + auto SOName = CTX->Config.ThunkHostLibsPath() + "/" + (const char*)Name + "-host.so"; LogMan::Msg::D("Load lib: %s -> %s", Name, SOName.c_str()); diff --git a/External/FEXCore/include/FEXCore/Config/ConfigValues.inl b/External/FEXCore/include/FEXCore/Config/ConfigValues.inl index 373a309e9..810865f6f 100644 --- a/External/FEXCore/include/FEXCore/Config/ConfigValues.inl +++ b/External/FEXCore/include/FEXCore/Config/ConfigValues.inl @@ -36,8 +36,9 @@ OPT_INT32 (CPU, MAXBLOCKINST, MaxInst, MAXINST, 5000) OPT_INT32 (CPU, EMULATED_CPU_CORES, Threads, THREADS, 1) OPT_STR (EMULATION, ROOTFSPATH, RootFS, ROOTFS, "") -OPT_STR (EMULATION, THUNKLIBSPATH, ThunkLibs, THUNKLIBS, "") -OPT_STR (EMULATION, THUNKSCONFIGPATH, ThunksConfigPath, THUNKSCONFIGPATH, "") +OPT_STR (EMULATION, THUNKHOSTLIBSPATH, ThunkHostLibs, THUNKHOSTLIBS, "") +OPT_STR (EMULATION, THUNKGUESTLIBSPATH, ThunkGuestLibs, THUNKGUESTLIBS, "") +OPT_STR (EMULATION, THUNKCONFIGPATH, ThunkConfig, THUNKCONFIG, "") OPT_STR (EMULATION, ENVIRONMENT, Env, ENV, "") diff --git a/Source/Common/ArgumentLoader.cpp b/Source/Common/ArgumentLoader.cpp index f063c4d5f..b3571c293 100644 --- a/Source/Common/ArgumentLoader.cpp +++ b/Source/Common/ArgumentLoader.cpp @@ -94,16 +94,26 @@ namespace FEX::ArgLoader { } { Parser.set_defaults("RootFS", ""); - Parser.set_defaults("ThunkLibs", ""); + Parser.set_defaults("ThunkHostLibs", ""); + Parser.set_defaults("ThunkGuestLibs", ""); + Parser.set_defaults("ThunkConfig", ""); EmulationGroup.add_option("-R", "--rootfs") .dest("RootFS") .help("Which Root filesystem prefix to use"); - EmulationGroup.add_option("-t", "--thunklibs") - .dest("ThunkLibs") + EmulationGroup.add_option("-t", "--thunkhostlibs") + .dest("ThunkHostLibs") .help("Folder to find the host-side thunking libs"); + EmulationGroup.add_option("-j", "--thunkguestlibs") + .dest("ThunkGuestLibs") + .help("Folder to find the guest-side thunking libs"); + + EmulationGroup.add_option("-k", "--thunkconfig") + .dest("ThunkConfig") + .help("A json file specifying where to overlay the thunks"); + EmulationGroup.add_option("-E", "--env") .dest("Env") .help("Adds an environment variable") @@ -248,9 +258,19 @@ namespace FEX::ArgLoader { Set(FEXCore::Config::ConfigOption::CONFIG_ROOTFSPATH, Option); } - if (Options.is_set_by_user("ThunkLibs")) { - std::string Option = Options["ThunkLibs"]; - Set(FEXCore::Config::ConfigOption::CONFIG_THUNKLIBSPATH, Option); + if (Options.is_set_by_user("ThunkHostLibs")) { + std::string Option = Options["ThunkHostLibs"]; + Set(FEXCore::Config::ConfigOption::CONFIG_THUNKHOSTLIBSPATH, Option); + } + + if (Options.is_set_by_user("ThunkGuestLibs")) { + std::string Option = Options["ThunkGuestLibs"]; + Set(FEXCore::Config::ConfigOption::CONFIG_THUNKGUESTLIBSPATH, Option); + } + + if (Options.is_set_by_user("ThunkConfig")) { + std::string Option = Options["ThunkConfig"]; + Set(FEXCore::Config::ConfigOption::CONFIG_THUNKCONFIGPATH, Option); } if (Options.is_set_by_user("Env")) { diff --git a/Source/Tests/LinuxSyscalls/FileManagement.cpp b/Source/Tests/LinuxSyscalls/FileManagement.cpp index 9fe9a0103..096315e81 100644 --- a/Source/Tests/LinuxSyscalls/FileManagement.cpp +++ b/Source/Tests/LinuxSyscalls/FileManagement.cpp @@ -15,18 +15,109 @@ #include #include +#include + +#include +#include + namespace FEX::HLE { +static bool LoadFile(std::vector &Data, const std::string &Filename) { + std::fstream File; + File.open(Filename, std::ios::in); + + if (!File.is_open()) { + return false; + } + + if (!File.seekg(0, std::fstream::end)) { + LogMan::Msg::D("Couldn't load configuration file: Seek end"); + return false; + } + + auto FileSize = File.tellg(); + if (File.fail()) { + LogMan::Msg::D("Couldn't load configuration file: tellg"); + return false; + } + + if (!File.seekg(0, std::fstream::beg)) { + LogMan::Msg::D("Couldn't load configuration file: Seek beginning"); + return false; + } + + if (FileSize > 0) { + Data.resize(FileSize); + if (!File.read(&Data.at(0), FileSize)) { + // Probably means permissions aren't set. Just early exit + return false; + } + File.close(); + } + else { + return false; + } + + return true; +} + FileManager::FileManager(FEXCore::Context::Context *ctx) : EmuFD {ctx} { - // calculate the non-self link to exe - // Some executables do getpid, stat("/proc/$pid/exe") - int pid = getpid(); + // calculate the non-self link to exe + // Some executables do getpid, stat("/proc/$pid/exe") + int pid = getpid(); - char buf[50]; - snprintf(buf, 50, "/proc/%i/exe", pid); + char buf[50]; + snprintf(buf, 50, "/proc/%i/exe", pid); - PidSelfPath = std::string(buf); + PidSelfPath = std::string(buf); + + + auto ThunkConfigFile = ThunkConfig(); + + if (ThunkConfigFile.size()) { + + auto ThunkGuestPath = std::filesystem::path(ThunkGuestLibs()); + + std::vector FileData; + if (LoadFile(FileData, ThunkConfigFile)) { + FileData.push_back(0); + + json_t mem[128]; + json_t const* json = json_create( &FileData.at(0), mem, sizeof mem / sizeof *mem ); + + json_t const* thunks = json_getProperty( json, "thunks" ); + if ( !thunks || JSON_OBJ != json_getType( thunks ) ) { + return; + } + + json_t const* thunk; + for( thunk = json_getChild( thunks ); thunk != 0; thunk = json_getSibling( thunk )) { + char const* GuestThunk = json_getName( thunk ); + jsonType_t propertyType = json_getType( thunk ); + + if (propertyType == JSON_TEXT) { + char const* RootFSLib = json_getValue( thunk ); + ThunkOverlays.emplace(RootFSLib, ThunkGuestPath / GuestThunk); + } else if (propertyType == JSON_ARRAY) { + json_t const* child; + for( child = json_getChild( thunk ); child != 0; child = json_getSibling( child ) ) { + if (json_getType( child ) == JSON_TEXT) { + char const* RootFSLib = json_getValue( child ); + ThunkOverlays.emplace(RootFSLib, ThunkGuestPath / GuestThunk); + } + } + } + } + } + + if (ThunkOverlays.size()) { + LogMan::Msg::I("Thunk Overlays:"); + for (auto &Thunk: ThunkOverlays) { + LogMan::Msg::I("\t%s -> %s", Thunk.first.c_str(), Thunk.second.c_str()); + } + } + } } FileManager::~FileManager() { @@ -40,6 +131,11 @@ std::string FileManager::GetEmulatedPath(const char *pathname) { return {}; } + auto thunkOverlay = ThunkOverlays.find(pathname); + if (thunkOverlay != ThunkOverlays.end()) { + return thunkOverlay->second; + } + return RootFSPath + pathname; } diff --git a/Source/Tests/LinuxSyscalls/FileManagement.h b/Source/Tests/LinuxSyscalls/FileManagement.h index 21f095712..2c45b646d 100644 --- a/Source/Tests/LinuxSyscalls/FileManagement.h +++ b/Source/Tests/LinuxSyscalls/FileManagement.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.h" @@ -49,8 +50,12 @@ private: std::unordered_map FDToNameMap; std::string PidSelfPath; std::string GetEmulatedPath(const char *pathname); + std::map ThunkOverlays; FEX_CONFIG_OPT(Filename, APP_FILENAME); FEX_CONFIG_OPT(LDPath, ROOTFSPATH); + FEX_CONFIG_OPT(ThunkHostLibs, THUNKHOSTLIBSPATH); + FEX_CONFIG_OPT(ThunkGuestLibs, THUNKGUESTLIBSPATH); + FEX_CONFIG_OPT(ThunkConfig, THUNKCONFIGPATH); }; } diff --git a/Source/Tools/FEXConfig/Main.cpp b/Source/Tools/FEXConfig/Main.cpp index 3e92ba989..50aed56bd 100644 --- a/Source/Tools/FEXConfig/Main.cpp +++ b/Source/Tools/FEXConfig/Main.cpp @@ -63,7 +63,9 @@ namespace { LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_GDBSERVER, "0"); LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_EMULATED_CPU_CORES, "1"); LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_ROOTFSPATH, ""); - LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_THUNKLIBSPATH, ""); + LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_THUNKHOSTLIBSPATH, ""); + LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_THUNKGUESTLIBSPATH, ""); + LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_THUNKCONFIGPATH, ""); LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_SILENTLOGS, "0"); LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_ENVIRONMENT, "GALLIUM_THREAD=1"); LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_ENVIRONMENT, "GALLIUM_HUD=fps"); @@ -198,7 +200,9 @@ namespace { void FillEmulationConfig() { char RootFS[256]{}; - char ThunkPath[256]{}; + char ThunkHostPath[256]{}; + char ThunkGuestPath[256]{}; + char ThunkConfigPath[256]{}; int NumEnvironmentVariables{}; @@ -212,12 +216,30 @@ namespace { ConfigChanged = true; } - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_THUNKLIBSPATH); + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_THUNKHOSTLIBSPATH); if (Value.has_value() && !(*Value)->empty()) { - strncpy(ThunkPath, &(*Value)->at(0), 256); + strncpy(ThunkHostPath, &(*Value)->at(0), 256); } - if (ImGui::InputText("Thunk library folder:", ThunkPath, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_THUNKLIBSPATH, ThunkPath); + if (ImGui::InputText("Thunk Host library folder:", ThunkHostPath, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_THUNKHOSTLIBSPATH, ThunkHostPath); + ConfigChanged = true; + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_THUNKGUESTLIBSPATH); + if (Value.has_value() && !(*Value)->empty()) { + strncpy(ThunkGuestPath, &(*Value)->at(0), 256); + } + if (ImGui::InputText("Thunk Guest library folder:", ThunkGuestPath, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_THUNKGUESTLIBSPATH, ThunkGuestPath); + ConfigChanged = true; + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_THUNKCONFIGPATH); + if (Value.has_value() && !(*Value)->empty()) { + strncpy(ThunkConfigPath, &(*Value)->at(0), 256); + } + if (ImGui::InputText("Thunk Config file:", ThunkConfigPath, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_THUNKCONFIGPATH, ThunkConfigPath); ConfigChanged = true; }