Merge pull request #293 from shadps4-emu/misc-fixes3

Various linux fixes
This commit is contained in:
georgemoralis 2024-07-15 15:25:20 +03:00 committed by GitHub
commit 0de914995f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 172 additions and 165 deletions

View File

@ -59,6 +59,7 @@ endif()
# SDL3 # SDL3
if (NOT TARGET SDL3::SDL3) if (NOT TARGET SDL3::SDL3)
set(SDL_PIPEWIRE OFF)
add_subdirectory(sdl3) add_subdirectory(sdl3)
endif() endif()

View File

@ -205,9 +205,9 @@ public:
return WriteSpan(string); return WriteSpan(string);
} }
static void WriteBytes(const std::filesystem::path path, std::span<u8> vec) { static void WriteBytes(const std::filesystem::path path, std::span<const u8> data) {
IOFile out(path, FileAccessMode::Write); IOFile out(path, FileAccessMode::Write);
out.Write(vec); out.Write(data);
} }
private: private:

View File

@ -11,18 +11,12 @@ constexpr int RESERVED_HANDLES = 3; // First 3 handles are stdin,stdout,stderr
void MntPoints::Mount(const std::filesystem::path& host_folder, const std::string& guest_folder) { void MntPoints::Mount(const std::filesystem::path& host_folder, const std::string& guest_folder) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
m_mnt_pairs.emplace_back(host_folder, guest_folder);
MntPair pair;
pair.host_path = host_folder.string();
std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/');
pair.guest_path = guest_folder;
m_mnt_pairs.push_back(pair);
} }
void MntPoints::Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder) { void MntPoints::Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder) {
auto it = std::remove_if(m_mnt_pairs.begin(), m_mnt_pairs.end(), auto it = std::remove_if(m_mnt_pairs.begin(), m_mnt_pairs.end(),
[&](const MntPair& pair) { return pair.guest_path == guest_folder; }); [&](const MntPair& pair) { return pair.mount == guest_folder; });
m_mnt_pairs.erase(it, m_mnt_pairs.end()); m_mnt_pairs.erase(it, m_mnt_pairs.end());
} }
@ -31,47 +25,79 @@ void MntPoints::UnmountAll() {
m_mnt_pairs.clear(); m_mnt_pairs.clear();
} }
std::string MntPoints::GetHostDirectory(const std::string& guest_directory) { std::filesystem::path MntPoints::GetHostPath(const std::string& guest_directory) {
std::scoped_lock lock{m_mutex}; const MntPair* mount = GetMount(guest_directory);
for (auto& pair : m_mnt_pairs) { if (!mount) {
// horrible code but it works :D return guest_directory;
int find = guest_directory.find(pair.guest_path);
if (find == 0) {
std::string npath =
guest_directory.substr(pair.guest_path.size(), guest_directory.size() - 1);
std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/');
return pair.host_path + npath;
}
}
return "";
} }
std::string MntPoints::GetHostFile(const std::string& guest_file) { // Nothing to do if getting the mount itself.
std::scoped_lock lock{m_mutex}; if (guest_directory == mount->mount) {
return mount->host_path;
}
for (auto& pair : m_mnt_pairs) { // Remove device (e.g /app0) from path to retrieve relative path.
// horrible code but it works :D const u32 pos = mount->mount.size() + 1;
int find = guest_file.find(pair.guest_path); const auto rel_path = std::string_view(guest_directory).substr(pos);
if (find != 0) { const auto host_path = mount->host_path / rel_path;
continue; if (!NeedsCaseInsensiveSearch) {
}
std::string npath = guest_file.substr(pair.guest_path.size(), guest_file.size() - 1);
const auto host_path = pair.host_path + npath;
#ifndef _WIN64
const std::filesystem::path path{host_path};
if (!std::filesystem::exists(path)) {
const auto filename = Common::ToLower(path.filename());
for (const auto& file : std::filesystem::directory_iterator(path.parent_path())) {
const auto exist_filename = Common::ToLower(file.path().filename());
if (filename == exist_filename) {
return file.path();
}
}
}
#endif
return host_path; return host_path;
} }
return "";
// If the path does not exist attempt to verify this.
// Retrieve parent path until we find one that exists.
path_parts.clear();
auto current_path = host_path;
while (!std::filesystem::exists(current_path)) {
// We have probably cached this if it's a folder.
if (auto it = path_cache.find(current_path); it != path_cache.end()) {
current_path = it->second;
break;
}
path_parts.emplace_back(current_path.filename());
current_path = current_path.parent_path();
}
// We have found an anchor. Traverse parts we recoded and see if they
// exist in filesystem but in different case.
auto guest_path = current_path;
while (!path_parts.empty()) {
const auto& part = path_parts.back();
const auto add_match = [&](const auto& host_part) {
current_path += host_part;
guest_path += part;
path_cache[guest_path] = current_path;
path_parts.pop_back();
};
// Can happen when the mismatch is in upper folder.
if (std::filesystem::exists(current_path / part)) {
add_match(part);
continue;
}
const auto part_low = Common::ToLower(part.string());
bool found_match = false;
for (const auto& path : std::filesystem::directory_iterator(current_path)) {
const auto candidate = path.path().filename();
const auto filename = Common::ToLower(candidate.string());
// Check if a filename matches in case insensitive manner.
if (filename != part_low) {
continue;
}
// We found a match, record the actual path in the cache.
add_match(candidate);
found_match = true;
break;
}
if (!found_match) {
// Opening the guest path will surely fail but at least gives
// a better error message than the empty path.
return host_path;
}
}
// The path was found.
return current_path;
} }
int HandleTable::CreateHandle() { int HandleTable::CreateHandle() {
@ -105,14 +131,9 @@ File* HandleTable::GetFile(int d) {
return m_files.at(d - RESERVED_HANDLES); return m_files.at(d - RESERVED_HANDLES);
} }
File* HandleTable::getFile(const std::string& host_name) { File* HandleTable::GetFile(const std::filesystem::path& host_name) {
std::scoped_lock lock{m_mutex}; const auto it = std::ranges::find(m_files, host_name, &File::m_host_name);
for (auto* file : m_files) { return it == m_files.end() ? nullptr : *it;
if (file != nullptr && file->m_host_name == host_name) {
return file;
}
}
return nullptr;
} }
} // namespace Core::FileSys } // namespace Core::FileSys

