From 4b9030bd3d2447d05f2cb9205249db01f569a22c Mon Sep 17 00:00:00 2001 From: nmzik Date: Mon, 27 Jul 2026 23:44:12 +0200 Subject: [PATCH] ABI fixes: libNet, libSaveData (rewrite the legacy Kyty implementation) --- src/libs/libNet.cpp | 3 ++ src/libs/libSaveData.cpp | 87 ++++++++++++++++++++++------------- src/libs/libSystemService.cpp | 2 + src/libs/saveDataMountSlots.h | 67 +++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 32 deletions(-) create mode 100644 src/libs/saveDataMountSlots.h diff --git a/src/libs/libNet.cpp b/src/libs/libNet.cpp index 4861e123b..3d857a98b 100644 --- a/src/libs/libNet.cpp +++ b/src/libs/libNet.cpp @@ -35,6 +35,7 @@ namespace LibNet { LIB_VERSION("Net", 1, "Net", 1, 1); static thread_local int g_net_errno = 0; +static constexpr uint32_t g_in6addr_any[4] {}; namespace Net = Network::Net; @@ -180,6 +181,8 @@ uint16_t KYTY_SYSV_ABI NetNtohs(uint16_t net16) { } LIB_DEFINE(InitNet_1_Net) { + LIB_OBJECT("ZRAJo-A-ukc", &LibNet::g_in6addr_any); + LIB_FUNC("Nlev7Lg8k3A", LibNet::NetInit); LIB_FUNC("HQOwnfMGipQ", LibNet::GetNetErrorAddr); LIB_FUNC("PIWqhn9oSxc", LibNet::NetAccept); diff --git a/src/libs/libSaveData.cpp b/src/libs/libSaveData.cpp index a52502d55..cab5049eb 100644 --- a/src/libs/libSaveData.cpp +++ b/src/libs/libSaveData.cpp @@ -4,9 +4,11 @@ #include "common/file.h" #include "common/logging/log.h" #include "common/stringUtils.h" +#include "common/threads.h" #include "kernel/fileSystem.h" #include "libs/errno.h" #include "libs/libs.h" +#include "libs/saveDataMountSlots.h" #include "loader/symbolDatabase.h" #include "loader/systemContent.h" @@ -23,7 +25,6 @@ namespace SaveData { // TODO(): specify dir at launcher static constexpr char SAVE_DATA_DIR[] = "_SaveData"; -static constexpr char SAVE_DATA_POINT[] = "/savedata0"; static constexpr uint64_t SAVE_DATA_BLOCKS_MAX = 16384; struct SceSaveDataDirName { @@ -234,6 +235,8 @@ static constexpr uint32_t SAVE_DATA_EVENT_TYPE_COMMIT_BACKUP_END = 4u; static std::vector g_save_data_memory(0x10000); static int32_t g_next_transaction_resource = 1; static std::deque g_save_data_events; +static SaveDataMountSlots g_mount_slots; +static Common::Mutex g_mount_mutex; static std::string get_title_id() { std::string title_id; @@ -291,6 +294,18 @@ static bool dir_name_match(const char* str, const char* pattern) { return *str == '\0' && *pattern == '\0'; } +static int mount_save_data(int slot, std::string_view dir_name, const std::string& directory, + uint32_t status, SaveDataMountResult* result) { + const std::string mount_point = SaveDataMountSlots::MountPoint(static_cast(slot)); + LibKernel::FileSystem::Mount(directory, mount_point); + g_mount_slots.Mount(static_cast(slot), dir_name); + std::snprintf(result->mount_point.data, sizeof(result->mount_point.data), "%s", + mount_point.c_str()); + result->required_blocks = 0; + result->mount_status = status; + return OK; +} + int KYTY_SYSV_ABI SaveDataInitialize3(const void* /*init*/) { PRINT_NAME(); @@ -302,6 +317,10 @@ int KYTY_SYSV_ABI SaveDataInitialize3(const void* /*init*/) { int KYTY_SYSV_ABI SaveDataTerminate() { PRINT_NAME(); + Common::LockGuard lock(g_mount_mutex); + if (!g_mount_slots.Empty()) { + return SAVE_DATA_ERROR_BUSY; + } g_save_data_events.clear(); return OK; @@ -418,12 +437,20 @@ int KYTY_SYSV_ABI SaveDataMount3(const SaveDataMount3* mount, SaveDataMountResul *mount_result = {}; - std::string mount_dir = std::string(SAVE_DATA_DIR) + "/" + get_title_id() + "/" + - std::string(mount->dir_name->data); - std::string mount_point = SAVE_DATA_POINT; - bool create = ((mount->mount_mode & 4u) != 0); - bool create2 = ((mount->mount_mode & 32u) != 0); - bool open = (!create && !create2 && ((mount->mount_mode & 3u) != 0)); + Common::LockGuard lock(g_mount_mutex); + const std::string dir_name = mount->dir_name->data; + const std::string mount_dir = std::string(SAVE_DATA_DIR) + "/" + get_title_id() + "/" + dir_name; + const bool create = ((mount->mount_mode & 4u) != 0); + const bool create2 = ((mount->mount_mode & 32u) != 0); + const bool open = (!create && !create2 && ((mount->mount_mode & 3u) != 0)); + + const int slot = g_mount_slots.FindAvailable(dir_name); + if (slot == SaveDataMountSlots::BUSY) { + return SAVE_DATA_ERROR_BUSY; + } + if (slot == SaveDataMountSlots::FULL) { + return SAVE_DATA_ERROR_MOUNT_FULL; + } if (!create && !create2 && !open) { EXIT("unknown mount mode: %u", mount->mount_mode); @@ -445,16 +472,7 @@ int KYTY_SYSV_ABI SaveDataMount3(const SaveDataMount3* mount, SaveDataMountResul EXIT_NOT_IMPLEMENTED((!Common::File::IsDirectoryExisting(mount_dir))); } - LibKernel::FileSystem::Mount(mount_dir, mount_point); - - int s = snprintf(mount_result->mount_point.data, 16, "%s", mount_point.c_str()); - - EXIT_NOT_IMPLEMENTED(s >= 16); - - mount_result->required_blocks = 0; - mount_result->mount_status = (created ? 1 : 0); - - return OK; + return mount_save_data(slot, dir_name, mount_dir, created ? 1u : 0u, mount_result); } int KYTY_SYSV_ABI SaveDataSetupSaveDataMemory2(const SaveDataMemorySetup2* setup_param, @@ -575,24 +593,22 @@ int KYTY_SYSV_ABI SaveDataTransferringMount(const SaveDataTransferringMount* mou *mount_result = {}; - std::string mount_dir = std::string(SAVE_DATA_DIR) + "/" + get_title_id() + "/" + - std::string(mount->dir_name->data); - std::string mount_point = SAVE_DATA_POINT; + Common::LockGuard lock(g_mount_mutex); + const std::string dir_name = mount->dir_name->data; + const std::string mount_dir = std::string(SAVE_DATA_DIR) + "/" + get_title_id() + "/" + dir_name; + const int slot = g_mount_slots.FindAvailable(dir_name); + if (slot == SaveDataMountSlots::BUSY) { + return SAVE_DATA_ERROR_BUSY; + } + if (slot == SaveDataMountSlots::FULL) { + return SAVE_DATA_ERROR_MOUNT_FULL; + } if (!Common::File::IsDirectoryExisting(mount_dir)) { Common::File::CreateDirectories(mount_dir); } - LibKernel::FileSystem::Mount(mount_dir, mount_point); - - int s = snprintf(mount_result->mount_point.data, 16, "%s", mount_point.c_str()); - - EXIT_NOT_IMPLEMENTED(s >= 16); - - mount_result->required_blocks = 0; - mount_result->mount_status = 1; - - return OK; + return mount_save_data(slot, dir_name, mount_dir, 1, mount_result); } int KYTY_SYSV_ABI SaveDataUmount2(uint32_t mode, const SaveDataMountPoint* mount_point) { @@ -606,11 +622,18 @@ int KYTY_SYSV_ABI SaveDataUmount2(uint32_t mode, const SaveDataMountPoint* mount "\t mount_point = %s\n", mode, mount_point->data); + Common::LockGuard lock(g_mount_mutex); + const std::string point = mount_point->data; + const int slot = g_mount_slots.Find(point); + if (slot == SaveDataMountSlots::FULL) { + return SAVE_DATA_ERROR_NOT_FOUND; + } + if ((mode & SAVE_DATA_UMOUNT_MODE_BACKUP_ASYNC) != 0) { queue_save_data_event(SAVE_DATA_EVENT_TYPE_UMOUNT_BACKUP_END, 0, nullptr, nullptr); } - - LibKernel::FileSystem::Umount(std::string(mount_point->data)); + LibKernel::FileSystem::Umount(point); + g_mount_slots.Release(static_cast(slot)); return OK; } diff --git a/src/libs/libSystemService.cpp b/src/libs/libSystemService.cpp index 3f1537907..7dbd05e7f 100644 --- a/src/libs/libSystemService.cpp +++ b/src/libs/libSystemService.cpp @@ -22,6 +22,7 @@ namespace SystemService { [[maybe_unused]] constexpr int PARAM_ID_SUMMERTIME = 5; [[maybe_unused]] constexpr int PARAM_ID_SYSTEM_NAME = 6; [[maybe_unused]] constexpr int PARAM_ID_GAME_PARENTAL_LEVEL = 7; +[[maybe_unused]] constexpr int PARAM_ID_SCREEN_READER = 208; [[maybe_unused]] constexpr int PARAM_ID_ENTER_BUTTON_ASSIGN = 1000; [[maybe_unused]] constexpr int PARAM_LANG_JAPANESE = 0; @@ -126,6 +127,7 @@ static int KYTY_SYSV_ABI SystemServiceParamGetInt(int param_id, int* value) { case PARAM_ID_TIME_ZONE: v = +180; break; case PARAM_ID_SUMMERTIME: v = 0; break; case PARAM_ID_GAME_PARENTAL_LEVEL: v = PARAM_GAME_PARENTAL_OFF; break; + case PARAM_ID_SCREEN_READER: v = 0; break; case PARAM_ID_ENTER_BUTTON_ASSIGN: v = PARAM_ENTER_BUTTON_ASSIGN_CROSS; break; default: EXIT("unknown param_id: %d\n", param_id); } diff --git a/src/libs/saveDataMountSlots.h b/src/libs/saveDataMountSlots.h new file mode 100644 index 000000000..8be28caec --- /dev/null +++ b/src/libs/saveDataMountSlots.h @@ -0,0 +1,67 @@ +#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_SAVEDATAMOUNTSLOTS_H_ +#define EMULATOR_INCLUDE_EMULATOR_LIBS_SAVEDATAMOUNTSLOTS_H_ + +#include +#include +#include +#include + +namespace Libs::SaveData { + +class SaveDataMountSlots { +public: + static constexpr int BUSY = -2; + static constexpr int FULL = -1; + static constexpr size_t COUNT = 16; + + [[nodiscard]] int FindAvailable(std::string_view directory) const { + int available = FULL; + for (size_t index = 0; index < m_directories.size(); index++) { + const auto& mounted = m_directories[index]; + if (mounted == directory) { + return BUSY; + } + if (!mounted.has_value() && available == FULL) { + available = static_cast(index); + } + } + return available; + } + + void Mount(size_t slot, std::string_view directory) { m_directories[slot] = directory; } + + void Release(size_t slot) { + if (slot < m_directories.size()) { + m_directories[slot].reset(); + } + } + + [[nodiscard]] int Find(std::string_view mount_point) const { + for (size_t index = 0; index < m_directories.size(); index++) { + if (m_directories[index].has_value() && MountPoint(index) == mount_point) { + return static_cast(index); + } + } + return FULL; + } + + [[nodiscard]] static std::string MountPoint(size_t slot) { + return "/savedata" + std::to_string(slot); + } + + [[nodiscard]] bool Empty() const { + for (const auto& directory: m_directories) { + if (directory.has_value()) { + return false; + } + } + return true; + } + +private: + std::array, COUNT> m_directories; +}; + +} // namespace Libs::SaveData + +#endif /* EMULATOR_INCLUDE_EMULATOR_LIBS_SAVEDATAMOUNTSLOTS_H_ */