From a59cf50f037e895fffbd854f7c759f2cd4891983 Mon Sep 17 00:00:00 2001 From: DHrpcs3 Date: Sat, 29 Nov 2014 15:16:53 +0200 Subject: [PATCH] Improved LLE Manager Improved VFS --- Utilities/StrFmt.cpp | 31 ++++ Utilities/StrFmt.h | 2 + rpcs3/Emu/FS/VFS.cpp | 228 +++++++++++++++++++++-------- rpcs3/Emu/FS/VFS.h | 7 + rpcs3/Emu/FS/vfsDir.cpp | 79 +++++++--- rpcs3/Emu/FS/vfsDir.h | 4 +- rpcs3/Emu/FS/vfsDirBase.cpp | 8 +- rpcs3/Emu/FS/vfsDirBase.h | 53 +++++++ rpcs3/Emu/FS/vfsLocalDir.cpp | 5 + rpcs3/Emu/FS/vfsLocalDir.h | 1 + rpcs3/Emu/Memory/vm.h | 33 +++++ rpcs3/Emu/SysCalls/ModuleManager.h | 17 --- rpcs3/Emu/SysCalls/Modules.cpp | 35 +++-- rpcs3/Emu/SysCalls/Modules.h | 31 +++- rpcs3/Emu/SysCalls/lv2/lv2Fs.cpp | 4 +- rpcs3/Emu/System.cpp | 2 +- rpcs3/Emu/System.h | 11 ++ rpcs3/Gui/LLEModulesManager.cpp | 47 ++++-- rpcs3/Gui/LLEModulesManager.h | 3 +- rpcs3/Loader/ELF64.cpp | 114 ++++++++++----- rpcs3/Loader/ELF64.h | 12 +- rpcs3/rpcs3.cpp | 7 +- 22 files changed, 559 insertions(+), 175 deletions(-) diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 9f1709c0bf..b9e3955888 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -102,4 +102,35 @@ std::vector fmt::rSplit(const std::string& source, const std::strin } } while (true); return ret; +} + +std::vector fmt::split(const std::string& source, std::initializer_list separators, bool is_skip_empty) +{ + std::vector result; + + size_t cursor_begin = 0; + + for (size_t cursor_end = 0; cursor_end < source.length(); ++cursor_end) + { + for (auto &separator : separators) + { + if (strncmp(source.c_str() + cursor_end, separator.c_str(), separator.length()) == 0) + { + std::string candidate = source.substr(cursor_begin, cursor_end - cursor_begin); + if (!is_skip_empty || !candidate.empty()) + result.push_back(candidate); + + cursor_begin = cursor_end + separator.length(); + cursor_end = cursor_begin - 1; + break; + } + } + } + + if (cursor_begin != source.length()) + { + result.push_back(source.substr(cursor_begin)); + } + + return std::move(result); } \ No newline at end of file diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index 1914cb26e0..20a5fdcfc2 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -192,4 +192,6 @@ namespace fmt{ void Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm); std::vector rSplit(const std::string& source, const std::string& delim); + + std::vector split(const std::string& source, std::initializer_list separators, bool is_skip_empty = true); } diff --git a/rpcs3/Emu/FS/VFS.cpp b/rpcs3/Emu/FS/VFS.cpp index 7007955899..884290142a 100644 --- a/rpcs3/Emu/FS/VFS.cpp +++ b/rpcs3/Emu/FS/VFS.cpp @@ -4,33 +4,91 @@ #include "Emu/HDD/HDD.h" #include "vfsDeviceLocalFile.h" #include "Ini.h" +#include "Emu/System.h" -#undef CreateFile // TODO: what's wrong with it? +#undef CreateFile int sort_devices(const void* _a, const void* _b) { const vfsDevice& a = **(const vfsDevice**)_a; const vfsDevice& b = **(const vfsDevice**)_b; - if(a.GetPs3Path().length() > b.GetPs3Path().length()) return 1; - if(a.GetPs3Path().length() < b.GetPs3Path().length()) return -1; + if (a.GetPs3Path().length() > b.GetPs3Path().length()) return 1; + if (a.GetPs3Path().length() < b.GetPs3Path().length()) return -1; return 0; } +std::vector simplify_path_blocks(const std::string& path) +{ + std::vector path_blocks = std::move(fmt::split(path, { "/", "\\" })); + + for (size_t i = 0; i < path_blocks.size(); ++i) + { + if (path_blocks[i] == ".") + { + path_blocks.erase(path_blocks.begin() + i--); + } + else if (i && path_blocks[i] == "..") + { + path_blocks.erase(path_blocks.begin() + (i - 1), path_blocks.begin() + (i + 1)); + i--; + } + } + + return path_blocks; +} + +std::string simplify_path(const std::string& path, bool is_dir) +{ + std::vector path_blocks = simplify_path_blocks(path); + + std::string result; + + if (path_blocks.empty()) + return result; + + if (is_dir) + { + for (auto &dir : path_blocks) + { + result += dir + "/"; + } + } + else + { + for (size_t i = 0; i < path_blocks.size() - 1; ++i) + { + result += path_blocks[i] + "/"; + } + + result += path_blocks[path_blocks.size() - 1]; + } + + return result; +} + VFS::~VFS() { UnMountAll(); } +std::string VFS::FindEntry(const std::string &path) +{ + return path; + return cwd + "/" + path; +} + void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device) { - UnMount(ps3_path); + std::string simpl_ps3_path = simplify_path(ps3_path, true); - device->SetPath(ps3_path, local_path); + UnMount(simpl_ps3_path); + + device->SetPath(simpl_ps3_path, simplify_path(local_path, true)); m_devices.push_back(device); - if(m_devices.size() > 1) + if (m_devices.size() > 1) { //std::qsort(m_devices.GetPtr(), m_devices.GetCount(), sizeof(vfsDevice*), sort_devices); } @@ -38,11 +96,14 @@ void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsD void VFS::UnMount(const std::string& ps3_path) { - for(u32 i=0; iGetPs3Path().compare(ps3_path)) + if (!stricmp(m_devices[i]->GetPs3Path().c_str(), simpl_ps3_path.c_str())) { delete m_devices[i]; + m_devices.erase(m_devices.begin() +i); return; @@ -63,9 +124,9 @@ void VFS::UnMountAll() vfsFileBase* VFS::OpenFile(const std::string& ps3_path, vfsOpenMode mode) const { std::string path; - if(vfsDevice* dev = GetDevice(ps3_path, path)) + if (vfsDevice* dev = GetDevice(ps3_path, path)) { - if(vfsFileBase* res = dev->GetNewFileStream()) + if (vfsFileBase* res = dev->GetNewFileStream()) { res->Open(path, mode); return res; @@ -79,9 +140,9 @@ vfsDirBase* VFS::OpenDir(const std::string& ps3_path) const { std::string path; - if(vfsDevice* dev = GetDevice(ps3_path, path)) + if (vfsDevice* dev = GetDevice(ps3_path, path)) { - if(vfsDirBase* res = dev->GetNewDirStream()) + if (vfsDirBase* res = dev->GetNewDirStream()) { res->Open(path); return res; @@ -94,11 +155,11 @@ vfsDirBase* VFS::OpenDir(const std::string& ps3_path) const bool VFS::CreateFile(const std::string& ps3_path) const { std::string path; - if(vfsDevice* dev = GetDevice(ps3_path, path)) + if (vfsDevice* dev = GetDevice(ps3_path, path)) { std::shared_ptr res(dev->GetNewFileStream()); - if(res) + if (res) { return res->Create(path); } @@ -110,11 +171,11 @@ bool VFS::CreateFile(const std::string& ps3_path) const bool VFS::CreateDir(const std::string& ps3_path) const { std::string path; - if(vfsDevice* dev = GetDevice(ps3_path, path)) + if (vfsDevice* dev = GetDevice(ps3_path, path)) { std::shared_ptr res(dev->GetNewDirStream()); - if(res) + if (res) { return res->Create(path); } @@ -126,11 +187,11 @@ bool VFS::CreateDir(const std::string& ps3_path) const bool VFS::RemoveFile(const std::string& ps3_path) const { std::string path; - if(vfsDevice* dev = GetDevice(ps3_path, path)) + if (vfsDevice* dev = GetDevice(ps3_path, path)) { std::shared_ptr res(dev->GetNewFileStream()); - if(res) + if (res) { return res->Remove(path); } @@ -142,11 +203,11 @@ bool VFS::RemoveFile(const std::string& ps3_path) const bool VFS::RemoveDir(const std::string& ps3_path) const { std::string path; - if(vfsDevice* dev = GetDevice(ps3_path, path)) + if (vfsDevice* dev = GetDevice(ps3_path, path)) { std::shared_ptr res(dev->GetNewDirStream()); - if(res) + if (res) { return res->Remove(path); } @@ -158,11 +219,11 @@ bool VFS::RemoveDir(const std::string& ps3_path) const bool VFS::ExistsFile(const std::string& ps3_path) const { std::string path; - if(vfsDevice* dev = GetDevice(ps3_path, path)) + if (vfsDevice* dev = GetDevice(ps3_path, path)) { std::shared_ptr res(dev->GetNewFileStream()); - if(res) + if (res) { return res->Exists(path); } @@ -174,11 +235,11 @@ bool VFS::ExistsFile(const std::string& ps3_path) const bool VFS::ExistsDir(const std::string& ps3_path) const { std::string path; - if(vfsDevice* dev = GetDevice(ps3_path, path)) + if (vfsDevice* dev = GetDevice(ps3_path, path)) { std::shared_ptr res(dev->GetNewDirStream()); - if(res) + if (res) { return res->IsExists(path); } @@ -190,11 +251,11 @@ bool VFS::ExistsDir(const std::string& ps3_path) const bool VFS::RenameFile(const std::string& ps3_path_from, const std::string& ps3_path_to) const { std::string path; - if(vfsDevice* dev = GetDevice(ps3_path_from, path)) + if (vfsDevice* dev = GetDevice(ps3_path_from, path)) { std::shared_ptr res(dev->GetNewFileStream()); - if(res) + if (res) { return res->Rename(path, ps3_path_to); } @@ -206,11 +267,11 @@ bool VFS::RenameFile(const std::string& ps3_path_from, const std::string& ps3_pa bool VFS::RenameDir(const std::string& ps3_path_from, const std::string& ps3_path_to) const { std::string path; - if(vfsDevice* dev = GetDevice(ps3_path_from, path)) + if (vfsDevice* dev = GetDevice(ps3_path_from, path)) { std::shared_ptr res(dev->GetNewDirStream()); - if(res) + if (res) { return res->Rename(path, ps3_path_to); } @@ -221,53 +282,107 @@ bool VFS::RenameDir(const std::string& ps3_path_from, const std::string& ps3_pat vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const { - u32 max_eq; - s32 max_i=-1; - - for(u32 i=0; i& ps3_path_blocks) -> vfsDevice* { - const u32 eq = m_devices[i]->CmpPs3Path(ps3_path); + size_t max_eq = 0; + int max_i = -1; - if(max_i < 0 || eq > max_eq) + for (u32 i = 0; i < m_devices.size(); ++i) { - max_eq = eq; - max_i = i; - } - } + std::vector dev_ps3_path_blocks = simplify_path_blocks(m_devices[i]->GetPs3Path()); - if(max_i < 0) return nullptr; - path = vfsDevice::GetWinPath(m_devices[max_i]->GetLocalPath(), ps3_path.substr(max_eq, ps3_path.length() - max_eq)); - return m_devices[max_i]; + if (ps3_path_blocks.size() < dev_ps3_path_blocks.size()) + continue; + + size_t eq = 0; + for (; eq < dev_ps3_path_blocks.size(); ++eq) + { + if (stricmp(ps3_path_blocks[eq].c_str(), dev_ps3_path_blocks[eq].c_str())) + { + break; + } + } + + if (eq > max_eq) + { + max_eq = eq; + max_i = i; + } + } + + if (max_i < 0) + return nullptr; + + path = m_devices[max_i]->GetLocalPath(); + + for (u32 i = max_eq; i < ps3_path_blocks.size(); i++) + { + path += "/" + ps3_path_blocks[i]; + } + + path = simplify_path(path, false); + + return m_devices[max_i]; + }; + + if (auto res = try_get_device(simplify_path_blocks(ps3_path))) + return res; + + if (auto res = try_get_device(simplify_path_blocks(cwd + ps3_path))) + return res; + + return nullptr; } vfsDevice* VFS::GetDeviceLocal(const std::string& local_path, std::string& path) const { - u32 max_eq; - s32 max_i=-1; + size_t max_eq = 0; + int max_i = -1; - rFileName file_path(local_path); - file_path.Normalize(); - std::string mormalized_path = file_path.GetFullPath(); + std::vector local_path_blocks = simplify_path_blocks(local_path); - for(u32 i=0; iCmpLocalPath(mormalized_path); + std::vector dev_local_path_blocks_blocks = simplify_path_blocks(m_devices[i]->GetLocalPath()); - if(max_i < 0 || eq > max_eq) + if (local_path_blocks.size() < dev_local_path_blocks_blocks.size()) + continue; + + size_t eq = 0; + for (; eq < dev_local_path_blocks_blocks.size(); ++eq) + { + if (stricmp(local_path_blocks[eq].c_str(), dev_local_path_blocks_blocks[eq].c_str())) + { + break; + } + } + + if (eq > max_eq) { max_eq = eq; max_i = i; } } - if(max_i < 0) return nullptr; + if (max_i < 0) + return nullptr; + + path = m_devices[max_i]->GetPs3Path(); + + for (u32 i = max_eq; i < local_path_blocks.size(); i++) + { + path += "/" + local_path_blocks[i]; + } + + path = simplify_path(path, false); - path = vfsDevice::GetPs3Path(m_devices[max_i]->GetPs3Path(), local_path.substr(max_eq, local_path.length() - max_eq)); return m_devices[max_i]; } void VFS::Init(const std::string& path) { + cwd = simplify_path(path, true); + UnMountAll(); std::vector entries; @@ -293,8 +408,8 @@ void VFS::Init(const std::string& path) std::string mpath = entry.path; // TODO: This shouldn't use current dir - fmt::Replace(mpath,"$(EmulatorDir)", "."); - fmt::Replace(mpath,"$(GameDir)", vfsDevice::GetRoot(path)); + fmt::Replace(mpath, "$(EmulatorDir)", Emu.GetEmulatorPath()); + fmt::Replace(mpath, "$(GameDir)", cwd); Mount(entry.mount, mpath, dev); } } @@ -305,11 +420,11 @@ void VFS::SaveLoadDevices(std::vector& res, bool is_load) entries_count.Init("count", "VFSManager"); int count = 0; - if(is_load) + if (is_load) { count = entries_count.LoadValue(count); - if(!count) + if (!count) { res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd0/", "/dev_hdd0/"); res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd1/", "/dev_hdd1/"); @@ -319,7 +434,6 @@ void VFS::SaveLoadDevices(std::vector& res, bool is_load) res.emplace_back(vfsDevice_LocalFile, "$(GameDir)", "/app_home/"); res.emplace_back(vfsDevice_LocalFile, "$(GameDir)/../", "/dev_bdvd/"); res.emplace_back(vfsDevice_LocalFile, "", "/host_root/"); - res.emplace_back(vfsDevice_LocalFile, "$(GameDir)", "/"); return; } @@ -344,7 +458,7 @@ void VFS::SaveLoadDevices(std::vector& res, bool is_load) entry_mount.Init(fmt::Format("mount[%d]", i), "VFSManager"); entry_device.Init(fmt::Format("device[%d]", i), "VFSManager"); - if(is_load) + if (is_load) { res[i] = VFSManagerEntry(); res[i].path = entry_path.LoadValue(""); diff --git a/rpcs3/Emu/FS/VFS.h b/rpcs3/Emu/FS/VFS.h index 8876072b3f..acaccf17ec 100644 --- a/rpcs3/Emu/FS/VFS.h +++ b/rpcs3/Emu/FS/VFS.h @@ -42,10 +42,17 @@ struct VFSManagerEntry } }; +std::vector simplify_path_blocks(const std::string& path); +std::string simplify_path(const std::string& path, bool is_dir); + struct VFS { ~VFS(); + std::string cwd; + + std::string FindEntry(const std::string &path); + //TODO: find out where these are supposed to be deleted or just make it shared_ptr //and also make GetDevice and GetDeviceLocal return shared_ptr then. // A vfsDevice will be deleted when they're unmounted or the VFS struct is destroyed. diff --git a/rpcs3/Emu/FS/vfsDir.cpp b/rpcs3/Emu/FS/vfsDir.cpp index 94ed07096a..13025e51e7 100644 --- a/rpcs3/Emu/FS/vfsDir.cpp +++ b/rpcs3/Emu/FS/vfsDir.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "Emu/System.h" +#include "vfsDevice.h" #include "VFS.h" #include "vfsDir.h" @@ -10,7 +11,7 @@ vfsDir::vfsDir() { // TODO: proper implementation // m_stream is nullptr here. So open root until a proper dir is given - Open("/"); + //Open("/"); } vfsDir::vfsDir(const std::string& path) @@ -26,37 +27,78 @@ bool vfsDir::Open(const std::string& path) m_stream.reset(Emu.GetVFS().OpenDir(path)); - return m_stream && m_stream->IsOpened(); + DirEntryInfo info; + + m_cwd = simplify_path(0 && m_stream && m_stream->IsOpened() ? m_stream->GetPath() : path, true); + + auto blocks = simplify_path_blocks(GetPath()); + + for (auto dev : Emu.GetVFS().m_devices) + { + auto dev_blocks = simplify_path_blocks(dev->GetPs3Path()); + + if (dev_blocks.size() < (blocks.size() + 1)) + { + continue; + } + + bool is_ok = true; + + for (size_t i = 0; i < blocks.size(); ++i) + { + if (stricmp(dev_blocks[i].c_str(), blocks[i].c_str())) + { + is_ok = false; + break; + } + } + + if (is_ok) + { + info.name = dev_blocks[blocks.size()]; + m_entries.push_back(info); + } + } + + if (m_stream && m_stream->IsOpened()) + { + m_entries.insert(m_entries.begin(), m_stream->GetEntries().begin(), m_stream->GetEntries().end()); + } + + return !m_entries.empty(); } bool vfsDir::Create(const std::string& path) { - return m_stream->Create(path); + return Emu.GetVFS().CreateDir(path); } bool vfsDir::IsExists(const std::string& path) const { - return m_stream->IsExists(path); -} + auto path_blocks = simplify_path_blocks(path); -const std::vector& vfsDir::GetEntries() const -{ - return m_stream->GetEntries(); + if (path_blocks.empty()) + return false; + + std::string dir_name = path_blocks[path_blocks.size() - 1]; + + for (const auto entry : vfsDir(path + "/..")) + { + if (!stricmp(entry->name.c_str(), dir_name.c_str())) + return true; + } + + return false; } bool vfsDir::Rename(const std::string& from, const std::string& to) { - return m_stream->Rename(from, to); + return Emu.GetVFS().RenameDir(from, to); } bool vfsDir::Remove(const std::string& path) { - return m_stream->Remove(path); -} - -const DirEntryInfo* vfsDir::Read() -{ - return m_stream->Read(); + return Emu.GetVFS().RemoveDir(path); } void vfsDir::Close() @@ -64,12 +106,7 @@ void vfsDir::Close() m_stream.reset(); } -std::string vfsDir::GetPath() const -{ - return m_stream->GetPath(); -} - bool vfsDir::IsOpened() const { - return m_stream && m_stream->IsOpened(); + return !m_entries.empty(); } diff --git a/rpcs3/Emu/FS/vfsDir.h b/rpcs3/Emu/FS/vfsDir.h index 09c8ee197d..5dd2b8897e 100644 --- a/rpcs3/Emu/FS/vfsDir.h +++ b/rpcs3/Emu/FS/vfsDir.h @@ -13,13 +13,11 @@ public: virtual bool Open(const std::string& path) override; virtual bool IsOpened() const override; virtual bool IsExists(const std::string& path) const override; - virtual const std::vector& GetEntries() const override; virtual void Close() override; - virtual std::string GetPath() const override; + //virtual std::string GetPath() const override; virtual bool Create(const std::string& path) override; //virtual bool Create(const DirEntryInfo& info) override; virtual bool Rename(const std::string& from, const std::string& to) override; virtual bool Remove(const std::string& path) override; - virtual const DirEntryInfo* Read() override; }; diff --git a/rpcs3/Emu/FS/vfsDirBase.cpp b/rpcs3/Emu/FS/vfsDirBase.cpp index e5bda0eded..2d54b48e42 100644 --- a/rpcs3/Emu/FS/vfsDirBase.cpp +++ b/rpcs3/Emu/FS/vfsDirBase.cpp @@ -32,7 +32,7 @@ bool vfsDirBase::IsOpened() const bool vfsDirBase::IsExists(const std::string& path) const { - return rExists(path); + return false; } const std::vector& vfsDirBase::GetEntries() const @@ -58,3 +58,9 @@ const DirEntryInfo* vfsDirBase::Read() return &m_entries[m_pos++]; } + +const DirEntryInfo* vfsDirBase::First() +{ + m_pos = 0; + return Read(); +} \ No newline at end of file diff --git a/rpcs3/Emu/FS/vfsDirBase.h b/rpcs3/Emu/FS/vfsDirBase.h index 7251862976..0d05dcbaf5 100644 --- a/rpcs3/Emu/FS/vfsDirBase.h +++ b/rpcs3/Emu/FS/vfsDirBase.h @@ -53,4 +53,57 @@ public: virtual bool Rename(const std::string& from, const std::string& to) = 0; virtual bool Remove(const std::string& path) = 0; virtual const DirEntryInfo* Read(); + virtual const DirEntryInfo* First(); + + class iterator + { + vfsDirBase *parent; + const DirEntryInfo* data; + + public: + iterator(vfsDirBase* parent) + : parent(parent) + , data(parent->First()) + { + } + + iterator(const DirEntryInfo* data) + : parent(parent) + , data(data) + { + } + + iterator& operator++() + { + data = parent->Read(); + return *this; + } + + iterator operator++(int) + { + const DirEntryInfo* olddata = data; + data = parent->Read(); + return iterator(olddata); + } + + const DirEntryInfo* operator *() + { + return data; + } + + bool operator!=(iterator other) const + { + return data != other.data; + } + }; + + iterator begin() + { + return iterator(this); + } + + iterator end() + { + return iterator((const DirEntryInfo*)nullptr); + } }; diff --git a/rpcs3/Emu/FS/vfsLocalDir.cpp b/rpcs3/Emu/FS/vfsLocalDir.cpp index 0c44144ab9..8a07be19ef 100644 --- a/rpcs3/Emu/FS/vfsLocalDir.cpp +++ b/rpcs3/Emu/FS/vfsLocalDir.cpp @@ -46,6 +46,11 @@ bool vfsLocalDir::Create(const std::string& path) return rMkpath(path); } +bool vfsLocalDir::IsExists(const std::string& path) const +{ + return rIsDir(path); +} + bool vfsLocalDir::Rename(const std::string& from, const std::string& to) { return false; diff --git a/rpcs3/Emu/FS/vfsLocalDir.h b/rpcs3/Emu/FS/vfsLocalDir.h index f4b41509d2..c2174f3658 100644 --- a/rpcs3/Emu/FS/vfsLocalDir.h +++ b/rpcs3/Emu/FS/vfsLocalDir.h @@ -18,4 +18,5 @@ public: virtual bool Rename(const std::string& from, const std::string& to) override; virtual bool Remove(const std::string& path) override; virtual bool IsOpened() const override; + virtual bool IsExists(const std::string& path) const; }; \ No newline at end of file diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 0d5859a8ee..87d173bbb5 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -219,4 +219,37 @@ namespace vm assert(location < memory_location_count); return g_locations[location]; } + + class stack + { + u32 m_begin; + u32 m_size; + int m_page_size; + int m_position; + u8 m_align; + + public: + void init(u32 begin, u32 size, u32 page_size = 180, u8 align = 0x10) + { + m_begin = begin; + m_size = size; + m_page_size = page_size; + m_position = 0; + m_align = align; + } + + u32 alloc_new_page() + { + assert(m_position + m_page_size < (int)m_size); + m_position += (int)m_page_size; + return m_begin + m_position; + } + + u32 dealloc_new_page() + { + assert(m_position - m_page_size > 0); + m_position -= (int)m_page_size; + return m_begin + m_position; + } + }; } diff --git a/rpcs3/Emu/SysCalls/ModuleManager.h b/rpcs3/Emu/SysCalls/ModuleManager.h index 5d40cd35ad..524887112d 100644 --- a/rpcs3/Emu/SysCalls/ModuleManager.h +++ b/rpcs3/Emu/SysCalls/ModuleManager.h @@ -10,7 +10,6 @@ class ModuleManager std::vector m_modules_funcs_list; std::vector m_mod_init; //owner of Module bool initialized; - std::unordered_map m_registered_functions; public: ModuleManager(); @@ -26,20 +25,4 @@ public: u32 GetFuncNumById(u32 id); Module* GetModuleByName(const std::string& name); Module* GetModuleById(u16 id); - - void register_function(u32 fnid, u32 fstub) - { - m_registered_functions[fnid] = fstub; - } - - bool get_function_stub(u32 fnid, be_t& res) - { - auto f = m_registered_functions.find(fnid); - - if (f == m_registered_functions.end()) - return false; - - res = f->second; - return true; - } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index e74349e7ae..c1a17c4b2f 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -62,10 +62,12 @@ Module::~Module() { UnLoad(); - for (int i = 0; i < m_funcs_list.size(); i++) + for (auto &i : m_funcs_list) { - delete m_funcs_list[i]; + delete i.second; } + + m_funcs_list.clear(); } void Module::Load() @@ -75,12 +77,10 @@ void Module::Load() if(m_load_func) m_load_func(); - for(u32 i=0; ille_func.set(0); + } + // TODO: Re-enable this when needed // This was disabled because some functions would get unloaded and // some games tried to use them, thus only printing a TODO message @@ -106,16 +111,14 @@ bool Module::Load(u32 id) if(Emu.GetModuleManager().IsLoadedFunc(id)) return false; - for(u32 i=0; iid == id) - { - Emu.GetModuleManager().AddFunc(m_funcs_list[i]); - return true; - } - } + auto res = m_funcs_list.find(id); - return false; + if (res == m_funcs_list.end()) + return false; + + Emu.GetModuleManager().AddFunc(res->second); + + return true; } bool Module::UnLoad(u32 id) @@ -177,7 +180,7 @@ void fix_import(Module* module, u32 func, u32 addr) { using namespace PPU_instr; - vm::ptr& ptr = (vm::ptr&)addr; + vm::ptr& ptr = vm::ptr::make(addr); *ptr++ = ADDIS(11, 0, func >> 16); *ptr++ = ORI(11, 11, func & 0xffff); diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h index 1e7afebc22..0ee2ddd9f4 100644 --- a/rpcs3/Emu/SysCalls/Modules.h +++ b/rpcs3/Emu/SysCalls/Modules.h @@ -9,10 +9,12 @@ struct ModuleFunc { u32 id; func_caller* func; + vm::ptr lle_func; - ModuleFunc(u32 id, func_caller* func) + ModuleFunc(u32 id, func_caller* func, vm::ptr lle_func = vm::ptr::make(0)) : id(id) , func(func) + , lle_func(lle_func) { } @@ -57,7 +59,7 @@ class Module : public LogBase void PushNewFuncSub(SFunc* func); public: - std::vector m_funcs_list; + std::unordered_map m_funcs_list; Module(u16 id, const char* name, void(*load)() = nullptr, void(*unload)() = nullptr); @@ -66,6 +68,16 @@ public: Module &operator =(Module &other) = delete; Module &operator =(Module &&other); + + ModuleFunc* GetFunc(u32 id) + { + auto res = m_funcs_list.find(id); + + if (res == m_funcs_list.end()) + return nullptr; + + return res->second; + } ~Module(); @@ -114,9 +126,20 @@ public: } bool RemoveId(u32 id); + + void RegisterLLEFunc(u32 id, vm::ptr func) + { + if (auto f = GetFunc(id)) + { + f->lle_func = func; + return; + } + + m_funcs_list[id] = new ModuleFunc(id, nullptr, func); + } template __forceinline void AddFunc(u32 id, T func); - template __forceinline void AddFunc(const char* name, T func); + template __forceinline void AddFunc(const char* name, T func); template __forceinline void AddFuncSub(const char group[8], const u64 ops[], const char* name, T func); }; @@ -125,7 +148,7 @@ u32 getFunctionId(const char* name); template __forceinline void Module::AddFunc(u32 id, T func) { - m_funcs_list.emplace_back(new ModuleFunc(id, bind_func(func))); + m_funcs_list[id] = new ModuleFunc(id, bind_func(func)); } template diff --git a/rpcs3/Emu/SysCalls/lv2/lv2Fs.cpp b/rpcs3/Emu/SysCalls/lv2/lv2Fs.cpp index 9c5feb2a0c..d0d9400761 100644 --- a/rpcs3/Emu/SysCalls/lv2/lv2Fs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/lv2Fs.cpp @@ -305,7 +305,7 @@ s32 cellFsMkdir(vm::ptr path, u32 mode) const std::string _path = path.get_ptr(); - if(Emu.GetVFS().ExistsDir(_path)) + if(vfsDir().IsExists(_path)) return CELL_EEXIST; if(!Emu.GetVFS().CreateDir(_path)) return CELL_EBUSY; @@ -395,7 +395,7 @@ s32 cellFsUnlink(vm::ptr path) std::string _path = path.get_ptr(); - if (Emu.GetVFS().ExistsDir(_path)) + if (vfsDir().IsExists(_path)) return CELL_EISDIR; if (!Emu.GetVFS().ExistsFile(_path)) diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 7c6919724f..b2cfa2b6ea 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -192,7 +192,7 @@ void Emulator::Load() LOG_NOTICE(LOADER, "Loading '%s'...", m_path.c_str()); GetInfo().Reset(); - GetVFS().Init(m_path); + GetVFS().Init(rFileName(m_path).GetPath()); LOG_NOTICE(LOADER, " "); //used to be skip_line LOG_NOTICE(LOADER, "Mount info:"); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 63469f3467..8c9a711532 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -112,6 +112,7 @@ class Emulator public: std::string m_path; std::string m_elf_path; + std::string m_emu_path; std::string m_title_id; u32 m_ppu_thr_stop; s32 m_sdk_version; @@ -128,6 +129,16 @@ public: return m_elf_path; } + std::string GetEmulatorPath() const + { + return m_emu_path; + } + + void SetEmulatorPath(const std::string& path) + { + m_emu_path = path; + } + std::recursive_mutex& GetCoreMutex() { return m_core_mutex; } CPUThreadManager& GetCPU() { return *m_thread_manager; } diff --git a/rpcs3/Gui/LLEModulesManager.cpp b/rpcs3/Gui/LLEModulesManager.cpp index 387e0e6433..f6ccd60b0b 100644 --- a/rpcs3/Gui/LLEModulesManager.cpp +++ b/rpcs3/Gui/LLEModulesManager.cpp @@ -13,19 +13,20 @@ LLEModulesManagerFrame::LLEModulesManagerFrame(wxWindow* parent) : FrameBase(par wxBoxSizer *s_p_panel = new wxBoxSizer(wxVERTICAL); wxPanel *p_main = new wxPanel(this); m_check_list = new wxCheckListBox(p_main, wxID_ANY); - s_p_panel->Add(m_check_list, 0, wxEXPAND | wxALL, 5); + s_p_panel->Add(m_check_list, 1, wxEXPAND | wxALL, 5); p_main->SetSizerAndFit(s_p_panel); - s_panel->Add(p_main, 0, wxEXPAND | wxALL, 5); + s_panel->Add(p_main, 1, wxEXPAND | wxALL, 5); SetSizerAndFit(s_panel); Refresh(); - //Bind(wxEVT_CHECKLISTBOX, [this](wxCommandEvent& event) { UpdateSelection(); }); - Bind(wxEVT_SIZE, [p_main, this](wxSizeEvent& event) { p_main->SetSize(GetClientSize()); m_check_list->SetSize(p_main->GetClientSize() - wxSize(10, 10)); }); + Bind(wxEVT_CHECKLISTBOX, [this](wxCommandEvent& event) { UpdateSelection(event.GetInt()); event.Skip(); }); + Bind(wxEVT_SIZE, [p_main, this](wxSizeEvent& event) { p_main->SetSize(GetClientSize()); m_check_list->SetSize(p_main->GetClientSize() - wxSize(10, 10)); event.Skip(); }); } void LLEModulesManagerFrame::Refresh() { m_check_list->Clear(); + m_funcs.clear(); std::string path = "/dev_flash/sys/external/"; @@ -34,7 +35,7 @@ void LLEModulesManagerFrame::Refresh() vfsDir dir(path); loader::handlers::elf64 sprx_loader; - for (const DirEntryInfo* info = dir.Read(); info; info = dir.Read()) + for (const auto info : dir) { if (info->flags & DirEntry_TypeFile) { @@ -49,17 +50,45 @@ void LLEModulesManagerFrame::Refresh() continue; } - sprx_loader.load(); + //loader::handlers::elf64::sprx_info info; + //sprx_loader.load_sprx(info); - m_check_list->Check(m_check_list->Append(sprx_loader.sprx_get_module_name() + - " v" + std::to_string((int)sprx_loader.m_sprx_module_info.version[0]) + "." + std::to_string((int)sprx_loader.m_sprx_module_info.version[1]))); + std::string name = sprx_loader.sprx_get_module_name(); + + bool is_skip = false; + for (auto &i : m_funcs) + { + if (i == name) + { + is_skip = true; + break; + } + } + + if (is_skip) + continue; + + m_funcs.push_back(name); + + IniEntry load_lib; + load_lib.Init(name, "LLE"); + + m_check_list->Check(m_check_list->Append(name + + " v" + std::to_string((int)sprx_loader.m_sprx_module_info.version[0]) + + "." + std::to_string((int)sprx_loader.m_sprx_module_info.version[1])), + load_lib.LoadValue(false)); } } Emu.GetVFS().UnMountAll(); } -void LLEModulesManagerFrame::UpdateSelection() +void LLEModulesManagerFrame::UpdateSelection(int index) { + if (index < 0) + return; + IniEntry load_lib; + load_lib.Init(m_funcs[index], "LLE"); + load_lib.SaveValue(m_check_list->IsChecked(index)); } \ No newline at end of file diff --git a/rpcs3/Gui/LLEModulesManager.h b/rpcs3/Gui/LLEModulesManager.h index f6344bba3b..f73fa02910 100644 --- a/rpcs3/Gui/LLEModulesManager.h +++ b/rpcs3/Gui/LLEModulesManager.h @@ -5,9 +5,10 @@ class LLEModulesManagerFrame : public FrameBase { wxCheckListBox *m_check_list; + std::vector m_funcs; public: LLEModulesManagerFrame(wxWindow *parent); void Refresh(); - void UpdateSelection(); + void UpdateSelection(int index); }; \ No newline at end of file diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index 01036e8bf5..7784f593f1 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -3,6 +3,7 @@ #include "Utilities/rFile.h" #include "Emu/FS/vfsStream.h" #include "Emu/FS/vfsFile.h" +#include "Emu/FS/vfsDir.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" @@ -12,6 +13,7 @@ #include "Emu/Cell/PPUInstrTable.h" #include "Emu/CPU/CPUThreadManager.h" #include "ELF64.h" +#include "Ini.h" using namespace PPU_instr; @@ -43,8 +45,6 @@ namespace loader return broken_file; } - LOG_WARNING(LOADER, "m_ehdr.e_type = 0x%x", m_ehdr.e_type.ToLE()); - if (m_ehdr.e_machine != MACHINE_PPC64 && m_ehdr.e_machine != MACHINE_SPU) { LOG_ERROR(LOADER, "Unknown elf64 machine type: 0x%x", m_ehdr.e_machine.ToLE()); @@ -73,8 +73,6 @@ namespace loader if (is_sprx()) { - LOG_NOTICE(LOADER, "SPRX loading..."); - m_stream->Seek(handler::get_stream_offset() + m_phdrs[0].p_paddr.addr()); m_stream->Read(&m_sprx_module_info, sizeof(sprx_module_info)); @@ -94,7 +92,7 @@ namespace loader { for (auto &phdr : m_phdrs) { - switch (phdr.p_type.ToLE()) + switch ((u32)phdr.p_type) { case 0x1: //load if (phdr.p_memsz) @@ -127,6 +125,8 @@ namespace loader m_stream->Seek(handler::get_stream_offset() + phdr.p_paddr.addr()); m_stream->Read(&module_info, sizeof(module_info)); LOG_ERROR(LOADER, "%s (%x):", module_info.name, (u32)module_info.toc); + info.name = std::string((const char*)module_info.name, 28); + info.rtoc = module_info.toc; int import_count = (module_info.imports_end - module_info.imports_start) / sizeof(sys_prx_library_info_t); @@ -149,12 +149,12 @@ namespace loader { char name[27]; m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.name_addr); - modulename = std::string(name, m_stream->Read(name, sizeof(name))); + m_stream->Read(name, sizeof(name)); + modulename = std::string(name); LOG_ERROR(LOADER, "**** %s", name); } - //ModuleManager& manager = Emu.GetModuleManager(); - //Module* module = manager.GetModuleByName(modulename); + auto &module = info.modules[modulename]; LOG_ERROR(LOADER, "**** 0x%x - 0x%x - 0x%x", (u32)lib.unk4, (u32)lib.unk5, (u32)lib.unk6); @@ -167,7 +167,7 @@ namespace loader m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fstub_addr + i * sizeof(fstub)); m_stream->Read(&fstub, sizeof(fstub)); - info.exports[fnid] = fstub; + module.exports[fnid] = fstub; //LOG_NOTICE(LOADER, "Exported function '%s' in '%s' module (LLE)", SysCalls::GetHLEFuncName(fnid).c_str(), module_name.c_str()); LOG_ERROR(LOADER, "**** %s: [%s] -> 0x%x", modulename.c_str(), SysCalls::GetHLEFuncName(fnid).c_str(), (u32)fstub); @@ -201,17 +201,17 @@ namespace loader switch ((u32)rel.type) { case 1: - LOG_ERROR(LOADER, "**** RELOCATION(1): 0x%x <- 0x%x", ADDR, (u32)(info.segments[rel.index_value].begin.addr() + rel.ptr.addr())); + LOG_WARNING(LOADER, "**** RELOCATION(1): 0x%x <- 0x%x", ADDR, (u32)(info.segments[rel.index_value].begin.addr() + rel.ptr.addr())); *vm::ptr::make(ADDR) = info.segments[rel.index_value].begin.addr() + rel.ptr.addr(); break; case 4: - LOG_ERROR(LOADER, "**** RELOCATION(4): 0x%x <- 0x%x", ADDR, (u16)(rel.ptr.addr())); + LOG_WARNING(LOADER, "**** RELOCATION(4): 0x%x <- 0x%x", ADDR, (u16)(rel.ptr.addr())); *vm::ptr::make(ADDR) = (u16)(u64)rel.ptr.addr(); break; case 5: - LOG_ERROR(LOADER, "**** RELOCATION(5): 0x%x <- 0x%x", ADDR, (u16)(info.segments[rel.index_value].begin.addr() >> 16)); + LOG_WARNING(LOADER, "**** RELOCATION(5): 0x%x <- 0x%x", ADDR, (u16)(info.segments[rel.index_value].begin.addr() >> 16)); *vm::ptr::make(ADDR) = info.segments[rel.index_value].begin.addr() >> 16; break; @@ -230,20 +230,23 @@ namespace loader } } - for (auto &e : info.exports) + for (auto &m : info.modules) { - u32 stub = e.second; - - for (auto &s : info.segments) + for (auto &e : m.second.exports) { - if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file) - { - stub += s.begin.addr() - s.initial_addr.addr(); - break; - } - } + u32 stub = e.second; - e.second = stub; + for (auto &s : info.segments) + { + if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file) + { + stub += s.begin.addr() - s.initial_addr.addr(); + break; + } + } + + e.second = stub; + } } return ok; @@ -266,12 +269,12 @@ namespace loader std::vector stop_funcs; //load modules - static const char* lle_modules[] = { "lv2", "sre", "l10n", "gcm_sys", "fs" }; - //TODO: for (auto &module : lle_modules) - char* module; if (0) + vfsDir lle_dir("/dev_flash/sys/external"); + + for (const auto module : lle_dir) { elf64 sprx_handler; - vfsFile fsprx(std::string("/dev_flash/sys/external/lib") + module + ".sprx"); + vfsFile fsprx(lle_dir.GetPath() + "/" + module->name); if (fsprx.IsOpened()) { @@ -279,21 +282,52 @@ namespace loader if (sprx_handler.is_sprx()) { + IniEntry load_lib; + load_lib.Init(sprx_handler.sprx_get_module_name(), "LLE"); + + if (!load_lib.LoadValue(false)) + { + LOG_ERROR(LOADER, "skipped lle library '%s'", sprx_handler.sprx_get_module_name().c_str()); + continue; + } + else + { + LOG_WARNING(LOADER, "loading lle library '%s'", sprx_handler.sprx_get_module_name().c_str()); + } + sprx_info info; sprx_handler.load_sprx(info); - std::unordered_map::iterator f; - - if ((f = info.exports.find(0xbc9a0086)) != info.exports.end()) - start_funcs.push_back(f->second); - - if ((f = info.exports.find(0xab779874)) != info.exports.end()) - stop_funcs.push_back(f->second); - - for (auto &e : info.exports) + for (auto &m : info.modules) { - if (e.first != 0xbc9a0086 && e.first != 0xab779874) - Emu.GetModuleManager().register_function(e.first, e.second); + if (m.first == "") + { + for (auto &e : m.second.exports) + { + switch (e.first) + { + case 0xbc9a0086: start_funcs.push_back(e.second); break; + case 0xab779874: stop_funcs.push_back(e.second); break; + + default: LOG_ERROR(LOADER, "unknown special func 0x%08x in '%s' library", e.first, info.name.c_str()); break; + } + } + + continue; + } + + Module* module = Emu.GetModuleManager().GetModuleByName(m.first); + + if (!module) + { + LOG_ERROR(LOADER, "unknown module '%s' in '%s' library", m.first.c_str(), info.name.c_str()); + module = new Module(-1, m.first.c_str()); + } + + for (auto &e : m.second.exports) + { + module->RegisterLLEFunc(e.first, vm::ptr::make(e.second)); + } } } } @@ -469,8 +503,9 @@ namespace loader for (u32 i = 0; i < stub->s_imports; ++i) { const u32 nid = stub->s_nid[i]; + auto func = module->GetFunc(nid); - if (!Emu.GetModuleManager().get_function_stub(nid, stub->s_text[i])) + if (!func || !func->lle_func) { dst[i] = stub_data; @@ -490,6 +525,7 @@ namespace loader } else { + stub->s_text[i] = func->lle_func.addr(); //Is function auto exported, than we can use it LOG_NOTICE(LOADER, "Imported function '%s' in '%s' module (LLE: 0x%x)", SysCalls::GetHLEFuncName(nid).c_str(), module_name.c_str(), (u32)stub->s_text[i]); } diff --git a/rpcs3/Loader/ELF64.h b/rpcs3/Loader/ELF64.h index a5b2cde70b..b78cd643ed 100644 --- a/rpcs3/Loader/ELF64.h +++ b/rpcs3/Loader/ELF64.h @@ -131,8 +131,16 @@ namespace loader struct sprx_info { - std::unordered_map exports; - std::unordered_map imports; + std::string name; + u32 rtoc; + + struct module_info + { + std::unordered_map exports; + std::unordered_map imports; + }; + + std::unordered_map modules; std::vector segments; }; diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index 65867c0320..3f4f2ab104 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -40,6 +40,8 @@ wxDEFINE_EVENT(wxEVT_DBG_COMMAND, wxCommandEvent); IMPLEMENT_APP(Rpcs3App) Rpcs3App* TheApp; +std::string simplify_path(const std::string& path, bool is_dir); + bool Rpcs3App::OnInit() { SetSendDbgCommandCallback([](DbgCommand id, CPUThread* t) @@ -128,8 +130,8 @@ bool Rpcs3App::OnInit() wxInitAllImageHandlers(); // RPCS3 assumes the current working directory is the folder where it is contained, so we make sure this is true - const wxString executablePath = wxStandardPaths::Get().GetExecutablePath(); - wxSetWorkingDirectory(wxPathOnly(executablePath)); + const wxString executablePath = wxPathOnly(wxStandardPaths::Get().GetExecutablePath()); + wxSetWorkingDirectory(executablePath); main_thread = std::this_thread::get_id(); @@ -137,6 +139,7 @@ bool Rpcs3App::OnInit() m_MainFrame = new MainFrame(); SetTopWindow(m_MainFrame); Emu.Init(); + Emu.SetEmulatorPath(executablePath.ToStdString()); m_MainFrame->Show(); m_MainFrame->DoSettings(true);