View File

@ -7,28 +7,42 @@
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <vector> #include <vector>
#include <tsl/robin_map.h>
#include "common/io_file.h" #include "common/io_file.h"
namespace Core::FileSys { namespace Core::FileSys {
class MntPoints { class MntPoints {
#ifdef _WIN64
static constexpr bool NeedsCaseInsensiveSearch = false;
#else
static constexpr bool NeedsCaseInsensiveSearch = true;
#endif
public: public:
struct MntPair { struct MntPair {
std::string host_path; std::filesystem::path host_path;
std::string guest_path; // e.g /app0/ std::string mount; // e.g /app0/
}; };
MntPoints() = default; explicit MntPoints() = default;
virtual ~MntPoints() = default; ~MntPoints() = default;
void Mount(const std::filesystem::path& host_folder, const std::string& guest_folder); void Mount(const std::filesystem::path& host_folder, const std::string& guest_folder);
void Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder); void Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder);
void UnmountAll(); void UnmountAll();
std::string GetHostDirectory(const std::string& guest_directory);
std::string GetHostFile(const std::string& guest_file); std::filesystem::path GetHostPath(const std::string& guest_directory);
const MntPair* GetMount(const std::string& guest_path) {
const auto it = std::ranges::find_if(
m_mnt_pairs, [&](const auto& mount) { return guest_path.starts_with(mount.mount); });
return it == m_mnt_pairs.end() ? nullptr : &*it;
}
private: private:
std::vector<MntPair> m_mnt_pairs; std::vector<MntPair> m_mnt_pairs;
std::vector<std::filesystem::path> path_parts;
tsl::robin_map<std::filesystem::path, std::filesystem::path> path_cache;
std::mutex m_mutex; std::mutex m_mutex;
}; };
@ -40,7 +54,7 @@ struct DirEntry {
struct File { struct File {
std::atomic_bool is_opened{}; std::atomic_bool is_opened{};
std::atomic_bool is_directory{}; std::atomic_bool is_directory{};
std::string m_host_name; std::filesystem::path m_host_name;
std::string m_guest_name; std::string m_guest_name;
Common::FS::IOFile f; Common::FS::IOFile f;
std::vector<DirEntry> dirents; std::vector<DirEntry> dirents;
@ -56,7 +70,7 @@ public:
int CreateHandle(); int CreateHandle();
void DeleteHandle(int d); void DeleteHandle(int d);
File* GetFile(int d); File* GetFile(int d);
File* getFile(const std::string& host_name); File* GetFile(const std::filesystem::path& host_name);
private: private:
std::vector<File*> m_files; std::vector<File*> m_files;

View File

@ -7,8 +7,6 @@
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/kernel/event_queues.h" #include "core/libraries/kernel/event_queues.h"
#include <boost/asio/placeholders.hpp>
namespace Libraries::Kernel { namespace Libraries::Kernel {
extern boost::asio::io_context io_context; extern boost::asio::io_context io_context;
@ -136,8 +134,7 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec*
event.timer = std::make_unique<boost::asio::steady_timer>( event.timer = std::make_unique<boost::asio::steady_timer>(
io_context, std::chrono::microseconds(total_us - HrTimerSpinlockThresholdUs)); io_context, std::chrono::microseconds(total_us - HrTimerSpinlockThresholdUs));
event.timer->async_wait( event.timer->async_wait(std::bind(SmallTimerCallback, std::placeholders::_1, eq, event.event));
std::bind(SmallTimerCallback, boost::asio::placeholders::error, eq, event.event));
if (!eq->AddEvent(event)) { if (!eq->AddEvent(event)) {
return ORBIS_KERNEL_ERROR_ENOMEM; return ORBIS_KERNEL_ERROR_ENOMEM;

View File

@ -13,7 +13,7 @@
namespace Libraries::Kernel { namespace Libraries::Kernel {
std::vector<Core::FileSys::DirEntry> GetDirectoryEntries(const std::string& path) { std::vector<Core::FileSys::DirEntry> GetDirectoryEntries(const std::filesystem::path& path) {
std::vector<Core::FileSys::DirEntry> files; std::vector<Core::FileSys::DirEntry> files;
for (const auto& entry : std::filesystem::directory_iterator(path)) { for (const auto& entry : std::filesystem::directory_iterator(path)) {
auto& dir_entry = files.emplace_back(); auto& dir_entry = files.emplace_back();
@ -58,7 +58,7 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
if (directory) { if (directory) {
file->is_directory = true; file->is_directory = true;
file->m_guest_name = path; file->m_guest_name = path;
file->m_host_name = mnt->GetHostDirectory(file->m_guest_name); file->m_host_name = mnt->GetHostPath(file->m_guest_name);
if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist
h->DeleteHandle(handle); h->DeleteHandle(handle);
return ORBIS_KERNEL_ERROR_ENOTDIR; return ORBIS_KERNEL_ERROR_ENOTDIR;
@ -72,7 +72,7 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
} }
} else { } else {
file->m_guest_name = path; file->m_guest_name = path;
file->m_host_name = mnt->GetHostFile(file->m_guest_name); file->m_host_name = mnt->GetHostPath(file->m_guest_name);
int e = 0; int e = 0;
if (read) { if (read) {
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read); e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read);
@ -165,8 +165,7 @@ int PS4_SYSV_ABI sceKernelUnlink(const char* path) {
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance(); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
std::string host_path = mnt->GetHostFile(path); const auto host_path = mnt->GetHostPath(path);
if (host_path.empty()) { if (host_path.empty()) {
return SCE_KERNEL_ERROR_EACCES; return SCE_KERNEL_ERROR_EACCES;
} }
@ -175,7 +174,7 @@ int PS4_SYSV_ABI sceKernelUnlink(const char* path) {
return SCE_KERNEL_ERROR_EPERM; return SCE_KERNEL_ERROR_EPERM;
} }
auto* file = h->getFile(host_path); auto* file = h->GetFile(host_path);
if (file != nullptr) { if (file != nullptr) {
file->f.Unlink(); file->f.Unlink();
} }
@ -250,7 +249,7 @@ int PS4_SYSV_ABI sceKernelMkdir(const char* path, u16 mode) {
return SCE_KERNEL_ERROR_EINVAL; return SCE_KERNEL_ERROR_EINVAL;
} }
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
std::string dir_name = mnt->GetHostFile(path); const auto dir_name = mnt->GetHostPath(path);
if (std::filesystem::exists(dir_name)) { if (std::filesystem::exists(dir_name)) {
return SCE_KERNEL_ERROR_EEXIST; return SCE_KERNEL_ERROR_EEXIST;
} }
@ -279,7 +278,7 @@ int PS4_SYSV_ABI posix_mkdir(const char* path, u16 mode) {
int PS4_SYSV_ABI sceKernelStat(const char* path, OrbisKernelStat* sb) { int PS4_SYSV_ABI sceKernelStat(const char* path, OrbisKernelStat* sb) {
LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path); LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path);
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto& path_name = mnt->GetHostFile(path); const auto path_name = mnt->GetHostPath(path);
std::memset(sb, 0, sizeof(OrbisKernelStat)); std::memset(sb, 0, sizeof(OrbisKernelStat));
const bool is_dir = std::filesystem::is_directory(path_name); const bool is_dir = std::filesystem::is_directory(path_name);
const bool is_file = std::filesystem::is_regular_file(path_name); const bool is_file = std::filesystem::is_regular_file(path_name);
@ -314,7 +313,7 @@ int PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
int PS4_SYSV_ABI sceKernelCheckReachability(const char* path) { int PS4_SYSV_ABI sceKernelCheckReachability(const char* path) {
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
std::string path_name = mnt->GetHostFile(path); const auto path_name = mnt->GetHostPath(path);
if (!std::filesystem::exists(path_name)) { if (!std::filesystem::exists(path_name)) {
return SCE_KERNEL_ERROR_ENOENT; return SCE_KERNEL_ERROR_ENOENT;
} }

View File

@ -222,7 +222,7 @@ s32 PS4_SYSV_ABI sceKernelLoadStartModule(const char* moduleFileName, size_t arg
} }
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto path = mnt->GetHostFile(moduleFileName); const auto path = mnt->GetHostPath(moduleFileName);
// Load PRX module and relocate any modules that import it. // Load PRX module and relocate any modules that import it.
auto* linker = Common::Singleton<Core::Linker>::Instance(); auto* linker = Common::Singleton<Core::Linker>::Instance();

View File

@ -1006,17 +1006,7 @@ ScePthread PThreadPool::Create() {
} }
} }
#ifdef _WIN64
auto* ret = new PthreadInternal{}; auto* ret = new PthreadInternal{};
#else
// TODO: Linux specific hack
static u8* hint_address = reinterpret_cast<u8*>(0x7FFFFC000ULL);
auto* ret = reinterpret_cast<PthreadInternal*>(
mmap(hint_address, sizeof(PthreadInternal), PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0));
hint_address += Common::AlignUp(sizeof(PthreadInternal), 4_KB);
#endif
ret->is_free = false; ret->is_free = false;
ret->is_detached = false; ret->is_detached = false;
ret->is_almost_done = false; ret->is_almost_done = false;

View File

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h" #include "common/logging/log.h"
#include "common/singleton.h" #include "common/singleton.h"
#include "core/file_sys/fs.h" #include "core/file_sys/fs.h"
#include "core/libraries/libc/libc_stdio.h" #include "core/libraries/libc/libc_stdio.h"
@ -10,11 +10,12 @@ namespace Libraries::LibC {
std::FILE* PS4_SYSV_ABI ps4_fopen(const char* filename, const char* mode) { std::FILE* PS4_SYSV_ABI ps4_fopen(const char* filename, const char* mode) {
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
FILE* f = std::fopen(mnt->GetHostFile(filename).c_str(), mode); const auto host_path = mnt->GetHostPath(filename).string();
FILE* f = std::fopen(host_path.c_str(), mode);
if (f != nullptr) { if (f != nullptr) {
LOG_INFO(Lib_LibC, "fopen = {}", mnt->GetHostFile(filename).c_str()); LOG_INFO(Lib_LibC, "fopen = {}", host_path);
} else { } else {
LOG_INFO(Lib_LibC, "fopen can't open = {}", mnt->GetHostFile(filename).c_str()); LOG_INFO(Lib_LibC, "fopen can't open = {}", host_path);
} }
return f; return f;
} }

View File

@ -15,7 +15,8 @@
#include "error_codes.h" #include "error_codes.h"
namespace Libraries::SaveData { namespace Libraries::SaveData {
static std::string g_mount_point = "/savedata0"; // temp mount point (todo)
static constexpr std::string_view g_mount_point = "/savedata0"; // temp mount point (todo)
std::string game_serial; std::string game_serial;
int PS4_SYSV_ABI sceSaveDataAbort() { int PS4_SYSV_ABI sceSaveDataAbort() {
@ -50,11 +51,11 @@ int PS4_SYSV_ABI sceSaveDataChangeInternal() {
int PS4_SYSV_ABI sceSaveDataCheckBackupData(const OrbisSaveDataCheckBackupData* check) { int PS4_SYSV_ABI sceSaveDataCheckBackupData(const OrbisSaveDataCheckBackupData* check) {
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
std::string mount_dir = mnt->GetHostFile(check->dirName->data); const auto mount_dir = mnt->GetHostPath(check->dirName->data);
if (!std::filesystem::exists(mount_dir)) { if (!std::filesystem::exists(mount_dir)) {
return ORBIS_SAVE_DATA_ERROR_NOT_FOUND; return ORBIS_SAVE_DATA_ERROR_NOT_FOUND;
} }
LOG_INFO(Lib_SaveData, "called = {}", mount_dir); LOG_INFO(Lib_SaveData, "called = {}", mount_dir.string());
return ORBIS_OK; return ORBIS_OK;
} }
@ -317,14 +318,14 @@ int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getParam
return false; return false;
} }
file.Seek(getParam->data->offset); file.Seek(getParam->data->offset);
size_t nbytes = file.ReadRaw<u8>(getParam->data->buf, getParam->data->bufSize); file.ReadRaw<u8>(getParam->data->buf, getParam->data->bufSize);
LOG_INFO(Lib_SaveData, "called: bufSize = {}, offset = {}", getParam->data->bufSize, LOG_INFO(Lib_SaveData, "called: bufSize = {}, offset = {}", getParam->data->bufSize,
getParam->data->offset); getParam->data->offset);
} }
if (getParam->param != nullptr) { if (getParam->param != nullptr) {
Common::FS::IOFile file1(mount_dir / "param.txt", Common::FS::FileAccessMode::Read); Common::FS::IOFile file(mount_dir / "param.txt", Common::FS::FileAccessMode::Read);
size_t nbytes = file1.ReadRaw<u8>(getParam->param, sizeof(OrbisSaveDataParam)); file.ReadRaw<u8>(getParam->param, sizeof(OrbisSaveDataParam));
} }
return ORBIS_OK; return ORBIS_OK;
@ -394,13 +395,13 @@ int PS4_SYSV_ABI sceSaveDataIsMounted() {
int PS4_SYSV_ABI sceSaveDataLoadIcon(const OrbisSaveDataMountPoint* mountPoint, int PS4_SYSV_ABI sceSaveDataLoadIcon(const OrbisSaveDataMountPoint* mountPoint,
OrbisSaveDataIcon* icon) { OrbisSaveDataIcon* icon) {
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
std::string mount_dir = mnt->GetHostFile(mountPoint->data); const auto mount_dir = mnt->GetHostPath(mountPoint->data);
LOG_INFO(Lib_SaveData, "called: dir = {}", mount_dir); LOG_INFO(Lib_SaveData, "called: dir = {}", mount_dir.string());
if (icon != nullptr) { if (icon != nullptr) {
Common::FS::IOFile file(mount_dir + "/save_data.png", Common::FS::FileAccessMode::Read); Common::FS::IOFile file(mount_dir / "save_data.png", Common::FS::FileAccessMode::Read);
icon->bufSize = file.GetSize(); icon->bufSize = file.GetSize();
size_t nbytes = file.ReadRaw<u8>(icon->buf, icon->bufSize); file.ReadRaw<u8>(icon->buf, icon->bufSize);
} }
return ORBIS_OK; return ORBIS_OK;
} }
@ -409,6 +410,7 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode,
OrbisSaveDataMountResult* mount_result) { OrbisSaveDataMountResult* mount_result) {
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) /
std::to_string(user_id) / game_serial / dir_name; std::to_string(user_id) / game_serial / dir_name;
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
switch (mount_mode) { switch (mount_mode) {
case ORBIS_SAVE_DATA_MOUNT_MODE_RDONLY: case ORBIS_SAVE_DATA_MOUNT_MODE_RDONLY:
case ORBIS_SAVE_DATA_MOUNT_MODE_RDWR: case ORBIS_SAVE_DATA_MOUNT_MODE_RDWR:
@ -417,9 +419,8 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode,
if (!std::filesystem::exists(mount_dir)) { if (!std::filesystem::exists(mount_dir)) {
return ORBIS_SAVE_DATA_ERROR_NOT_FOUND; return ORBIS_SAVE_DATA_ERROR_NOT_FOUND;
} }
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
mount_result->mount_status = 0; mount_result->mount_status = 0;
std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); g_mount_point.copy(mount_result->mount_point.data, 16);
mnt->Mount(mount_dir, mount_result->mount_point.data); mnt->Mount(mount_dir, mount_result->mount_point.data);
} break; } break;
case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE: case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE:
@ -431,16 +432,15 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode,
ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON: ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON:
case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE | ORBIS_SAVE_DATA_MOUNT_MODE_DESTRUCT_OFF | case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE | ORBIS_SAVE_DATA_MOUNT_MODE_DESTRUCT_OFF |
ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON: { ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON: {
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
if (std::filesystem::exists(mount_dir)) { if (std::filesystem::exists(mount_dir)) {
std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); g_mount_point.copy(mount_result->mount_point.data, 16);
mnt->Mount(mount_dir, mount_result->mount_point.data); mnt->Mount(mount_dir, mount_result->mount_point.data);
mount_result->required_blocks = 0; mount_result->required_blocks = 0;
mount_result->mount_status = 0; mount_result->mount_status = 0;
return ORBIS_SAVE_DATA_ERROR_EXISTS; return ORBIS_SAVE_DATA_ERROR_EXISTS;
} }
if (std::filesystem::create_directories(mount_dir)) { if (std::filesystem::create_directories(mount_dir)) {
std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); g_mount_point.copy(mount_result->mount_point.data, 16);
mnt->Mount(mount_dir, mount_result->mount_point.data); mnt->Mount(mount_dir, mount_result->mount_point.data);
mount_result->mount_status = 1; mount_result->mount_status = 1;
} }
@ -451,8 +451,7 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode,
if (!std::filesystem::exists(mount_dir)) { if (!std::filesystem::exists(mount_dir)) {
std::filesystem::create_directories(mount_dir); std::filesystem::create_directories(mount_dir);
} }
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); g_mount_point.copy(mount_result->mount_point.data, 16);
std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16);
mnt->Mount(mount_dir, mount_result->mount_point.data); mnt->Mount(mount_dir, mount_result->mount_point.data);
mount_result->mount_status = 1; mount_result->mount_status = 1;
} break; } break;
@ -534,12 +533,12 @@ int PS4_SYSV_ABI sceSaveDataRestoreLoadSaveDataMemory() {
int PS4_SYSV_ABI sceSaveDataSaveIcon(const OrbisSaveDataMountPoint* mountPoint, int PS4_SYSV_ABI sceSaveDataSaveIcon(const OrbisSaveDataMountPoint* mountPoint,
const OrbisSaveDataIcon* icon) { const OrbisSaveDataIcon* icon) {
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
std::string mount_dir = mnt->GetHostFile(mountPoint->data); const auto mount_dir = mnt->GetHostPath(mountPoint->data);
LOG_INFO(Lib_SaveData, "called = {}", mount_dir); LOG_INFO(Lib_SaveData, "called = {}", mount_dir.string());
if (icon != nullptr) { if (icon != nullptr) {
Common::FS::IOFile file(mount_dir + "/save_data.png", Common::FS::FileAccessMode::Write); Common::FS::IOFile file(mount_dir / "save_data.png", Common::FS::FileAccessMode::Write);
file.WriteRaw<u8>((void*)icon->buf, icon->bufSize); file.WriteRaw<u8>(icon->buf, icon->bufSize);
} }
return ORBIS_OK; return ORBIS_OK;
} }
@ -558,12 +557,13 @@ int PS4_SYSV_ABI sceSaveDataSetParam(const OrbisSaveDataMountPoint* mountPoint,
OrbisSaveDataParamType paramType, const void* paramBuf, OrbisSaveDataParamType paramType, const void* paramBuf,
size_t paramBufSize) { size_t paramBufSize) {
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
std::string mount_dir = mnt->GetHostFile(mountPoint->data); const auto mount_dir = mnt->GetHostPath(mountPoint->data);
LOG_INFO(Lib_SaveData, "called = {}, mountPoint->data = {}", mount_dir, mountPoint->data); LOG_INFO(Lib_SaveData, "called = {}, mountPoint->data = {}", mount_dir.string(),
mountPoint->data);
if (paramBuf != nullptr) { if (paramBuf != nullptr) {
Common::FS::IOFile file(mount_dir + "/param.txt", Common::FS::FileAccessMode::Write); Common::FS::IOFile file(mount_dir / "param.txt", Common::FS::FileAccessMode::Write);
file.WriteRaw<u8>((void*)paramBuf, paramBufSize); file.WriteRaw<u8>(paramBuf, paramBufSize);
} }
return ORBIS_OK; return ORBIS_OK;
} }
@ -711,24 +711,23 @@ int PS4_SYSV_ABI sceSaveDataUmountSys() {
int PS4_SYSV_ABI sceSaveDataUmountWithBackup(const OrbisSaveDataMountPoint* mountPoint) { int PS4_SYSV_ABI sceSaveDataUmountWithBackup(const OrbisSaveDataMountPoint* mountPoint) {
LOG_ERROR(Lib_SaveData, "called = {}", std::string(mountPoint->data)); LOG_ERROR(Lib_SaveData, "called = {}", std::string(mountPoint->data));
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
std::string mount_dir = mnt->GetHostFile(mountPoint->data); const auto mount_dir = mnt->GetHostPath(mountPoint->data);
if (!std::filesystem::exists(mount_dir)) { if (!std::filesystem::exists(mount_dir)) {
return ORBIS_SAVE_DATA_ERROR_NOT_FOUND; return ORBIS_SAVE_DATA_ERROR_NOT_FOUND;
} else { }
std::filesystem::path mnt_dir(mount_dir);
std::filesystem::create_directories(mnt_dir.parent_path() / "backup");
for (const auto& entry : std::filesystem::recursive_directory_iterator(mnt_dir)) { std::filesystem::create_directories(mount_dir.parent_path() / "backup");
for (const auto& entry : std::filesystem::recursive_directory_iterator(mount_dir)) {
const auto& path = entry.path(); const auto& path = entry.path();
std::filesystem::path target_path = mnt_dir.parent_path() / "backup"; const auto target_path = mount_dir.parent_path() / "backup";
if (std::filesystem::is_regular_file(path)) { if (std::filesystem::is_regular_file(path)) {
std::filesystem::copy(path, target_path, std::filesystem::copy(path, target_path,
std::filesystem::copy_options::overwrite_existing); std::filesystem::copy_options::overwrite_existing);
} }
} }
mnt->Unmount(mount_dir, mountPoint->data); mnt->Unmount(mount_dir, mountPoint->data);
}
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -9,7 +9,8 @@
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#else #else
#include <pthread.h> #include <asm/prctl.h> /* Definition of ARCH_* constants */
#include <sys/syscall.h> /* Definition of SYS_* constants */
#endif #endif
namespace Core { namespace Core {
@ -89,47 +90,28 @@ static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGe
#else #else
static pthread_key_t slot = 0; static u32 slot = 0;
void SetTcbBase(void* image_address) { void SetTcbBase(void* image_address) {
ASSERT(pthread_setspecific(slot, image_address) == 0); asm volatile("wrgsbase %0" ::"r"(image_address) : "memory");
} }
Tcb* GetTcbBase() { Tcb* GetTcbBase() {
return reinterpret_cast<Tcb*>(pthread_getspecific(slot)); Tcb* tcb;
asm volatile("rdgsbase %0" : "=r"(tcb)::"memory");
return tcb;
} }
static void AllocTcbKey() { static void AllocTcbKey() {}
ASSERT(pthread_key_create(&slot, nullptr) == 0);
}
static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGenerator& c) { static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGenerator& c) {
using namespace Xbyak::util; using namespace Xbyak::util;
const auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size; const auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size;
// Replace mov instruction with near jump to the trampoline. // Replace fs read with gs read.
static constexpr u32 NearJmpSize = 5;
auto patch = Xbyak::CodeGenerator(total_size, code); auto patch = Xbyak::CodeGenerator(total_size, code);
patch.jmp(c.getCurr(), Xbyak::CodeGenerator::LabelType::T_NEAR);
patch.nop(total_size - NearJmpSize);
// Write the trampoline.
// The following logic is based on the glibc implementation of pthread_getspecific
// https://github.com/bminor/glibc/blob/29807a27/nptl/pthread_getspecific.c#L23
static constexpr u32 PthreadKeySecondLevelSize = 32;
static constexpr u32 PthreadSpecificOffset = 0x510;
static constexpr u32 PthreadKeyDataSize = 16;
ASSERT(slot >= PthreadKeySecondLevelSize);
const u32 idx1st = slot / PthreadKeySecondLevelSize;
const u32 idx2nd = slot % PthreadKeySecondLevelSize;
const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg); const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg);
c.mov(target_reg, PthreadSpecificOffset); patch.putSeg(gs);
c.putSeg(fs);
c.mov(target_reg, qword[target_reg + idx1st * 8]); // Load first level specific array.
c.mov(target_reg, qword[target_reg + idx2nd * 16 +
8]); // Load data member of pthread_key_data our slot specifies.
c.jmp(code + total_size); // Return to the instruction right after the mov.
} }
#endif #endif

View File

@ -7,7 +7,7 @@
namespace Shader::Gcn { namespace Shader::Gcn {
void Translator::EXP(const GcnInst& inst) { void Translator::EXP(const GcnInst& inst) {
if (ir.block->has_multiple_predecessors) { if (ir.block->has_multiple_predecessors && info.stage == Stage::Fragment) {
LOG_WARNING(Render_Recompiler, "An ambiguous export appeared in translation"); LOG_WARNING(Render_Recompiler, "An ambiguous export appeared in translation");
ir.Discard(ir.LogicalNot(ir.GetExec())); ir.Discard(ir.LogicalNot(ir.GetExec()));
} }

View File

@ -173,7 +173,7 @@ public:
} }
template <typename Type> template <typename Type>
IR::Value ReadVariable(Type variable, IR::Block* root_block) { IR::Value ReadVariable(Type variable, IR::Block* root_block, bool is_thread_bit = false) {
boost::container::small_vector<ReadState<Type>, 64> stack{ boost::container::small_vector<ReadState<Type>, 64> stack{
ReadState<Type>(nullptr), ReadState<Type>(nullptr),
ReadState<Type>(root_block), ReadState<Type>(root_block),
@ -201,7 +201,7 @@ public:
} else if (!block->IsSsaSealed()) { } else if (!block->IsSsaSealed()) {
// Incomplete CFG // Incomplete CFG
IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)}; IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)};
phi->SetFlags(IR::TypeOf(UndefOpcode(variable))); phi->SetFlags(is_thread_bit ? IR::Type::U1 : IR::TypeOf(UndefOpcode(variable)));
incomplete_phis[block].insert_or_assign(variable, phi); incomplete_phis[block].insert_or_assign(variable, phi);
stack.back().result = IR::Value{&*phi}; stack.back().result = IR::Value{&*phi};
@ -214,7 +214,7 @@ public:
} else { } else {
// Break potential cycles with operandless phi // Break potential cycles with operandless phi
IR::Inst* const phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)}; IR::Inst* const phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)};
phi->SetFlags(IR::TypeOf(UndefOpcode(variable))); phi->SetFlags(is_thread_bit ? IR::Type::U1 : IR::TypeOf(UndefOpcode(variable)));
WriteVariable(variable, block, IR::Value{phi}); WriteVariable(variable, block, IR::Value{phi});
@ -263,7 +263,9 @@ private:
template <typename Type> template <typename Type>
IR::Value AddPhiOperands(Type variable, IR::Inst& phi, IR::Block* block) { IR::Value AddPhiOperands(Type variable, IR::Inst& phi, IR::Block* block) {
for (IR::Block* const imm_pred : block->ImmPredecessors()) { for (IR::Block* const imm_pred : block->ImmPredecessors()) {
phi.AddPhiOperand(imm_pred, ReadVariable(variable, imm_pred)); const bool is_thread_bit =
std::is_same_v<Type, IR::ScalarReg> && phi.Flags<IR::Type>() == IR::Type::U1;
phi.AddPhiOperand(imm_pred, ReadVariable(variable, imm_pred, is_thread_bit));
} }
return TryRemoveTrivialPhi(phi, block, UndefOpcode(variable)); return TryRemoveTrivialPhi(phi, block, UndefOpcode(variable));
} }
@ -346,7 +348,8 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
case IR::Opcode::GetThreadBitScalarReg: case IR::Opcode::GetThreadBitScalarReg:
case IR::Opcode::GetScalarRegister: { case IR::Opcode::GetScalarRegister: {
const IR::ScalarReg reg{inst.Arg(0).ScalarReg()}; const IR::ScalarReg reg{inst.Arg(0).ScalarReg()};
inst.ReplaceUsesWith(pass.ReadVariable(reg, block)); inst.ReplaceUsesWith(
pass.ReadVariable(reg, block, opcode == IR::Opcode::GetThreadBitScalarReg));
break; break;
} }
case IR::Opcode::GetVectorRegister: { case IR::Opcode::GetVectorRegister: {

View File

@ -1033,7 +1033,7 @@ private:
Vulkan::Rasterizer* rasterizer{}; Vulkan::Rasterizer* rasterizer{};
std::jthread process_thread{}; std::jthread process_thread{};
u32 num_submits{}; std::atomic<u32> num_submits{};
std::mutex submit_mutex; std::mutex submit_mutex;
std::condition_variable_any submit_cv; std::condition_variable_any submit_cv;
}; };