diff --git a/src/common/config.cpp b/src/common/config.cpp index b55182ba6..12d711e2c 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -147,6 +147,7 @@ static ConfigEntry isSideTrophy("right"); static ConfigEntry isConnectedToNetwork(false); static bool enableDiscordRPC = false; static std::filesystem::path sys_modules_path = {}; +static std::filesystem::path fonts_path = {}; // Input static ConfigEntry cursorState(HideCursorState::Idle); @@ -239,6 +240,17 @@ void setSysModulesPath(const std::filesystem::path& path) { sys_modules_path = path; } +std::filesystem::path getFontsPath() { + if (fonts_path.empty()) { + return Common::FS::GetUserPath(Common::FS::PathType::FontsDir); + } + return fonts_path; +} + +void setFontsPath(const std::filesystem::path& path) { + fonts_path = path; +} + int getVolumeSlider() { return volumeSlider.get(); } @@ -906,6 +918,7 @@ void load(const std::filesystem::path& path, bool is_game_specific) { isConnectedToNetwork.setFromToml(general, "isConnectedToNetwork", is_game_specific); defaultControllerID.setFromToml(general, "defaultControllerID", is_game_specific); sys_modules_path = toml::find_fs_path_or(general, "sysModulesPath", sys_modules_path); + fonts_path = toml::find_fs_path_or(general, "fontsPath", fonts_path); } if (data.contains("Input")) { @@ -1184,6 +1197,7 @@ void save(const std::filesystem::path& path, bool is_game_specific) { // Non game-specific entries data["General"]["enableDiscordRPC"] = enableDiscordRPC; data["General"]["sysModulesPath"] = string{fmt::UTF(sys_modules_path.u8string()).data}; + data["General"]["fontsPath"] = string{fmt::UTF(fonts_path.u8string()).data}; data["GUI"]["installDirs"] = install_dirs; data["GUI"]["installDirsEnabled"] = install_dirs_enabled; data["GUI"]["saveDataPath"] = string{fmt::UTF(save_data_path.u8string()).data}; diff --git a/src/common/config.h b/src/common/config.h index 184cc97ff..062eb04db 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -157,6 +157,8 @@ void setConnectedToNetwork(bool enable, bool is_game_specific = false); void setUserName(const std::string& name, bool is_game_specific = false); std::filesystem::path getSysModulesPath(); void setSysModulesPath(const std::filesystem::path& path); +std::filesystem::path getFontsPath(); +void setFontsPath(const std::filesystem::path& path); enum UsbBackendType : int { Real, SkylandersPortal, InfinityBase, DimensionsToypad }; int getUsbDeviceBackend(); diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index b0cbb10cf..5d37990ff 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -128,6 +128,7 @@ static auto UserPaths = [] { create_path(PathType::CustomTrophy, user_dir / CUSTOM_TROPHY); create_path(PathType::CustomConfigs, user_dir / CUSTOM_CONFIGS); create_path(PathType::CacheDir, user_dir / CACHE_DIR); + create_path(PathType::FontsDir, user_dir / FONTS_DIR); std::ofstream notice_file(user_dir / CUSTOM_TROPHY / "Notice.txt"); if (notice_file.is_open()) { diff --git a/src/common/path_util.h b/src/common/path_util.h index fd2c18baa..434f77b0d 100644 --- a/src/common/path_util.h +++ b/src/common/path_util.h @@ -25,6 +25,7 @@ enum class PathType { CustomTrophy, // Where custom files for trophies are stored. CustomConfigs, // Where custom files for different games are stored. CacheDir, // Where pipeline and shader cache is stored. + FontsDir, // Where dumped system fonts are stored. }; constexpr auto PORTABLE_DIR = "user"; @@ -44,6 +45,7 @@ constexpr auto METADATA_DIR = "game_data"; constexpr auto CUSTOM_TROPHY = "custom_trophy"; constexpr auto CUSTOM_CONFIGS = "custom_configs"; constexpr auto CACHE_DIR = "cache"; +constexpr auto FONTS_DIR = "fonts"; // Filenames constexpr auto LOG_FILE = "shad_log.txt"; diff --git a/src/core/address_space.cpp b/src/core/address_space.cpp index 194f676f9..758c7240c 100644 --- a/src/core/address_space.cpp +++ b/src/core/address_space.cpp @@ -373,6 +373,7 @@ struct AddressSpace::Impl { } void* Map(VAddr virtual_addr, PAddr phys_addr, u64 size, ULONG prot, s32 fd = -1) { + std::scoped_lock lk{mutex}; // Get a pointer to the region containing virtual_addr auto it = std::prev(regions.upper_bound(virtual_addr)); @@ -441,6 +442,7 @@ struct AddressSpace::Impl { } void Unmap(VAddr virtual_addr, u64 size) { + std::scoped_lock lk{mutex}; // Loop through all regions in the requested range u64 remaining_size = size; VAddr current_addr = virtual_addr; @@ -481,6 +483,7 @@ struct AddressSpace::Impl { } void Protect(VAddr virtual_addr, u64 size, bool read, bool write, bool execute) { + std::scoped_lock lk{mutex}; DWORD new_flags{}; if (write && !read) { @@ -530,8 +533,9 @@ struct AddressSpace::Impl { DWORD old_flags{}; if (!VirtualProtectEx(process, LPVOID(range_addr), range_size, new_flags, &old_flags)) { UNREACHABLE_MSG( - "Failed to change virtual memory protection for address {:#x}, size {:#x}", - range_addr, range_size); + "Failed to change virtual memory protection for address {:#x}, size " + "{:#x}, error {}", + virtual_addr, size, Common::GetLastErrorMsg()); } } } @@ -544,6 +548,7 @@ struct AddressSpace::Impl { return reserved_regions; } + std::mutex mutex; HANDLE process{}; HANDLE backing_handle{}; u8* backing_base{}; diff --git a/src/core/libraries/kernel/kernel.h b/src/core/libraries/kernel/kernel.h index 057043131..581b2acab 100644 --- a/src/core/libraries/kernel/kernel.h +++ b/src/core/libraries/kernel/kernel.h @@ -17,6 +17,7 @@ void ErrSceToPosix(s32 result); s32 ErrnoToSceKernelError(s32 e); void SetPosixErrno(s32 e); s32* PS4_SYSV_ABI __Error(); +const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord(); extern Core::EntryParams entry_params; diff --git a/src/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp index 5f50b8a7d..b31ed1f0b 100644 --- a/src/core/libraries/pad/pad.cpp +++ b/src/core/libraries/pad/pad.cpp @@ -397,6 +397,9 @@ int ProcessStates(s32 handle, OrbisPadData* pData, Input::State* states, s32 num int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) { LOG_TRACE(Lib_Pad, "called"); + if (handle < 1) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } int connected_count = 0; bool connected = false; std::vector states(64); @@ -428,7 +431,7 @@ int PS4_SYSV_ABI scePadReadHistory() { int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) { LOG_TRACE(Lib_Pad, "called"); - if (handle == ORBIS_PAD_ERROR_DEVICE_NO_HANDLE) { + if (handle < 1) { return ORBIS_PAD_ERROR_INVALID_HANDLE; } auto* controller = Common::Singleton::Instance(); diff --git a/src/emulator.cpp b/src/emulator.cpp index 0dde0b7fa..87ce82326 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -36,6 +36,7 @@ #include "core/libraries/font/font.h" #include "core/libraries/font/fontft.h" #include "core/libraries/jpeg/jpegenc.h" +#include "core/libraries/kernel/kernel.h" #include "core/libraries/libc_internal/libc_internal.h" #include "core/libraries/libpng/pngenc.h" #include "core/libraries/libs.h" @@ -368,6 +369,34 @@ void Emulator::Run(std::filesystem::path file, std::vector args, } VideoCore::SetOutputDir(mount_captures_dir, id); + // Mount system fonts + const auto& fonts_dir = Config::getFontsPath(); + if (!std::filesystem::exists(fonts_dir)) { + std::filesystem::create_directory(fonts_dir); + } + + // Fonts are mounted into the sandboxed system directory, construct the appropriate path. + const char* sandbox_root = Libraries::Kernel::sceKernelGetFsSandboxRandomWord(); + std::string guest_font_dir = "/"; + guest_font_dir.append(sandbox_root).append("/common/font"); + const auto& host_font_dir = fonts_dir / "font"; + if (!std::filesystem::exists(host_font_dir)) { + std::filesystem::create_directory(host_font_dir); + } + mnt->Mount(host_font_dir, guest_font_dir); + + // There is a second font directory, mount that too. + guest_font_dir.append("2"); + const auto& host_font2_dir = fonts_dir / "font2"; + if (!std::filesystem::exists(host_font2_dir)) { + std::filesystem::create_directory(host_font2_dir); + } + mnt->Mount(host_font2_dir, guest_font_dir); + + if (std::filesystem::is_empty(host_font_dir) || std::filesystem::is_empty(host_font2_dir)) { + LOG_WARNING(Loader, "No dumped system fonts, expect missing text or instability"); + } + // Initialize kernel and library facilities. Libraries::InitHLELibs(&linker->GetHLESymbols()); diff --git a/src/input/input_mouse.cpp b/src/input/input_mouse.cpp index 0dc44608b..19daab3d6 100644 --- a/src/input/input_mouse.cpp +++ b/src/input/input_mouse.cpp @@ -85,7 +85,7 @@ void EmulateJoystick(GameController* controller, u32 interval) { } } -constexpr float constant_down_accel[3] = {0.0f, 10.0f, 0.0f}; +constexpr float constant_down_accel[3] = {0.0f, 9.81f, 0.0f}; void EmulateGyro(GameController* controller, u32 interval) { float d_x = 0, d_y = 0; SDL_GetRelativeMouseState(&d_x, &d_y); diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 1ee107efe..ae4646de6 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -270,7 +270,7 @@ namespace Frontend { using namespace Libraries::Pad; std::mutex motion_control_mutex; -float gyro_buf[3] = {0.0f, 0.0f, 0.0f}, accel_buf[3] = {0.0f, -9.81f, 0.0f}; +float gyro_buf[3] = {0.0f, 0.0f, 0.0f}, accel_buf[3] = {0.0f, 9.81f, 0.0f}; static Uint32 SDLCALL PollGyroAndAccel(void* userdata, SDL_TimerID timer_id, Uint32 interval) { auto* controller = reinterpret_cast(userdata); std::scoped_lock l{motion_control_mutex};