From 73c2115968cc3d6836fad280a920e4f98b4e3e24 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 26 May 2016 18:06:06 +0300 Subject: [PATCH 1/6] BEType: explicit alignment specifier --- Utilities/BEType.h | 186 ++++++++++++++++++------------ Utilities/types.h | 6 + rpcs3/Emu/Cell/Modules/cellPamf.h | 26 ++--- rpcs3/Emu/Cell/lv2/sys_fs.h | 20 ++-- rpcs3/Emu/Memory/vm_ptr.h | 38 +++--- rpcs3/Emu/Memory/vm_var.h | 12 +- rpcs3/Loader/ELF.h | 14 ++- 7 files changed, 177 insertions(+), 125 deletions(-) diff --git a/Utilities/BEType.h b/Utilities/BEType.h index be6f012c70..4476106a3a 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -327,14 +327,44 @@ inline v128 operator ~(const v128& other) #define IS_INTEGER(t) (std::is_integral::value || std::is_enum::value) #define IS_BINARY_COMPARABLE(t1, t2) (IS_INTEGER(t1) && IS_INTEGER(t2) && sizeof(t1) == sizeof(t2)) -template +template struct se_storage { - static_assert(!Size, "Bad se_storage<> type"); + using type = std::aligned_storage_t; + + // Unoptimized generic byteswap for unaligned data + static void reverse(u8* dst, const u8* src) + { + for (std::size_t i = 0; i < Size; i++) + { + dst[i] = src[Size - 1 - i]; + } + } + + static type to(const T& src) + { + type result; + reverse(reinterpret_cast(&result), reinterpret_cast(&src)); + return result; + } + + static T from(const type& src) + { + T result; + reverse(reinterpret_cast(&result), reinterpret_cast(&src)); + return result; + } + + static type copy(const type& src) + { + type result; + std::memcpy(&result, &src, Size); + return result; + } }; template -struct se_storage +struct se_storage { using type = u16; @@ -357,10 +387,15 @@ struct se_storage const u16 result = swap(src); return reinterpret_cast(result); } + + static inline T copy(const T& src) + { + return src; + } }; template -struct se_storage +struct se_storage { using type = u32; @@ -383,10 +418,15 @@ struct se_storage const u32 result = swap(src); return reinterpret_cast(result); } + + static inline T copy(const T& src) + { + return src; + } }; template -struct se_storage +struct se_storage { using type = u64; @@ -409,10 +449,15 @@ struct se_storage const u64 result = swap(src); return reinterpret_cast(result); } + + static inline T copy(const T& src) + { + return src; + } }; template -struct se_storage +struct se_storage { using type = v128; @@ -431,43 +476,22 @@ struct se_storage const v128 result = swap(src); return reinterpret_cast(result); } -}; -template using se_storage_t = typename se_storage::type; - -template -struct se_convert -{ - using type_from = std::remove_cv_t; - using type_to = std::remove_cv_t; - using stype_from = se_storage_t>; - using stype_to = se_storage_t>; - using storage_from = se_storage>; - using storage_to = se_storage>; - - static inline std::enable_if_t::value, stype_to> convert(const stype_from& data) + static inline T copy(const T& src) { - return data; - } - - static inline stype_to convert(const stype_from& data, ...) - { - return storage_to::to(storage_from::from(data)); + return src; } }; static struct se_raw_tag_t {} constexpr se_raw{}; -template -class se_t; - // Switched endianness -template -class se_t +template +class se_t { using type = typename std::remove_cv::type; - using stype = se_storage_t; - using storage = se_storage; + using stype = typename se_storage::type; + using storage = se_storage; stype m_data; @@ -585,39 +609,41 @@ public: }; // Native endianness -template -class se_t +template +class se_t { using type = typename std::remove_cv::type; + using stype = typename se_storage::type; + using storage = se_storage; static_assert(!std::is_pointer::value, "se_t<> error: invalid type (pointer)"); static_assert(!std::is_reference::value, "se_t<> error: invalid type (reference)"); static_assert(!std::is_array::value, "se_t<> error: invalid type (array)"); static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment"); - type m_data; + stype m_data; public: se_t() = default; - constexpr se_t(type value) - : m_data(value) + se_t(type value) + : m_data(reinterpret_cast(value)) { } // Construct directly from raw data (don't use) - constexpr se_t(const type& raw_value, const se_raw_tag_t&) + constexpr se_t(const stype& raw_value, const se_raw_tag_t&) : m_data(raw_value) { } - constexpr type value() const + type value() const { - return m_data; + return storage::copy(reinterpret_cast(m_data)); } // Access underlying raw data (don't use) - constexpr const type& raw_data() const noexcept + constexpr const stype& raw_data() const noexcept { return m_data; } @@ -626,14 +652,14 @@ public: se_t& operator =(type value) { - return m_data = value, *this; + return m_data = reinterpret_cast(value), *this; } using simple_type = simple_t; - constexpr operator type() const + operator type() const { - return m_data; + return storage::copy(reinterpret_cast(m_data)); } template @@ -656,59 +682,59 @@ public: }; // se_t with native endianness (alias) -template using nse_t = se_t; +template using nse_t = se_t; -template -inline se_t& operator +=(se_t& left, const T1& right) +template +inline se_t& operator +=(se_t& left, const T1& right) { auto value = left.value(); return left = (value += right); } -template -inline se_t& operator -=(se_t& left, const T1& right) +template +inline se_t& operator -=(se_t& left, const T1& right) { auto value = left.value(); return left = (value -= right); } -template -inline se_t& operator *=(se_t& left, const T1& right) +template +inline se_t& operator *=(se_t& left, const T1& right) { auto value = left.value(); return left = (value *= right); } -template -inline se_t& operator /=(se_t& left, const T1& right) +template +inline se_t& operator /=(se_t& left, const T1& right) { auto value = left.value(); return left = (value /= right); } -template -inline se_t& operator %=(se_t& left, const T1& right) +template +inline se_t& operator %=(se_t& left, const T1& right) { auto value = left.value(); return left = (value %= right); } -template -inline se_t& operator <<=(se_t& left, const T1& right) +template +inline se_t& operator <<=(se_t& left, const T1& right) { auto value = left.value(); return left = (value <<= right); } -template -inline se_t& operator >>=(se_t& left, const T1& right) +template +inline se_t& operator >>=(se_t& left, const T1& right) { auto value = left.value(); return left = (value >>= right); } -template -inline se_t operator ++(se_t& left, int) +template +inline se_t operator ++(se_t& left, int) { auto value = left.value(); auto result = value++; @@ -716,8 +742,8 @@ inline se_t operator ++(se_t& left, int) return result; } -template -inline se_t operator --(se_t& left, int) +template +inline se_t operator --(se_t& left, int) { auto value = left.value(); auto result = value--; @@ -725,15 +751,15 @@ inline se_t operator --(se_t& left, int) return result; } -template -inline se_t& operator ++(se_t& right) +template +inline se_t& operator ++(se_t& right) { auto value = right.value(); return right = ++value; } -template -inline se_t& operator --(se_t& right) +template +inline se_t& operator --(se_t& right) { auto value = right.value(); return right = --value; @@ -852,16 +878,28 @@ inline std::enable_if_t::value && sizeof(T) >= 4, se_t using be_t = se_t; -template using le_t = se_t; +template using be_t = se_t; +template using le_t = se_t; #endif // Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type template struct to_se { + template + struct to_se_ + { + using type = T2; + }; + + template + struct to_se_::value || std::is_enum::value>> + { + using type = se_t; + }; + // Convert arithmetic and enum types - using type = typename std::conditional::value || std::is_enum::value, se_t, T>::type; + using type = typename to_se_::type; }; template struct to_se { using type = se_t; }; @@ -911,10 +949,10 @@ template using atomic_le_t = atomic_t>; #endif // Formatting for BE/LE data -template -struct unveil, void> +template +struct unveil, void> { - static inline auto get(const se_t& arg) + static inline auto get(const se_t& arg) { return unveil::get(arg); } diff --git a/Utilities/types.h b/Utilities/types.h index c822aba50a..ad61bce0e2 100644 --- a/Utilities/types.h +++ b/Utilities/types.h @@ -34,6 +34,12 @@ struct bijective_pair T2 v2; }; +template +struct se_storage; + +template +class se_t; + // Specialization with static constexpr bijective_pair map[] member expected template struct bijective; diff --git a/rpcs3/Emu/Cell/Modules/cellPamf.h b/rpcs3/Emu/Cell/Modules/cellPamf.h index 60d042e77e..8f80f5fd12 100644 --- a/rpcs3/Emu/Cell/Modules/cellPamf.h +++ b/rpcs3/Emu/Cell/Modules/cellPamf.h @@ -253,8 +253,6 @@ struct CellPamfLpcmInfo -#pragma pack(push, 1) // file data - struct PamfStreamHeader { u8 type; @@ -341,7 +339,7 @@ struct PamfStreamHeader }; }; -CHECK_SIZE(PamfStreamHeader, 48); +CHECK_SIZE_ALIGN(PamfStreamHeader, 48, 4); struct PamfHeader { @@ -349,25 +347,25 @@ struct PamfHeader u32 version; //"0041" (is it const?) be_t data_offset; //== 2048 >> 11, PAMF headers seem to be always 2048 bytes in size be_t data_size; //== ((fileSize - 2048) >> 11) - u64 reserved[8]; + u32 reserved[16]; be_t table_size; //== size of mapping-table u16 reserved1; be_t start_pts_high; - be_t start_pts_low; //Presentation Time Stamp (start) + be_t start_pts_low; //Presentation Time Stamp (start) be_t end_pts_high; - be_t end_pts_low; //Presentation Time Stamp (end) - be_t mux_rate_max; //== 0x01D470 (400 bps per unit, == 48000000 bps) - be_t mux_rate_min; //== 0x0107AC (?????) + be_t end_pts_low; //Presentation Time Stamp (end) + be_t mux_rate_max; //== 0x01D470 (400 bps per unit, == 48000000 bps) + be_t mux_rate_min; //== 0x0107AC (?????) u16 reserved2; // ????? u8 reserved3; u8 stream_count; //total stream count (reduced to 1 byte) be_t unk1; //== 1 (?????) - be_t table_data_size; //== table_size - 0x20 == 0x14 + (0x30 * total_stream_num) (?????) + be_t table_data_size; //== table_size - 0x20 == 0x14 + (0x30 * total_stream_num) (?????) //TODO: check relative offset of stream structs (could be from 0x0c to 0x14, currently 0x14) be_t start_pts_high2; //????? (probably same values) - be_t start_pts_low2; //????? + be_t start_pts_low2; //????? be_t end_pts_high2; //????? - be_t end_pts_low2; //????? + be_t end_pts_low2; //????? be_t unk2; //== 0x10000 (?????) be_t unk3; // ????? be_t unk4; // == stream_count @@ -375,6 +373,8 @@ struct PamfHeader PamfStreamHeader stream_headers[256]; }; +CHECK_SIZE_ALIGN(PamfHeader, 136 + sizeof(PamfHeader::stream_headers), 4); + struct PamfEpHeader { be_t value0; //mixed indexN (probably left 2 bits) and nThRefPictureOffset @@ -383,9 +383,7 @@ struct PamfEpHeader be_t rpnOffset; }; -CHECK_SIZE(PamfEpHeader, 12); - -#pragma pack(pop) +CHECK_SIZE_ALIGN(PamfEpHeader, 12, 4); // not directly accessed by virtual CPU, fields are unknown struct CellPamfReader diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index ad044f23a3..d1f56d59a3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -7,8 +7,6 @@ namespace vm { using namespace ps3; } -#pragma pack(push, 4) - // Error Codes enum : s32 { @@ -136,20 +134,22 @@ struct CellFsStat be_t mode; be_t uid; be_t gid; - be_t atime; - be_t mtime; - be_t ctime; - be_t size; - be_t blksize; + be_t atime; + be_t mtime; + be_t ctime; + be_t size; + be_t blksize; }; +CHECK_SIZE_ALIGN(CellFsStat, 52, 4); + struct CellFsUtimbuf { - be_t actime; - be_t modtime; + be_t actime; + be_t modtime; }; -#pragma pack(pop) +CHECK_SIZE_ALIGN(CellFsUtimbuf, 16, 4); // Stream Support Status (st_status) enum : u32 diff --git a/rpcs3/Emu/Memory/vm_ptr.h b/rpcs3/Emu/Memory/vm_ptr.h index c2e96b46b5..3667d7a015 100644 --- a/rpcs3/Emu/Memory/vm_ptr.h +++ b/rpcs3/Emu/Memory/vm_ptr.h @@ -130,6 +130,18 @@ namespace vm return aligned(ALIGN_32(T)); } + // Get type size + static constexpr u32 size() + { + return SIZE_32(T); + } + + // Get type alignment + static constexpr u32 align() + { + return ALIGN_32(T); + } + // Test address for arbitrary alignment: (addr & (align - 1)) != 0 explicit_bool_t operator %(u32 align) const { @@ -266,9 +278,11 @@ namespace vm // Native endianness pointer to LE data template using ptrl = _ptr_base, AT>; + template using cptrl = ptrl; // Native endianness pointer to BE data template using ptrb = _ptr_base, AT>; + template using cptrb = ptrb; // BE pointer to LE data template using bptrl = _ptr_base, to_be_t>; @@ -286,24 +300,19 @@ namespace vm { // Default pointer type for PS3 HLE functions (Native endianness pointer to BE data) template using ptr = ptrb; + template using cptr = ptr; // Default pointer to pointer type for PS3 HLE functions (Native endianness pointer to BE pointer to BE data) template using pptr = ptr, AT>; + template using cpptr = pptr; // Default pointer type for PS3 HLE structures (BE pointer to BE data) template using bptr = bptrb; + template using bcptr = bptr; // Default pointer to pointer type for PS3 HLE structures (BE pointer to BE pointer to BE data) template using bpptr = bptr, AT>; - - // Native endianness pointer to const BE data - template using cptr = ptr; - - // BE pointer to const BE data - template using bcptr = bptr; - - template using cpptr = pptr; - template using bcpptr = bpptr; + template using bcpptr = bpptr; // Perform static_cast (for example, vm::ptr to vm::ptr) template*>(std::declval()))> @@ -324,23 +333,18 @@ namespace vm { // Default pointer type for PSV HLE functions (Native endianness pointer to LE data) template using ptr = ptrl; + template using cptr = ptr; // Default pointer to pointer type for PSV HLE functions (Native endianness pointer to LE pointer to LE data) template using pptr = ptr>; + template using cpptr = pptr; // Default pointer type for PSV HLE structures (LE pointer to LE data) template using lptr = lptrl; + template using lcptr = lptr; // Default pointer to pointer type for PSV HLE structures (LE pointer to LE pointer to LE data) template using lpptr = lptr>; - - // Native endianness pointer to const LE data - template using cptr = ptr; - - // LE pointer to const LE data - template using lcptr = lptr; - - template using cpptr = pptr; template using lcpptr = lpptr; // Perform static_cast (for example, vm::ptr to vm::ptr) diff --git a/rpcs3/Emu/Memory/vm_var.h b/rpcs3/Emu/Memory/vm_var.h index 24fa149396..7467919ae1 100644 --- a/rpcs3/Emu/Memory/vm_var.h +++ b/rpcs3/Emu/Memory/vm_var.h @@ -109,10 +109,10 @@ namespace vm template using var = varb; // Make BE variable initialized from value - template inline auto make_var(const T& value) + template + inline auto make_var(const T& value) { - varb var(value); - return var; + return varb(value); } // Global HLE variable @@ -128,10 +128,10 @@ namespace vm template using var = varl; // Make LE variable initialized from value - template inline auto make_var(const T& value) + template + inline auto make_var(const T& value) { - varl var(value); - return var; + return varl(value); } // Global HLE variable diff --git a/rpcs3/Loader/ELF.h b/rpcs3/Loader/ELF.h index cbe308c138..e46d21afb9 100644 --- a/rpcs3/Loader/ELF.h +++ b/rpcs3/Loader/ELF.h @@ -32,6 +32,12 @@ enum class elf_machine : u16 mips = 0x08, }; +template +using elf_be = be_t; + +template +using elf_le = le_t; + template class en_t, typename sz_t> struct elf_ehdr { @@ -341,7 +347,7 @@ public: } }; -using ppu_exec_object = elf_object; -using ppu_prx_object = elf_object; -using spu_exec_object = elf_object; -using arm_exec_object = elf_object; +using ppu_exec_object = elf_object; +using ppu_prx_object = elf_object; +using spu_exec_object = elf_object; +using arm_exec_object = elf_object; From c95f6c8c560aac219babbb62b48fc9b402e76ac5 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 25 May 2016 13:31:29 +0300 Subject: [PATCH 2/6] Partial commit: sys_vm --- rpcs3/Emu/Cell/lv2/sys_vm.cpp | 95 ++++++++++++++++++----------------- rpcs3/Emu/Cell/lv2/sys_vm.h | 32 ++++++------ 2 files changed, 67 insertions(+), 60 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp index 8c5ec0613c..61a10ad935 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -1,43 +1,46 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/IdManager.h" - -#include "Emu/Cell/ErrorCodes.h" -#include "sys_memory.h" #include "sys_vm.h" +#include "sys_memory.h" + +namespace vm { using namespace ps3; } logs::channel sys_vm("sys_vm", logs::level::notice); -s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) +ppu_error_code sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) { sys_vm.error("sys_vm_memory_map(vsize=0x%x, psize=0x%x, cid=0x%x, flags=0x%llx, policy=0x%llx, addr=*0x%x)", vsize, psize, cid, flag, policy, addr); - LV2_LOCK; - - // Use fixed address (TODO: search and use some free address instead) - const u32 new_addr = vm::check_addr(0x60000000) ? 0x70000000 : 0x60000000; - - // Map memory - const auto area = vm::map(new_addr, vsize, flag); - - // Alloc memory - if (!area || !area->alloc(vsize)) + if (!vsize || !psize || vsize & 0x2000000 || vsize > 0x10000000 || psize > 0x10000000 || policy != SYS_VM_POLICY_AUTO_RECOMMENDED) { - return CELL_ENOMEM; + return CELL_EINVAL; } - // Write a pointer for the allocated memory. - *addr = new_addr; + if (cid != SYS_MEMORY_CONTAINER_ID_INVALID && !idm::check(cid)) + { + return CELL_ESRCH; + } - return CELL_OK; + // Look for unmapped space (roughly) + for (u32 found = 0x60000000; found <= 0xC0000000 - vsize; found += 0x2000000) + { + // Try to map + if (const auto area = vm::map(found, vsize, flag)) + { + // Alloc all memory (shall not fail) + VERIFY(area->alloc(vsize)); + + // Write a pointer for the allocated memory + *addr = found; + return CELL_OK; + } + } + + return CELL_ENOMEM; } -s32 sys_vm_unmap(u32 addr) +ppu_error_code sys_vm_unmap(u32 addr) { - sys_vm.error("sys_vm_unmap(addr=0x%x)", addr); - - LV2_LOCK; + sys_vm.warning("sys_vm_unmap(addr=0x%x)", addr); if (!vm::unmap(addr)) { @@ -47,81 +50,81 @@ s32 sys_vm_unmap(u32 addr) return CELL_OK; } -s32 sys_vm_append_memory(u32 addr, u32 size) +ppu_error_code sys_vm_append_memory(u32 addr, u32 size) { - sys_vm.todo("sys_vm_append_memory(addr=0x%x, size=0x%x)", addr, size); + sys_vm.warning("sys_vm_append_memory(addr=0x%x, size=0x%x)", addr, size); return CELL_OK; } -s32 sys_vm_return_memory(u32 addr, u32 size) +ppu_error_code sys_vm_return_memory(u32 addr, u32 size) { - sys_vm.todo("sys_vm_return_memory(addr=0x%x, size=0x%x)", addr, size); + sys_vm.warning("sys_vm_return_memory(addr=0x%x, size=0x%x)", addr, size); return CELL_OK; } -s32 sys_vm_lock(u32 addr, u32 size) +ppu_error_code sys_vm_lock(u32 addr, u32 size) { - sys_vm.todo("sys_vm_lock(addr=0x%x, size=0x%x)", addr, size); + sys_vm.warning("sys_vm_lock(addr=0x%x, size=0x%x)", addr, size); return CELL_OK; } -s32 sys_vm_unlock(u32 addr, u32 size) +ppu_error_code sys_vm_unlock(u32 addr, u32 size) { - sys_vm.todo("sys_vm_unlock(addr=0x%x, size=0x%x)", addr, size); + sys_vm.warning("sys_vm_unlock(addr=0x%x, size=0x%x)", addr, size); return CELL_OK; } -s32 sys_vm_touch(u32 addr, u32 size) +ppu_error_code sys_vm_touch(u32 addr, u32 size) { - sys_vm.todo("sys_vm_touch(addr=0x%x, size=0x%x)", addr, size); + sys_vm.warning("sys_vm_touch(addr=0x%x, size=0x%x)", addr, size); return CELL_OK; } -s32 sys_vm_flush(u32 addr, u32 size) +ppu_error_code sys_vm_flush(u32 addr, u32 size) { - sys_vm.todo("sys_vm_flush(addr=0x%x, size=0x%x)", addr, size); + sys_vm.warning("sys_vm_flush(addr=0x%x, size=0x%x)", addr, size); return CELL_OK; } -s32 sys_vm_invalidate(u32 addr, u32 size) +ppu_error_code sys_vm_invalidate(u32 addr, u32 size) { sys_vm.todo("sys_vm_invalidate(addr=0x%x, size=0x%x)", addr, size); return CELL_OK; } -s32 sys_vm_store(u32 addr, u32 size) +ppu_error_code sys_vm_store(u32 addr, u32 size) { - sys_vm.todo("sys_vm_store(addr=0x%x, size=0x%x)", addr, size); + sys_vm.warning("sys_vm_store(addr=0x%x, size=0x%x)", addr, size); return CELL_OK; } -s32 sys_vm_sync(u32 addr, u32 size) +ppu_error_code sys_vm_sync(u32 addr, u32 size) { - sys_vm.todo("sys_vm_sync(addr=0x%x, size=0x%x)", addr, size); + sys_vm.warning("sys_vm_sync(addr=0x%x, size=0x%x)", addr, size); return CELL_OK; } -s32 sys_vm_test(u32 addr, u32 size, vm::ptr result) +ppu_error_code sys_vm_test(u32 addr, u32 size, vm::ptr result) { - sys_vm.todo("sys_vm_test(addr=0x%x, size=0x%x, result=*0x%x)", addr, size, result); + sys_vm.warning("sys_vm_test(addr=0x%x, size=0x%x, result=*0x%x)", addr, size, result); *result = SYS_VM_STATE_ON_MEMORY; return CELL_OK; } -s32 sys_vm_get_statistics(u32 addr, vm::ptr stat) +ppu_error_code sys_vm_get_statistics(u32 addr, vm::ptr stat) { - sys_vm.todo("sys_vm_get_statistics(addr=0x%x, stat=*0x%x)", addr, stat); + sys_vm.warning("sys_vm_get_statistics(addr=0x%x, stat=*0x%x)", addr, stat); stat->page_fault_ppu = 0; stat->page_fault_spu = 0; diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.h b/rpcs3/Emu/Cell/lv2/sys_vm.h index 5c03b588d1..84b2542b3c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.h +++ b/rpcs3/Emu/Cell/lv2/sys_vm.h @@ -1,6 +1,8 @@ #pragma once -#include "sys_sync.h" +#include "Emu/Memory/Memory.h" +#include "Emu/Cell/ErrorCodes.h" +#include "Emu/IdManager.h" enum : u64 { @@ -8,6 +10,8 @@ enum : u64 SYS_VM_STATE_UNUSED = 1ull, SYS_VM_STATE_ON_MEMORY = 2ull, SYS_VM_STATE_STORED = 4ull, + + SYS_VM_POLICY_AUTO_RECOMMENDED = 1ull, }; struct sys_vm_statistics_t @@ -22,16 +26,16 @@ struct sys_vm_statistics_t }; // SysCalls -s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); -s32 sys_vm_unmap(u32 addr); -s32 sys_vm_append_memory(u32 addr, u32 size); -s32 sys_vm_return_memory(u32 addr, u32 size); -s32 sys_vm_lock(u32 addr, u32 size); -s32 sys_vm_unlock(u32 addr, u32 size); -s32 sys_vm_touch(u32 addr, u32 size); -s32 sys_vm_flush(u32 addr, u32 size); -s32 sys_vm_invalidate(u32 addr, u32 size); -s32 sys_vm_store(u32 addr, u32 size); -s32 sys_vm_sync(u32 addr, u32 size); -s32 sys_vm_test(u32 addr, u32 size, vm::ptr result); -s32 sys_vm_get_statistics(u32 addr, vm::ptr stat); +ppu_error_code sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ps3::ptr addr); +ppu_error_code sys_vm_unmap(u32 addr); +ppu_error_code sys_vm_append_memory(u32 addr, u32 size); +ppu_error_code sys_vm_return_memory(u32 addr, u32 size); +ppu_error_code sys_vm_lock(u32 addr, u32 size); +ppu_error_code sys_vm_unlock(u32 addr, u32 size); +ppu_error_code sys_vm_touch(u32 addr, u32 size); +ppu_error_code sys_vm_flush(u32 addr, u32 size); +ppu_error_code sys_vm_invalidate(u32 addr, u32 size); +ppu_error_code sys_vm_store(u32 addr, u32 size); +ppu_error_code sys_vm_sync(u32 addr, u32 size); +ppu_error_code sys_vm_test(u32 addr, u32 size, vm::ps3::ptr result); +ppu_error_code sys_vm_get_statistics(u32 addr, vm::ps3::ptr stat); From f5e65e4ad9d34bced93967d8dd1b1601e4f2019e Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 25 May 2016 13:55:14 +0300 Subject: [PATCH 3/6] Partial commit: sys_tty --- rpcs3/Emu/Cell/lv2/sys_tty.cpp | 18 +++++++----------- rpcs3/Emu/Cell/lv2/sys_tty.h | 7 ++++--- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_tty.cpp b/rpcs3/Emu/Cell/lv2/sys_tty.cpp index 4a9b62ca72..bb991d3d82 100644 --- a/rpcs3/Emu/Cell/lv2/sys_tty.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_tty.cpp @@ -1,25 +1,21 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" - -#include "Emu/Cell/ErrorCodes.h" #include "sys_tty.h" +namespace vm { using namespace ps3; } + logs::channel sys_tty("sys_tty", logs::level::notice); extern fs::file g_tty; -s32 sys_tty_read(s32 ch, vm::ptr buf, u32 len, vm::ptr preadlen) +ppu_error_code sys_tty_read(s32 ch, vm::ptr buf, u32 len, vm::ptr preadlen) { - sys_tty.todo("sys_tty_read(ch=%d, buf=*0x%x, len=%d, preadlen=*0x%x)", ch, buf, len, preadlen); + sys_tty.fatal("sys_tty_read(ch=%d, buf=*0x%x, len=%d, preadlen=*0x%x)", ch, buf, len, preadlen); // We currently do not support reading from the Console - *preadlen = 0; - Emu.Pause(); - return CELL_OK; + throw std::runtime_error("Unimplemented" HERE); } -s32 sys_tty_write(s32 ch, vm::cptr buf, u32 len, vm::ptr pwritelen) +ppu_error_code sys_tty_write(s32 ch, vm::cptr buf, u32 len, vm::ptr pwritelen) { sys_tty.notice("sys_tty_write(ch=%d, buf=*0x%x, len=%d, pwritelen=*0x%x)", ch, buf, len, pwritelen); @@ -28,7 +24,7 @@ s32 sys_tty_write(s32 ch, vm::cptr buf, u32 len, vm::ptr pwritelen) return CELL_EINVAL; } - if ((s32)len <= 0) + if (static_cast(len) <= 0) { *pwritelen = 0; diff --git a/rpcs3/Emu/Cell/lv2/sys_tty.h b/rpcs3/Emu/Cell/lv2/sys_tty.h index 7c7f7ddba0..4eb8f092d8 100644 --- a/rpcs3/Emu/Cell/lv2/sys_tty.h +++ b/rpcs3/Emu/Cell/lv2/sys_tty.h @@ -1,6 +1,7 @@ #pragma once -namespace vm { using namespace ps3; } +#include "Emu/Memory/Memory.h" +#include "Emu/Cell/ErrorCodes.h" // TTY channels enum @@ -25,5 +26,5 @@ enum }; // SysCalls -s32 sys_tty_read(s32 ch, vm::ptr buf, u32 len, vm::ptr preadlen); -s32 sys_tty_write(s32 ch, vm::cptr buf, u32 len, vm::ptr pwritelen); +ppu_error_code sys_tty_read(s32 ch, vm::ps3::ptr buf, u32 len, vm::ps3::ptr preadlen); +ppu_error_code sys_tty_write(s32 ch, vm::ps3::cptr buf, u32 len, vm::ps3::ptr pwritelen); From 96728a83f6569a8413e6973d235d12594e80cb2c Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 25 May 2016 21:04:08 +0300 Subject: [PATCH 4/6] Partial commit: sys_memory, sys_mmapper --- Utilities/Thread.cpp | 1 + rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp | 43 ++++- rpcs3/Emu/Cell/PPUFunction.cpp | 2 +- rpcs3/Emu/Cell/lv2/lv2.cpp | 10 +- rpcs3/Emu/Cell/lv2/sys_memory.cpp | 208 ++++++++++-------------- rpcs3/Emu/Cell/lv2/sys_memory.h | 56 ++++--- rpcs3/Emu/Cell/lv2/sys_mmapper.cpp | 197 +++++++++++----------- rpcs3/Emu/Cell/lv2/sys_mmapper.h | 36 ++-- rpcs3/Emu/Cell/lv2/sys_process.cpp | 4 +- rpcs3/Emu/Cell/lv2/sys_vm.cpp | 2 +- rpcs3/Emu/Memory/vm.cpp | 122 +++++++------- rpcs3/Emu/Memory/vm.h | 50 +++--- rpcs3/Gui/KernelExplorer.cpp | 10 +- 13 files changed, 366 insertions(+), 375 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 999c31355e..77f876ea0f 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -12,6 +12,7 @@ #define _XOPEN_SOURCE #define __USE_GNU #endif +#include #include #include #endif diff --git a/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp b/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp index e07618022e..a4a0fbaf41 100644 --- a/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp @@ -1,15 +1,48 @@ #include "stdafx.h" -#include "Emu/System.h" #include "Emu/Cell/PPUModule.h" - #include "Emu/Cell/lv2/sys_mmapper.h" -#include "sysPrxForUser.h" + +namespace vm { using namespace ps3; } extern logs::channel sysPrxForUser; -void sysPrxForUser_sys_mmapper_init() +s32 sys_mmapper_allocate_memory(u32 size, u64 flags, vm::ptr mem_id) +{ + sysPrxForUser.notice("sys_mmapper_allocate_memory(size=0x%x, flags=0x%llx, mem_id=*0x%x)", size, flags, mem_id); + + return sys_mmapper_allocate_shared_memory(0xffff000000000000ull, size, flags, mem_id); +} + +s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm::ptr mem_id) +{ + sysPrxForUser.notice("sys_mmapper_allocate_memory_from_container(size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", size, cid, flags, mem_id); + + return sys_mmapper_allocate_shared_memory_from_container(0xffff000000000000ull, size, cid, flags, mem_id); +} + +s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags) +{ + sysPrxForUser.notice("sys_mmapper_map_memory(addr=0x%x, mem_id=0x%x, flags=0x%llx)", addr, mem_id, flags); + + return sys_mmapper_map_shared_memory(addr, mem_id, flags); +} + +s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr mem_id) +{ + sysPrxForUser.notice("sys_mmapper_unmap_memory(addr=0x%x, mem_id=*0x%x)", addr, mem_id); + + return sys_mmapper_unmap_shared_memory(addr, mem_id); +} + +s32 sys_mmapper_free_memory(u32 mem_id) +{ + sysPrxForUser.notice("sys_mmapper_free_memory(mem_id=0x%x)", mem_id); + + return sys_mmapper_free_shared_memory(mem_id); +} + +extern void sysPrxForUser_sys_mmapper_init() { - // TODO: split syscalls and liblv2 functions REG_FUNC(sysPrxForUser, sys_mmapper_allocate_memory); REG_FUNC(sysPrxForUser, sys_mmapper_allocate_memory_from_container); REG_FUNC(sysPrxForUser, sys_mmapper_map_memory); diff --git a/rpcs3/Emu/Cell/PPUFunction.cpp b/rpcs3/Emu/Cell/PPUFunction.cpp index 692a83a589..7ec4bb34f3 100644 --- a/rpcs3/Emu/Cell/PPUFunction.cpp +++ b/rpcs3/Emu/Cell/PPUFunction.cpp @@ -229,7 +229,7 @@ extern std::string ppu_get_syscall_name(u64 code) case 353: return "sys_memory_get_user_memory_stat"; case 356: return "sys_memory_allocate_colored"; case 361: return "sys_memory_allocate_from_container_colored"; - case 362: return "sys_mmapper_allocate_memory_from_container"; + case 362: return "sys_mmapper_allocate_shared_memory_from_container"; case 367: return "sys_uart_initialize"; case 368: return "sys_uart_receive"; case 369: return "sys_uart_send"; diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 037a24cce7..3b6ab8a1ef 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -333,13 +333,13 @@ std::array g_ppu_syscall_table BIND_FUNC(sys_mmapper_allocate_fixed_address), //326 (0x146) BIND_FUNC(sys_mmapper_enable_page_fault_notification), //327 (0x147) null_func,//BIND_FUNC(sys_mmapper_...) //328 (0x148) - null_func,//BIND_FUNC(sys_mmapper_free_shared_memory) //329 (0x149) + BIND_FUNC(sys_mmapper_free_shared_memory), //329 (0x149) BIND_FUNC(sys_mmapper_allocate_address), //330 (0x14A) BIND_FUNC(sys_mmapper_free_address), //331 (0x14B) - null_func,//BIND_FUNC(sys_mmapper_allocate_shared_memory)//332(0x14C) + BIND_FUNC(sys_mmapper_allocate_shared_memory), //332 (0x14C) null_func,//BIND_FUNC(sys_mmapper_set_shared_memory_flag)//333(0x14D) - null_func,//BIND_FUNC(sys_mmapper_map_shared_memory) //334 (0x14E) - null_func,//BIND_FUNC(sys_mmapper_unmap_shared_memory) //335 (0x14F) + BIND_FUNC(sys_mmapper_map_shared_memory), //334 (0x14E) + BIND_FUNC(sys_mmapper_unmap_shared_memory), //335 (0x14F) BIND_FUNC(sys_mmapper_change_address_access_right), //336 (0x150) BIND_FUNC(sys_mmapper_search_and_map), //337 (0x151) null_func,//BIND_FUNC(sys_mmapper_get_shared_memory_attribute) //338 (0x152) @@ -366,7 +366,7 @@ std::array g_ppu_syscall_table null_func,//BIND_FUNC(sys_memory_...) //359 (0x167) null_func,//BIND_FUNC(sys_memory_...) //360 (0x168) null_func,//BIND_FUNC(sys_memory_allocate_from_container_colored) //361 (0x169) - null_func,//BIND_FUNC(sys_mmapper_allocate_memory_from_container) //362 (0x16A) + BIND_FUNC(sys_mmapper_allocate_shared_memory_from_container),//362 (0x16A) null_func,//BIND_FUNC(sys_mmapper_...) //363 (0x16B) null_func,//BIND_FUNC(sys_mmapper_...) //364 (0x16C) null_func, //365 (0x16D) UNS diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp index ac850638f4..3902823b2d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -1,21 +1,16 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/IdManager.h" - -#include "Emu/Cell/ErrorCodes.h" #include "sys_memory.h" +namespace vm { using namespace ps3; } + logs::channel sys_memory("sys_memory", logs::level::notice); -s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr alloc_addr) +ppu_error_code sys_memory_allocate(u32 size, u64 flags, vm::ptr alloc_addr) { sys_memory.warning("sys_memory_allocate(size=0x%x, flags=0x%llx, alloc_addr=*0x%x)", size, flags, alloc_addr); - LV2_LOCK; - // Check allocation size - switch(flags) + switch (flags) { case SYS_MEMORY_PAGE_SIZE_1M: { @@ -43,36 +38,24 @@ s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr alloc_addr) } } - // Allocate memory - const u32 addr = - flags == SYS_MEMORY_PAGE_SIZE_1M ? vm::alloc(size, vm::user_space, 0x100000) : - flags == SYS_MEMORY_PAGE_SIZE_64K ? vm::alloc(size, vm::user_space, 0x10000) : - throw EXCEPTION("Unexpected flags"); + // Get "default" memory container + const auto dct = fxm::get_always(); - if (!addr) + // Try to get "physical memory" + if (!dct->take(size)) { return CELL_ENOMEM; } - - // Write back the start address of the allocated area - *alloc_addr = addr; + + // Allocate memory, write back the start address of the allocated area + VERIFY(*alloc_addr = vm::alloc(size, vm::user_space, flags == SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000)); return CELL_OK; } -s32 sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptr alloc_addr) +ppu_error_code sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptr alloc_addr) { sys_memory.warning("sys_memory_allocate_from_container(size=0x%x, cid=0x%x, flags=0x%llx, alloc_addr=*0x%x)", size, cid, flags, alloc_addr); - - LV2_LOCK; - - // Check if this container ID is valid - const auto ct = idm::get(cid); - - if (!ct) - { - return CELL_ESRCH; - } // Check allocation size switch (flags) @@ -103,89 +86,69 @@ s32 sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptrused > ct->size) + ppu_error_code result{}; + + const auto ct = idm::get(cid, [&](u32, lv2_memory_container& ct) { - throw EXCEPTION("Unexpected amount of memory taken (0x%x, size=0x%x)", ct->used.load(), ct->size); + // Try to get "physical memory" + if (!ct.take(size)) + { + result = CELL_ENOMEM; + return_ false; + } + + return_ true; + }); + + if (!ct && !result) + { + return CELL_ESRCH; } - // Check memory availability - if (size > ct->size - ct->used) + if (!ct) { - return CELL_ENOMEM; + return result; } - const auto area = vm::get(vm::user_space); - - // Return "physical" memory required for allocation - area->used -= size; - - // Allocate memory - const u32 addr = - flags == SYS_MEMORY_PAGE_SIZE_1M ? area->alloc(size, 0x100000) : - flags == SYS_MEMORY_PAGE_SIZE_64K ? area->alloc(size, 0x10000) : - throw EXCEPTION("Unexpected flags"); - - if (!addr) - { - throw EXCEPTION("Memory not allocated (ct=0x%x, size=0x%x)", cid, size); - } - - // Store the address and size in the container - ct->allocs.emplace(addr, size); - ct->used += size; - - // Write back the start address of the allocated area. - *alloc_addr = addr; + // Allocate memory, write back the start address of the allocated area, use cid as the supplementary info + VERIFY(*alloc_addr = vm::alloc(size, vm::user_space, flags == SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000, cid)); return CELL_OK; } -s32 sys_memory_free(u32 addr) +ppu_error_code sys_memory_free(u32 addr) { sys_memory.warning("sys_memory_free(addr=0x%x)", addr); - LV2_LOCK; - const auto area = vm::get(vm::user_space); - // Check all memory containers - const auto ct = idm::select([&](u32, lv2_memory_container_t& ct) - { - return ct.allocs.count(addr) != 0; - }); + VERIFY(area); - if (ct) - { - const u32 size = ct->allocs.at(addr); + // Deallocate memory + u32 cid, size = area->dealloc(addr, &cid); - if (!area->dealloc(addr)) - { - throw EXCEPTION("Memory not deallocated (cid=0x%x, addr=0x%x, size=0x%x)", ct->id, addr, size); - } - - ct->allocs.erase(addr); - - // Return "memory" - ct->used -= size; - area->used += size; - - return CELL_OK; - } - - if (!area->dealloc(addr)) + if (!size) { return CELL_EINVAL; } + // Return "physical memory" + if (cid == 0) + { + fxm::get()->used -= size; + } + else if (const auto ct = idm::get(cid)) + { + ct->used -= size; + } + return CELL_OK; } -s32 sys_memory_get_page_attribute(u32 addr, vm::ptr attr) +ppu_error_code sys_memory_get_page_attribute(u32 addr, vm::ptr attr) { sys_memory.error("sys_memory_get_page_attribute(addr=0x%x, attr=*0x%x)", addr, attr); - LV2_LOCK; - // TODO: Implement per thread page attribute setting. attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE attr->access_right = 0xFull; // SYS_MEMORY_ACCESS_RIGHT_ANY @@ -194,35 +157,29 @@ s32 sys_memory_get_page_attribute(u32 addr, vm::ptr attr) return CELL_OK; } -s32 sys_memory_get_user_memory_size(vm::ptr mem_info) +ppu_error_code sys_memory_get_user_memory_size(vm::ptr mem_info) { sys_memory.warning("sys_memory_get_user_memory_size(mem_info=*0x%x)", mem_info); - LV2_LOCK; + // Get "default" memory container + const auto dct = fxm::get_always(); - u32 reserved = 0; + mem_info->total_user_memory = dct->size; + mem_info->available_user_memory = dct->size - dct->used; - // Check all memory containers - idm::select([&](u32, lv2_memory_container_t& ct) + // Scan other memory containers + idm::select([&](u32, lv2_memory_container& ct) { - reserved += ct.size; + mem_info->total_user_memory -= ct.size; }); - const auto area = vm::get(vm::user_space); - - // Fetch the user memory available - mem_info->total_user_memory = area->size - reserved; - mem_info->available_user_memory = area->size - area->used; - return CELL_OK; } -s32 sys_memory_container_create(vm::ptr cid, u32 size) +ppu_error_code sys_memory_container_create(vm::ptr cid, u32 size) { sys_memory.warning("sys_memory_container_create(cid=*0x%x, size=0x%x)", cid, size); - LV2_LOCK; - // Round down to 1 MB granularity size &= ~0xfffff; @@ -231,66 +188,67 @@ s32 sys_memory_container_create(vm::ptr cid, u32 size) return CELL_ENOMEM; } - u32 reserved = 0; + const auto dct = fxm::get_always(); - // Check all memory containers - idm::select([&](u32, lv2_memory_container_t& ct) - { - reserved += ct.size; - }); - - const auto area = vm::get(vm::user_space); - - if (area->size < reserved + size || area->size - area->used < size) + // Try to obtain "physical memory" from the default container + if (!dct->take(size)) { return CELL_ENOMEM; } // Create the memory container - *cid = idm::make(size); + *cid = idm::make(size); return CELL_OK; } -s32 sys_memory_container_destroy(u32 cid) +ppu_error_code sys_memory_container_destroy(u32 cid) { sys_memory.warning("sys_memory_container_destroy(cid=0x%x)", cid); - LV2_LOCK; + ppu_error_code result{}; - const auto ct = idm::get(cid); + const auto ct = idm::withdraw(cid, [&](u32, lv2_memory_container& ct) + { + // Check if some memory is not deallocated (the container cannot be destroyed in this case) + if (!ct.used.compare_and_swap_test(0, ct.size)) + { + result = CELL_EBUSY; + return_ false; + } - if (!ct) + return_ true; + }); + + if (!ct && !result) { return CELL_ESRCH; } - // Check if some memory is not deallocated (the container cannot be destroyed in this case) - if (ct->used) + if (!ct) { - return CELL_EBUSY; + return result; } - idm::remove(cid); + // Return "physical memory" to the default container + fxm::get()->used -= ct->size; return CELL_OK; } -s32 sys_memory_container_get_size(vm::ptr mem_info, u32 cid) +ppu_error_code sys_memory_container_get_size(vm::ptr mem_info, u32 cid) { sys_memory.warning("sys_memory_container_get_size(mem_info=*0x%x, cid=0x%x)", mem_info, cid); - LV2_LOCK; - - const auto ct = idm::get(cid); + const auto ct = idm::get(cid); if (!ct) { return CELL_ESRCH; } - mem_info->total_user_memory = ct->size; // total container memory - mem_info->available_user_memory = ct->size - ct->used; // available container memory + mem_info->total_user_memory = ct->size; // Total container memory + mem_info->available_user_memory = ct->size - ct->used; // Available container memory return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.h b/rpcs3/Emu/Cell/lv2/sys_memory.h index bf9e425430..896ebade8e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.h +++ b/rpcs3/Emu/Cell/lv2/sys_memory.h @@ -1,6 +1,8 @@ #pragma once -#include "sys_sync.h" +#include "Emu/Memory/Memory.h" +#include "Emu/Cell/ErrorCodes.h" +#include "Emu/IdManager.h" enum : u32 { @@ -42,33 +44,45 @@ struct sys_page_attr_t be_t pad; }; -#include - -struct lv2_memory_container_t +struct lv2_memory_container { - // Amount of "physical" memory in this container - const u32 size; + const u32 size = 0x10000000; // Amount of "physical" memory in this container - const id_value<> id{}; - - // Amount of memory allocated - atomic_t used{ 0 }; + atomic_t used{}; // Amount of "physical" memory currently used - // Allocations (addr -> size) - std::map allocs; + lv2_memory_container() = default; - lv2_memory_container_t(u32 size) + lv2_memory_container(u32 size) : size(size) { } + + // Try to get specified amount of "physical" memory + u32 take(u32 amount) + { + const u32 old_value = used.fetch_op([&](u32& value) + { + if (size - value >= amount) + { + value += amount; + } + }); + + if (size - old_value >= amount) + { + return amount; + } + + return 0; + } }; // SysCalls -s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr alloc_addr); -s32 sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptr alloc_addr); -s32 sys_memory_free(u32 start_addr); -s32 sys_memory_get_page_attribute(u32 addr, vm::ptr attr); -s32 sys_memory_get_user_memory_size(vm::ptr mem_info); -s32 sys_memory_container_create(vm::ptr cid, u32 size); -s32 sys_memory_container_destroy(u32 cid); -s32 sys_memory_container_get_size(vm::ptr mem_info, u32 cid); +ppu_error_code sys_memory_allocate(u32 size, u64 flags, vm::ps3::ptr alloc_addr); +ppu_error_code sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ps3::ptr alloc_addr); +ppu_error_code sys_memory_free(u32 start_addr); +ppu_error_code sys_memory_get_page_attribute(u32 addr, vm::ps3::ptr attr); +ppu_error_code sys_memory_get_user_memory_size(vm::ps3::ptr mem_info); +ppu_error_code sys_memory_container_create(vm::ps3::ptr cid, u32 size); +ppu_error_code sys_memory_container_destroy(u32 cid); +ppu_error_code sys_memory_container_get_size(vm::ps3::ptr mem_info, u32 cid); diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp index 12d9218ccd..b295c3e99d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp @@ -1,19 +1,14 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/IdManager.h" - -#include "Emu/Cell/ErrorCodes.h" #include "sys_mmapper.h" +namespace vm { using namespace ps3; } + logs::channel sys_mmapper("sys_mmapper", logs::level::notice); -s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr alloc_addr) +ppu_error_code sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr alloc_addr) { sys_mmapper.error("sys_mmapper_allocate_address(size=0x%llx, flags=0x%llx, alignment=0x%llx, alloc_addr=*0x%x)", size, flags, alignment, alloc_addr); - LV2_LOCK; - if (size % 0x10000000) { return CELL_EALIGN; @@ -24,9 +19,8 @@ s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr(addr), static_cast(size), flags)) { - *alloc_addr = addr; - + *alloc_addr = static_cast(addr); return CELL_OK; } } @@ -56,12 +49,10 @@ s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr mem_id) +ppu_error_code sys_mmapper_allocate_shared_memory(u64 unk, u32 size, u64 flags, vm::ptr mem_id) { - sys_mmapper.warning("sys_mmapper_allocate_memory(size=0x%llx, flags=0x%llx, mem_id=*0x%x)", size, flags, mem_id); - - LV2_LOCK; + sys_mmapper.warning("sys_mmapper_allocate_shared_memory(0x%llx, size=0x%x, flags=0x%llx, mem_id=*0x%x)", unk, size, flags, mem_id); // Check page granularity switch (flags & SYS_MEMORY_PAGE_SIZE_MASK) @@ -106,35 +94,23 @@ s32 sys_mmapper_allocate_memory(u64 size, u64 flags, vm::ptr mem_id) } } - if (size > UINT32_MAX) + // Get "default" memory container + const auto dct = fxm::get_always(); + + if (!dct->take(size)) { return CELL_ENOMEM; } - const u32 align = - flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : - flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : - throw EXCEPTION("Unexpected"); - // Generate a new mem ID - *mem_id = idm::make(static_cast(size), align, flags, nullptr); + *mem_id = idm::make(size, flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000, flags, dct); return CELL_OK; } -s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm::ptr mem_id) +ppu_error_code sys_mmapper_allocate_shared_memory_from_container(u64 unk, u32 size, u32 cid, u64 flags, vm::ptr mem_id) { - sys_mmapper.error("sys_mmapper_allocate_memory_from_container(size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", size, cid, flags, mem_id); - - LV2_LOCK; - - // Check if this container ID is valid. - const auto ct = idm::get(cid); - - if (!ct) - { - return CELL_ESRCH; - } + sys_mmapper.error("sys_mmapper_allocate_shared_memory_from_container(0x%llx, size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", unk, size, cid, flags, mem_id); // Check page granularity. switch (flags & SYS_MEMORY_PAGE_SIZE_MASK) @@ -165,93 +141,100 @@ s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm: } } - if (ct->size - ct->used < size) + ppu_error_code result{}; + + const auto ct = idm::get(cid, [&](u32, lv2_memory_container& ct) { - return CELL_ENOMEM; + // Try to get "physical memory" + if (!ct.take(size)) + { + result = CELL_ENOMEM; + return_ false; + } + + return_ true; + }); + + if (!ct && !result) + { + return CELL_ESRCH; } - const u32 align = - flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : - flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : - throw EXCEPTION("Unexpected"); - - ct->used += size; + if (!ct) + { + return result; + } // Generate a new mem ID - *mem_id = idm::make(size, align, flags, ct); + *mem_id = idm::make(size, flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000, flags, ct); return CELL_OK; } -s32 sys_mmapper_change_address_access_right(u32 addr, u64 flags) +ppu_error_code sys_mmapper_change_address_access_right(u32 addr, u64 flags) { sys_mmapper.todo("sys_mmapper_change_address_access_right(addr=0x%x, flags=0x%llx)", addr, flags); return CELL_OK; } -s32 sys_mmapper_free_address(u32 addr) +ppu_error_code sys_mmapper_free_address(u32 addr) { sys_mmapper.error("sys_mmapper_free_address(addr=0x%x)", addr); - LV2_LOCK; + // Try to unmap area + const auto area = vm::unmap(addr, true); - const auto area = vm::get(vm::any, addr); - - if (!area || addr != area->addr) + if (!area) { return CELL_EINVAL; } - if (area->used) + if (!area.unique()) { return CELL_EBUSY; } - if (!vm::unmap(addr)) - { - throw EXCEPTION("Unexpected (failed to unmap memory ad 0x%x)", addr); - } - return CELL_OK; } -s32 sys_mmapper_free_memory(u32 mem_id) +ppu_error_code sys_mmapper_free_shared_memory(u32 mem_id) { - sys_mmapper.warning("sys_mmapper_free_memory(mem_id=0x%x)", mem_id); + sys_mmapper.warning("sys_mmapper_free_shared_memory(mem_id=0x%x)", mem_id); - LV2_LOCK; + ppu_error_code result{}; - // Check if this mem ID is valid. - const auto mem = idm::get(mem_id); + // Conditionally remove memory ID + const auto mem = idm::withdraw(mem_id, [&](u32, lv2_memory& mem) + { + if (mem.addr.compare_and_swap_test(0, -1)) + { + result = CELL_EBUSY; + return_ false; + } - if (!mem) + return_ true; + }); + + if (!mem && !result) { return CELL_ESRCH; } - if (mem->addr) + if (!mem) { - return CELL_EBUSY; + return result; } - // Return physical memory to the container if necessary - if (mem->ct) - { - mem->ct->used -= mem->size; - } - - // Release the allocated memory and remove the ID - idm::remove(mem_id); + // Return "physical memory" to the memory container + mem->ct->used -= mem->size; return CELL_OK; } -s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags) +ppu_error_code sys_mmapper_map_shared_memory(u32 addr, u32 mem_id, u64 flags) { - sys_mmapper.error("sys_mmapper_map_memory(addr=0x%x, mem_id=0x%x, flags=0x%llx)", addr, mem_id, flags); - - LV2_LOCK; + sys_mmapper.error("sys_mmapper_map_shared_memory(addr=0x%x, mem_id=0x%x, flags=0x%llx)", addr, mem_id, flags); const auto area = vm::get(vm::any, addr); @@ -260,7 +243,7 @@ s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags) return CELL_EINVAL; } - const auto mem = idm::get(mem_id); + const auto mem = idm::get(mem_id); if (!mem) { @@ -272,28 +255,26 @@ s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags) return CELL_EALIGN; } - if (const u32 old_addr = mem->addr) + if (const u32 old_addr = mem->addr.compare_and_swap(0, -1)) { - sys_mmapper.warning("sys_mmapper_map_memory: Already mapped (mem_id=0x%x, addr=0x%x)", mem_id, old_addr); + sys_mmapper.warning("sys_mmapper_map_shared_memory(): Already mapped (mem_id=0x%x, addr=0x%x)", mem_id, old_addr); return CELL_OK; } if (!area->falloc(addr, mem->size)) { + mem->addr = 0; return CELL_EBUSY; } mem->addr = addr; - return CELL_OK; } -s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ptr alloc_addr) +ppu_error_code sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ptr alloc_addr) { sys_mmapper.error("sys_mmapper_search_and_map(start_addr=0x%x, mem_id=0x%x, flags=0x%llx, alloc_addr=*0x%x)", start_addr, mem_id, flags, alloc_addr); - LV2_LOCK; - const auto area = vm::get(vm::any, start_addr); if (!area || start_addr != area->addr || start_addr < 0x30000000 || start_addr >= 0xC0000000) @@ -301,30 +282,34 @@ s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ptr(mem_id); + const auto mem = idm::get(mem_id); if (!mem) { return CELL_ESRCH; } + if (const u32 old_addr = mem->addr.compare_and_swap(0, -1)) + { + sys_mmapper.warning("sys_mmapper_search_and_map(): Already mapped (mem_id=0x%x, addr=0x%x)", mem_id, old_addr); + return CELL_OK; + } + const u32 addr = area->alloc(mem->size, mem->align); if (!addr) { + mem->addr = 0; return CELL_ENOMEM; } - *alloc_addr = addr; - + *alloc_addr = mem->addr = addr; return CELL_OK; } -s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr mem_id) +ppu_error_code sys_mmapper_unmap_shared_memory(u32 addr, vm::ptr mem_id) { - sys_mmapper.error("sys_mmapper_unmap_memory(addr=0x%x, mem_id=*0x%x)", addr, mem_id); - - LV2_LOCK; + sys_mmapper.error("sys_mmapper_unmap_shared_memory(addr=0x%x, mem_id=*0x%x)", addr, mem_id); const auto area = vm::get(vm::any, addr); @@ -333,9 +318,15 @@ s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr mem_id) return CELL_EINVAL; } - const auto mem = idm::select([&](u32, lv2_memory_t& mem) + const auto mem = idm::select([&](u32 id, lv2_memory& mem) { - return mem.addr == addr; + if (mem.addr == addr) + { + *mem_id = id; + return true; + } + + return false; }); if (!mem) @@ -343,19 +334,13 @@ s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr mem_id) return CELL_EINVAL; } - if (!area->dealloc(addr)) - { - throw EXCEPTION("Deallocation failed (mem_id=0x%x, addr=0x%x)", mem->id, addr); - } - - mem->addr = 0; - - *mem_id = mem->id; + VERIFY(area->dealloc(addr)); + VERIFY(mem->addr.exchange(0) == addr); return CELL_OK; } -s32 sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq) +ppu_error_code sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq) { sys_mmapper.todo("sys_mmapper_enable_page_fault_notification(addr=0x%x, eq=0x%x)", addr, eq); diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.h b/rpcs3/Emu/Cell/lv2/sys_mmapper.h index 0ecaf08d47..ac312841d1 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.h +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.h @@ -2,18 +2,16 @@ #include "sys_memory.h" -struct lv2_memory_t +struct lv2_memory { - const u32 size; // memory size - const u32 align; // required alignment + const u32 size; // Memory size + const u32 align; // Alignment required const u64 flags; - const std::shared_ptr ct; // memory container the physical memory is taken from + const std::shared_ptr ct; // Associated memory container - const id_value<> id{}; + atomic_t addr{}; // Actual mapping address - atomic_t addr{ 0 }; // actual mapping address - - lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr ct) + lv2_memory(u32 size, u32 align, u64 flags, const std::shared_ptr& ct) : size(size) , align(align) , flags(flags) @@ -23,14 +21,14 @@ struct lv2_memory_t }; // SysCalls -s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr alloc_addr); -s32 sys_mmapper_allocate_fixed_address(); -s32 sys_mmapper_allocate_memory(u64 size, u64 flags, vm::ptr mem_id); -s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm::ptr mem_id); -s32 sys_mmapper_change_address_access_right(u32 addr, u64 flags); -s32 sys_mmapper_free_address(u32 addr); -s32 sys_mmapper_free_memory(u32 mem_id); -s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags); -s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ptr alloc_addr); -s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr mem_id); -s32 sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq); +ppu_error_code sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ps3::ptr alloc_addr); +ppu_error_code sys_mmapper_allocate_fixed_address(); +ppu_error_code sys_mmapper_allocate_shared_memory(u64 unk, u32 size, u64 flags, vm::ps3::ptr mem_id); +ppu_error_code sys_mmapper_allocate_shared_memory_from_container(u64 unk, u32 size, u32 cid, u64 flags, vm::ps3::ptr mem_id); +ppu_error_code sys_mmapper_change_address_access_right(u32 addr, u64 flags); +ppu_error_code sys_mmapper_free_address(u32 addr); +ppu_error_code sys_mmapper_free_shared_memory(u32 mem_id); +ppu_error_code sys_mmapper_map_shared_memory(u32 addr, u32 mem_id, u64 flags); +ppu_error_code sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ps3::ptr alloc_addr); +ppu_error_code sys_mmapper_unmap_shared_memory(u32 addr, vm::ps3::ptr mem_id); +ppu_error_code sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq); diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index f1dcde9162..09ac2af5f9 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -74,7 +74,7 @@ s32 sys_process_get_number_of_object(u32 object, vm::ptr nump) switch(object) { - case SYS_MEM_OBJECT: *nump = idm::get_count(); break; + case SYS_MEM_OBJECT: *nump = idm::get_count(); break; case SYS_MUTEX_OBJECT: *nump = idm::get_count(); break; case SYS_COND_OBJECT: *nump = idm::get_count(); break; case SYS_RWLOCK_OBJECT: *nump = idm::get_count(); break; @@ -121,7 +121,7 @@ s32 sys_process_get_id(u32 object, vm::ptr buffer, u32 size, vm::ptr s switch (object) { - case SYS_MEM_OBJECT: idm_get_set(objects); break; + case SYS_MEM_OBJECT: idm_get_set(objects); break; case SYS_MUTEX_OBJECT: idm_get_set(objects); break; case SYS_COND_OBJECT: idm_get_set(objects); break; case SYS_RWLOCK_OBJECT: idm_get_set(objects); break; diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp index 61a10ad935..7258d73de0 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -15,7 +15,7 @@ ppu_error_code sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 po return CELL_EINVAL; } - if (cid != SYS_MEMORY_CONTAINER_ID_INVALID && !idm::check(cid)) + if (cid != SYS_MEMORY_CONTAINER_ID_INVALID && !idm::check(cid)) { return CELL_ESRCH; } diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 0f3f70ef5f..9c65309214 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -24,6 +24,8 @@ #include "wait_engine.h" +#include + namespace vm { thread_local u64 g_tls_fault_count{}; @@ -482,7 +484,7 @@ namespace vm return true; } - u32 alloc(u32 size, memory_location_t location, u32 align) + u32 alloc(u32 size, memory_location_t location, u32 align, u32 sup) { const auto block = get(location); @@ -491,10 +493,10 @@ namespace vm throw EXCEPTION("Invalid memory location (%d)", location); } - return block->alloc(size, align); + return block->alloc(size, align, sup); } - u32 falloc(u32 addr, u32 size, memory_location_t location) + u32 falloc(u32 addr, u32 size, memory_location_t location, u32 sup) { const auto block = get(location, addr); @@ -503,10 +505,10 @@ namespace vm throw EXCEPTION("Invalid memory location (%d, addr=0x%x)", location, addr); } - return block->falloc(addr, size); + return block->falloc(addr, size, sup); } - bool dealloc(u32 addr, memory_location_t location) + u32 dealloc(u32 addr, memory_location_t location, u32* sup_out) { const auto block = get(location, addr); @@ -515,7 +517,7 @@ namespace vm throw EXCEPTION("Invalid memory location (%d, addr=0x%x)", location, addr); } - return block->dealloc(addr); + return block->dealloc(addr, sup_out); } void dealloc_verbose_nothrow(u32 addr, memory_location_t location) noexcept @@ -535,9 +537,9 @@ namespace vm } } - bool block_t::try_alloc(u32 addr, u32 size) + bool block_t::try_alloc(u32 addr, u32 size, u32 sup) { - // check if memory area is already mapped + // Check if memory area is already mapped for (u32 i = addr / 4096; i <= (addr + size - 1) / 4096; i++) { if (g_pages[i]) @@ -546,86 +548,70 @@ namespace vm } } - // try to reserve "physical" memory - if (!used.atomic_op([=](u32& used) -> bool - { - if (used > this->size) - { - throw EXCEPTION("Unexpected memory amount used (0x%x)", used); - } - - if (used + size > this->size) - { - return false; - } - - used += size; - - return true; - })) - { - return false; - } - - // map memory pages + // Map "real" memory pages _page_map(addr, size, page_readable | page_writable); - // add entry + // Add entry m_map[addr] = size; + // Add supplementary info if necessary + if (sup) m_sup[addr] = sup; + return true; } + block_t::block_t(u32 addr, u32 size, u64 flags) + : addr(addr) + , size(size) + , flags(flags) + { + } + block_t::~block_t() { std::lock_guard lock(g_reservation_mutex); - // deallocate all memory + // Deallocate all memory for (auto& entry : m_map) { _page_unmap(entry.first, entry.second); } } - u32 block_t::alloc(u32 size, u32 align) + u32 block_t::alloc(u32 size, u32 align, u32 sup) { - std::lock_guard lock(m_mutex); + std::lock_guard lock(g_reservation_mutex); - // align to minimal page size + // Align to minimal page size size = ::align(size, 4096); - // check alignment (it's page allocation, so passing small values there is just silly) + // Check alignment (it's page allocation, so passing small values there is just silly) if (align < 4096 || align != (0x80000000u >> cntlz32(align))) { throw EXCEPTION("Invalid alignment (size=0x%x, align=0x%x)", size, align); } - // return if size is invalid + // Return if size is invalid if (!size || size > this->size) { return 0; } - // search for an appropriate place (unoptimized) + // Search for an appropriate place (unoptimized) for (u32 addr = ::align(this->addr, align); addr < this->addr + this->size - 1; addr += align) { - if (try_alloc(addr, size)) + if (try_alloc(addr, size, sup)) { return addr; } - - if (used + size > this->size) - { - return 0; - } } return 0; } - u32 block_t::falloc(u32 addr, u32 size) + u32 block_t::falloc(u32 addr, u32 size, u32 sup) { - std::lock_guard lock(m_mutex); + std::lock_guard lock(g_reservation_mutex); // align to minimal page size size = ::align(size, 4096); @@ -636,7 +622,7 @@ namespace vm return 0; } - if (!try_alloc(addr, size)) + if (!try_alloc(addr, size, sup)) { return 0; } @@ -644,9 +630,9 @@ namespace vm return addr; } - bool block_t::dealloc(u32 addr) + u32 block_t::dealloc(u32 addr, u32* sup_out) { - std::lock_guard lock(m_mutex); + std::lock_guard lock(g_reservation_mutex); const auto found = m_map.find(addr); @@ -654,19 +640,36 @@ namespace vm { const u32 size = found->second; - // remove entry + // Remove entry m_map.erase(found); - // return "physical" memory - used -= size; + // Unmap "real" memory pages + _page_unmap(addr, size); - // unmap memory pages - std::lock_guard{ g_reservation_mutex }, _page_unmap(addr, size); + // Write supplementary info if necessary + if (sup_out) *sup_out = m_sup[addr]; - return true; + // Remove supplementary info + m_sup.erase(addr); + + return size; } - return false; + return 0; + } + + u32 block_t::used() + { + std::lock_guard lock(g_reservation_mutex); + + u32 result = 0; + + for (auto& entry : m_map) + { + result += entry.second; + } + + return result; } std::shared_ptr map(u32 addr, u32 size, u64 flags) @@ -706,7 +709,7 @@ namespace vm return block; } - std::shared_ptr unmap(u32 addr) + std::shared_ptr unmap(u32 addr, bool must_be_empty) { std::lock_guard lock(g_reservation_mutex); @@ -714,6 +717,11 @@ namespace vm { if (*it && (*it)->addr == addr) { + if (must_be_empty && (!it->unique() || (*it)->used())) + { + return *it; + } + auto block = std::move(*it); g_locations.erase(it); return block; diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 26f1af795d..19f1f29b5f 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -1,7 +1,6 @@ #pragma once #include -#include class thread_ctrl; @@ -80,13 +79,13 @@ namespace vm bool check_addr(u32 addr, u32 size = 1); // Search and map memory in specified memory location (don't pass alignment smaller than 4096) - u32 alloc(u32 size, memory_location_t location, u32 align = 4096); + u32 alloc(u32 size, memory_location_t location, u32 align = 4096, u32 sup = 0); // Map memory at specified address (in optionally specified memory location) - u32 falloc(u32 addr, u32 size, memory_location_t location = any); + u32 falloc(u32 addr, u32 size, memory_location_t location = any, u32 sup = 0); - // Unmap memory at specified address (in optionally specified memory location) - bool dealloc(u32 addr, memory_location_t location = any); + // Unmap memory at specified address (in optionally specified memory location), return size + u32 dealloc(u32 addr, memory_location_t location = any, u32* sup_out = nullptr); // dealloc() with no return value and no exceptions void dealloc_verbose_nothrow(u32 addr, memory_location_t location = any) noexcept; @@ -94,46 +93,41 @@ namespace vm // Object that handles memory allocations inside specific constant bounds ("location") class block_t final { - std::map m_map; // addr -> size mapping of mapped locations - std::mutex m_mutex; + std::map m_map; // Mapped memory: addr -> size + std::unordered_map m_sup; // Supplementary info for allocations - bool try_alloc(u32 addr, u32 size); + bool try_alloc(u32 addr, u32 size, u32 sup); public: - block_t(u32 addr, u32 size, u64 flags = 0) - : addr(addr) - , size(size) - , flags(flags) - , used(0) - { - } + block_t(u32 addr, u32 size, u64 flags = 0); ~block_t(); public: - const u32 addr; // start address - const u32 size; // total size - const u64 flags; // currently unused - - atomic_t used; // amount of memory used, may be increased manually to prevent some memory from allocating + const u32 addr; // Start address + const u32 size; // Total size + const u64 flags; // Currently unused // Search and map memory (don't pass alignment smaller than 4096) - u32 alloc(u32 size, u32 align = 4096); + u32 alloc(u32 size, u32 align = 4096, u32 sup = 0); // Try to map memory at fixed location - u32 falloc(u32 addr, u32 size); + u32 falloc(u32 addr, u32 size, u32 sup = 0); - // Unmap memory at specified location previously returned by alloc() - bool dealloc(u32 addr); + // Unmap memory at specified location previously returned by alloc(), return size + u32 dealloc(u32 addr, u32* sup_out = nullptr); + + // Get allocated memory count + u32 used(); }; - // create new memory block with specified parameters and return it + // Create new memory block with specified parameters and return it std::shared_ptr map(u32 addr, u32 size, u64 flags = 0); - // delete existing memory block with specified start address - std::shared_ptr unmap(u32 addr); + // Delete existing memory block with specified start address, return it + std::shared_ptr unmap(u32 addr, bool must_be_empty = false); - // get memory block associated with optionally specified memory location or optionally specified address + // Get memory block associated with optionally specified memory location or optionally specified address std::shared_ptr get(memory_location_t location, u32 addr = 0); // Get PS3/PSV virtual memory address from the provided pointer (nullptr always converted to 0) diff --git a/rpcs3/Gui/KernelExplorer.cpp b/rpcs3/Gui/KernelExplorer.cpp index df743ed1f4..48dc5f64e3 100644 --- a/rpcs3/Gui/KernelExplorer.cpp +++ b/rpcs3/Gui/KernelExplorer.cpp @@ -57,7 +57,7 @@ KernelExplorer::KernelExplorer(wxWindow* parent) void KernelExplorer::Update() { m_tree->DeleteAllItems(); - const u32 total_memory_usage = vm::get(vm::user_space)->used.load(); + const u32 total_memory_usage = vm::get(vm::user_space)->used(); const auto& root = m_tree->AddRoot(fmt::format("Process, ID = 0x00000001, Total Memory Usage = 0x%x (%0.2f MB)", total_memory_usage, (float)total_memory_usage / (1024 * 1024))); @@ -198,22 +198,22 @@ void KernelExplorer::Update() } // Memory Containers - if (const u32 count = idm::get_count()) + if (const u32 count = idm::get_count()) { const auto& node = m_tree->AppendItem(root, fmt::format("Memory Containers (%zu)", count)); - idm::select([&](u32 id, lv2_memory_container_t&) + idm::select([&](u32 id, lv2_memory_container&) { m_tree->AppendItem(node, fmt::format("Memory Container: ID = 0x%08x", id)); }); } // Memory Objects - if (const u32 count = idm::get_count()) + if (const u32 count = idm::get_count()) { const auto& node = m_tree->AppendItem(root, fmt::format("Memory Objects (%zu)", count)); - idm::select([&](u32 id, lv2_memory_t&) + idm::select([&](u32 id, lv2_memory&) { m_tree->AppendItem(node, fmt::format("Memory Object: ID = 0x%08x", id)); }); From 59433bfcd529675acc1b906df5de8a217203c2cb Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 16 Jul 2016 20:58:42 +0300 Subject: [PATCH 5/6] Implemented thread_ctrl::interrupt --- Utilities/Thread.cpp | 171 +++++++++++++++++++++++++++++++++++++------ Utilities/Thread.h | 69 +++++++++++++++++ 2 files changed, 219 insertions(+), 21 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 77f876ea0f..e372d1e924 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1609,6 +1609,8 @@ static void prepare_throw_access_violation(x64_context* context, const char* cau RIP(context) = (u64)std::addressof(throw_access_violation); } +static void _handle_interrupt(x64_context* ctx); + #ifdef _WIN32 static LONG exception_handler(PEXCEPTION_POINTERS pExp) @@ -1698,6 +1700,11 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) { x64_context* context = (ucontext_t*)uct; + if (sig == SIGUSR1) + { + return _handle_interrupt(context); + } + #ifdef __APPLE__ const bool is_writing = context->uc_mcontext->__es.__err & 0x2; #else @@ -1735,7 +1742,15 @@ const bool s_exception_handler_set = []() -> bool if (::sigaction(SIGSEGV, &sa, NULL) == -1) { - std::printf("sigaction() failed (0x%x).", errno); + std::printf("sigaction(SIGSEGV) failed (0x%x).", errno); + std::abort(); + } + + sa.sa_sigaction = signal_handler; + + if (::sigaction(SIGUSR1, &sa, NULL) == -1) + { + std::printf("sigaction(SIGUSR1) failed (0x%x).", errno); std::abort(); } @@ -1767,13 +1782,23 @@ struct thread_ctrl::internal { std::mutex mutex; std::condition_variable cond; - std::condition_variable join; // Allows simultaneous joining + std::condition_variable jcv; // Allows simultaneous joining + std::condition_variable icv; task_stack atexit; - std::exception_ptr exception; // Caught exception + std::exception_ptr exception; // Stored exception std::chrono::high_resolution_clock::time_point time_limit; + +#ifdef _WIN32 + DWORD thread_id = 0; + x64_context _context{}; +#endif + + x64_context* thread_ctx{}; + + atomic_t interrupt{}; // Interrupt function }; thread_local thread_ctrl::internal* g_tls_internal = nullptr; @@ -1804,7 +1829,6 @@ void thread_ctrl::start(const std::shared_ptr& ctrl, task_stack tas } catch (...) { - ctrl->initialize_once(); ctrl->m_data->exception = std::current_exception(); } @@ -1814,15 +1838,11 @@ void thread_ctrl::start(const std::shared_ptr& ctrl, task_stack tas void thread_ctrl::wait_start(u64 timeout) { - initialize_once(); - m_data->time_limit = std::chrono::high_resolution_clock::now() + std::chrono::microseconds(timeout); } bool thread_ctrl::wait_wait(u64 timeout) { - initialize_once(); - std::unique_lock lock(m_data->mutex, std::adopt_lock); if (timeout && m_data->cond.wait_until(lock, m_data->time_limit) == std::cv_status::timeout) @@ -1846,11 +1866,12 @@ void thread_ctrl::test() void thread_ctrl::initialize() { - initialize_once(); // TODO (temporarily) - // Initialize TLS variable g_tls_this_thread = this; g_tls_internal = this->m_data; +#ifdef _WIN32 + m_data->thread_id = GetCurrentThreadId(); +#endif g_tls_log_prefix = [] { @@ -1892,6 +1913,10 @@ void thread_ctrl::initialize() void thread_ctrl::finalize() noexcept { + // Disable and discard possible interrupts + interrupt_disable(); + test_interrupt(); + // TODO vm::reservation_free(); @@ -1909,7 +1934,6 @@ void thread_ctrl::finalize() noexcept void thread_ctrl::push_atexit(task_stack task) { - initialize_once(); m_data->atexit.push(std::move(task)); } @@ -1922,6 +1946,8 @@ thread_ctrl::thread_ctrl(std::string&& name) #undef new new (&m_thread) std::thread; #pragma pop_macro("new") + + initialize_once(); } thread_ctrl::~thread_ctrl() @@ -1967,24 +1993,20 @@ void thread_ctrl::join() // Notify others if necessary if (UNLIKELY(m_joining.exchange(0x80000000) != 1)) { - initialize_once(); - // Serialize for reliable notification m_data->mutex.lock(); m_data->mutex.unlock(); - m_data->join.notify_all(); + m_data->jcv.notify_all(); } } else { // Hard way - initialize_once(); - std::unique_lock lock(m_data->mutex); - m_data->join.wait(lock, WRAP_EXPR(m_joining >= 0x80000000)); + m_data->jcv.wait(lock, WRAP_EXPR(m_joining >= 0x80000000)); } - if (UNLIKELY(m_data && m_data->exception)) + if (UNLIKELY(m_data && m_data->exception && !std::uncaught_exception())) { std::rethrow_exception(m_data->exception); } @@ -1992,7 +2014,6 @@ void thread_ctrl::join() void thread_ctrl::lock() { - initialize_once(); m_data->mutex.lock(); } @@ -2008,8 +2029,6 @@ void thread_ctrl::lock_notify() return; } - initialize_once(); - // Serialize for reliable notification, condition is assumed to be changed externally m_data->mutex.lock(); m_data->mutex.unlock(); @@ -2026,6 +2045,116 @@ void thread_ctrl::set_exception(std::exception_ptr e) m_data->exception = e; } +static void _handle_interrupt(x64_context* ctx) +{ + g_tls_internal->thread_ctx = ctx; + thread_ctrl::handle_interrupt(); +} + +void thread_ctrl::handle_interrupt() +{ + const auto _this = g_tls_this_thread; + const auto ctx = g_tls_internal->thread_ctx; + + if (_this->m_guard & 0x80000000) + { + // Discard interrupt if interrupts are disabled + if (g_tls_internal->interrupt.exchange(nullptr)) + { + _this->lock(); + _this->unlock(); + g_tls_internal->icv.notify_one(); + } + } + else if (_this->m_guard == 0) + { + // Set interrupt immediately if no guard set + if (const auto handler = g_tls_internal->interrupt.exchange(nullptr)) + { + _this->lock(); + _this->unlock(); + g_tls_internal->icv.notify_one(); + + // Install function call + *--(u64*&)(RSP(ctx)) = RIP(ctx); + RIP(ctx) = (u64)handler; + } + } + else + { + // Set delayed interrupt otherwise + _this->m_guard |= 0x40000000; + } + +#ifdef _WIN32 + RtlRestoreContext(ctx, nullptr); +#endif +} + +void thread_ctrl::interrupt(void(*handler)()) +{ + VERIFY(this != g_tls_this_thread); // TODO: self-interrupt + VERIFY(m_data->interrupt.compare_and_swap_test(nullptr, handler)); // TODO: multiple interrupts + +#ifdef _WIN32 + const auto ctx = &m_data->_context; + m_data->thread_ctx = ctx; + + const HANDLE nt = OpenThread(THREAD_ALL_ACCESS, FALSE, m_data->thread_id); + VERIFY(nt); + VERIFY(SuspendThread(nt) != -1); + + ctx->ContextFlags = CONTEXT_FULL; + VERIFY(GetThreadContext(nt, ctx)); + + ctx->ContextFlags = CONTEXT_FULL; + const u64 _rip = RIP(ctx); + RIP(ctx) = (u64)std::addressof(thread_ctrl::handle_interrupt); + VERIFY(SetThreadContext(nt, ctx)); + + RIP(ctx) = _rip; + VERIFY(ResumeThread(nt) != -1); + CloseHandle(nt); +#else + pthread_kill(reinterpret_cast(m_thread).native_handle(), SIGUSR1); +#endif + + std::unique_lock lock(m_data->mutex, std::adopt_lock); + + while (m_data->interrupt) + { + m_data->icv.wait(lock); + } + + lock.release(); +} + +void thread_ctrl::test_interrupt() +{ + if (m_guard & 0x80000000) + { + if (m_data->interrupt.exchange(nullptr)) + { + lock(), unlock(), m_data->icv.notify_one(); + } + + return; + } + + if (m_guard == 0x40000000 && !std::uncaught_exception()) + { + m_guard = 0; + + // Execute delayed interrupt handler + if (const auto handler = m_data->interrupt.exchange(nullptr)) + { + lock(), unlock(), m_data->icv.notify_one(); + + return handler(); + } + } +} + void thread_ctrl::sleep(u64 useconds) { std::this_thread::sleep_for(std::chrono::microseconds(useconds)); diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 46782c8c98..4e560d6f14 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -94,6 +94,9 @@ private: // Thread join contention counter atomic_t m_joining{}; + // Thread interrupt guard counter + u32 m_guard = 0x80000000; + // Thread internals atomic_t m_data{}; @@ -187,6 +190,42 @@ public: // Set exception (internal data must be initialized, thread mutex must be locked) void set_exception(std::exception_ptr); + // Internal + static void handle_interrupt(); + + // Interrupt thread with specified handler call (thread mutex must be locked) + void interrupt(void(*handler)()); + + // Interrupt guard recursive enter + void guard_enter() + { + m_guard++; + } + + // Interrupt guard recursive leave + void guard_leave() + { + if (UNLIKELY(--m_guard & 0x40000000)) + { + test_interrupt(); + } + } + + // Allow interrupts + void interrupt_enable() + { + m_guard &= ~0x80000000; + } + + // Disable and discard any interrupt + void interrupt_disable() + { + m_guard |= 0x80000000; + } + + // Check interrupt if delayed by guard scope + void test_interrupt(); + // Current thread sleeps for specified amount of microseconds. // Wrapper for std::this_thread::sleep, doesn't require valid thread_ctrl. [[deprecated]] static void sleep(u64 useconds); @@ -352,6 +391,36 @@ public: } }; +// Interrupt guard scope +class thread_guard final +{ + thread_ctrl* m_thread; + +public: + thread_guard(const thread_guard&) = delete; + + thread_guard(thread_ctrl* thread) + : m_thread(thread) + { + m_thread->guard_enter(); + } + + thread_guard(named_thread& thread) + : thread_guard(thread.operator->()) + { + } + + thread_guard() + : thread_guard(thread_ctrl::get_current()) + { + } + + ~thread_guard() noexcept(false) + { + m_thread->guard_leave(); + } +}; + // Wrapper for named thread, joins automatically in the destructor, can only be used in function scope class scope_thread final { From 438e057dc8d5c4b99fdc4a91e98a1e03917db4e3 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 2 Jun 2016 18:16:01 +0300 Subject: [PATCH 6/6] Partial commit: sys_fs --- Utilities/File.cpp | 2 + Utilities/lockless.h | 43 +++ Utilities/types.h | 9 + rpcs3/Emu/Cell/Modules/cellFs.cpp | 446 ++++++++------------------ rpcs3/Emu/Cell/Modules/cellFs.h | 4 +- rpcs3/Emu/Cell/Modules/cellGifDec.cpp | 8 +- rpcs3/Emu/Cell/Modules/cellJpgDec.cpp | 8 +- rpcs3/Emu/Cell/Modules/cellPngDec.cpp | 6 +- rpcs3/Emu/Cell/lv2/sys_fs.cpp | 266 ++++++++++----- rpcs3/Emu/Cell/lv2/sys_fs.h | 220 ++++++------- rpcs3/Emu/Cell/lv2/sys_process.cpp | 4 +- rpcs3/Emu/System.cpp | 67 +++- rpcs3/Emu/System.h | 3 + rpcs3/Emu/VFS.cpp | 102 +++--- rpcs3/Emu/VFS.h | 15 +- rpcs3/Gui/GameViewer.cpp | 28 +- rpcs3/Gui/GameViewer.h | 1 - rpcs3/Gui/MainFrame.cpp | 2 +- rpcs3/Gui/SettingsDialog.cpp | 2 +- 19 files changed, 598 insertions(+), 638 deletions(-) diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 05a3f584f8..9a7d9370c6 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -80,6 +80,8 @@ static fs::error to_error(DWORD e) case ERROR_ALREADY_EXISTS: return fs::error::exist; case ERROR_FILE_EXISTS: return fs::error::exist; case ERROR_NEGATIVE_SEEK: return fs::error::inval; + case ERROR_DIRECTORY: return fs::error::inval; + case ERROR_INVALID_NAME: return fs::error::inval; default: throw fmt::exception("Unknown Win32 error: %u.", e); } } diff --git a/Utilities/lockless.h b/Utilities/lockless.h index 863fe1d647..c6890722b2 100644 --- a/Utilities/lockless.h +++ b/Utilities/lockless.h @@ -103,3 +103,46 @@ public: }); } }; + +//! Simple lock-free map. Based on lf_array<>. All elements are accessible, implicitly initialized. +template, std::size_t Size = 256> +class lf_hashmap +{ + struct pair_t + { + // Default-constructed key means "no key" + atomic_t key{}; + T value{}; + }; + + // + lf_array m_data{}; + + // Value for default-constructed key + T m_default_key_data{}; + +public: + constexpr lf_hashmap() = default; + + // Access element (added implicitly) + T& operator [](const K& key) + { + if (UNLIKELY(key == K{})) + { + return m_default_key_data; + } + + // Calculate hash and array position + for (std::size_t pos = Hash{}(key) % Size;; pos += Size) + { + // Access the array + auto& pair = m_data[pos]; + + // Check the key value (optimistic) + if (LIKELY(pair.key == key) || pair.key.compare_and_swap_test(K{}, key)) + { + return pair.value; + } + } + } +}; diff --git a/Utilities/types.h b/Utilities/types.h index ad61bce0e2..8483e1b698 100644 --- a/Utilities/types.h +++ b/Utilities/types.h @@ -423,6 +423,15 @@ struct pointer_hash } }; +template +struct value_hash +{ + std::size_t operator()(T value) const + { + return static_cast(value) >> Shift; + } +}; + // Contains value of any POD type with fixed size and alignment. TT<> is the type converter applied. // For example, `simple_t` may be used to remove endianness. template class TT, std::size_t S, std::size_t A = S> diff --git a/rpcs3/Emu/Cell/Modules/cellFs.cpp b/rpcs3/Emu/Cell/Modules/cellFs.cpp index c0ca6a1ed8..56ca4a3524 100644 --- a/rpcs3/Emu/Cell/Modules/cellFs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFs.cpp @@ -58,8 +58,13 @@ s32 cellFsReaddir(u32 fd, vm::ptr dir, vm::ptr nread) { cellFs.trace("cellFsReaddir(fd=0x%x, dir=*0x%x, nread=*0x%x)", fd, dir, nread); + if (!dir || !nread) + { + return CELL_EFAULT; + } + // call the syscall - return dir && nread ? sys_fs_readdir(fd, dir, nread) : CELL_FS_EFAULT; + return sys_fs_readdir(fd, dir, nread); } s32 cellFsClosedir(u32 fd) @@ -132,8 +137,13 @@ s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr pos) { cellFs.trace("cellFsLseek(fd=0x%x, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos); + if (!pos) + { + return CELL_EFAULT; + } + // call the syscall - return pos ? sys_fs_lseek(fd, offset, whence, pos) : CELL_FS_EFAULT; + return sys_fs_lseek(fd, offset, whence, pos); } s32 cellFsFsync(u32 fd) @@ -147,8 +157,13 @@ s32 cellFsFGetBlockSize(u32 fd, vm::ptr sector_size, vm::ptr block_siz { cellFs.trace("cellFsFGetBlockSize(fd=0x%x, sector_size=*0x%x, block_size=*0x%x)", fd, sector_size, block_size); + if (!sector_size || !block_size) + { + return CELL_EFAULT; + } + // call the syscall - return sector_size && block_size ? sys_fs_fget_block_size(fd, sector_size, block_size, vm::var{}, vm::var{}) : CELL_FS_EFAULT; + return sys_fs_fget_block_size(fd, sector_size, block_size, vm::var{}, vm::var{}); } s32 cellFsGetBlockSize(vm::cptr path, vm::ptr sector_size, vm::ptr block_size) @@ -205,11 +220,11 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr entries, u32 { cellFs.warning("cellFsGetDirectoryEntries(fd=%d, entries=*0x%x, entries_size=0x%x, data_count=*0x%x)", fd, entries, entries_size, data_count); - const auto directory = idm::get(fd); + const auto directory = idm::get(fd); if (!directory) { - return CELL_FS_EBADF; + return CELL_EBADF; } u32 count = 0; @@ -246,474 +261,278 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr entries, u32 return CELL_OK; } -s32 cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr buf, u64 buffer_size, vm::ptr nread) +ppu_error_code cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr buf, u64 buffer_size, vm::ptr nread) { cellFs.trace("cellFsReadWithOffset(fd=%d, offset=0x%llx, buf=*0x%x, buffer_size=0x%llx, nread=*0x%x)", fd, offset, buf, buffer_size, nread); - // TODO: use single sys_fs_fcntl syscall - - const auto file = idm::get(fd); - - if (!file || file->flags & CELL_FS_O_WRONLY) + if (fd - 3 > 252) { - return CELL_FS_EBADF; + if (nread) *nread = 0; + return CELL_EBADF; } - std::lock_guard lock(file->mutex); + vm::var arg; - const auto old_pos = file->file.pos(); file->file.seek(offset); + arg->_vtable = vm::cast(0xfa8a0000); // Intentionally wrong (provide correct vtable if necessary) + + arg->op = 0x8000000a; + arg->fd = fd; + arg->buf = buf; + arg->offset = offset; + arg->size = buffer_size; - const auto read = file->file.read(buf.get_ptr(), buffer_size); + // Call the syscall + const s32 rc = sys_fs_fcntl(fd, 0x8000000a, arg, arg.size()); - file->file.seek(old_pos); + // Write size read + if (nread) *nread = rc && rc != CELL_EFSSPECIFIC ? 0 : arg->out_size.value(); - if (nread) - { - *nread = read; - } - - return CELL_OK; + return NOT_AN_ERROR(rc ? rc : arg->out_code.value()); } -s32 cellFsWriteWithOffset(u32 fd, u64 offset, vm::cptr buf, u64 data_size, vm::ptr nwrite) +ppu_error_code cellFsWriteWithOffset(u32 fd, u64 offset, vm::cptr buf, u64 data_size, vm::ptr nwrite) { cellFs.trace("cellFsWriteWithOffset(fd=%d, offset=0x%llx, buf=*0x%x, data_size=0x%llx, nwrite=*0x%x)", fd, offset, buf, data_size, nwrite); - // TODO: use single sys_fs_fcntl syscall - - const auto file = idm::get(fd); - - if (!file || !(file->flags & CELL_FS_O_ACCMODE)) + if (!buf) { - return CELL_FS_EBADF; + if (nwrite) *nwrite = 0; + return CELL_EFAULT; } - std::lock_guard lock(file->mutex); - - const auto old_pos = file->file.pos(); file->file.seek(offset); - - const auto written = file->file.write(buf.get_ptr(), data_size); - - file->file.seek(old_pos); - - if (nwrite) + if (fd - 3 > 252) { - *nwrite = written; + if (nwrite) *nwrite = 0; + return CELL_EBADF; } - return CELL_OK; + vm::var arg; + + arg->_vtable = vm::cast(0xfa8b0000); // Intentionally wrong (provide correct vtable if necessary) + + arg->op = 0x8000000b; + arg->fd = fd; + arg->buf = vm::const_ptr_cast(buf); + arg->offset = offset; + arg->size = data_size; + + // Call the syscall + const s32 rc = sys_fs_fcntl(fd, 0x8000000b, arg, arg.size()); + + // Write size written + if (nwrite) *nwrite = rc && rc != CELL_EFSSPECIFIC ? 0 : arg->out_size.value(); + + return NOT_AN_ERROR(rc ? rc : arg->out_code.value()); } s32 cellFsStReadInit(u32 fd, vm::cptr ringbuf) { - cellFs.warning("cellFsStReadInit(fd=%d, ringbuf=*0x%x)", fd, ringbuf); + cellFs.todo("cellFsStReadInit(fd=%d, ringbuf=*0x%x)", fd, ringbuf); if (ringbuf->copy & ~CELL_FS_ST_COPYLESS) { - return CELL_FS_EINVAL; + return CELL_EINVAL; } if (ringbuf->block_size & 0xfff) // check if a multiple of sector size { - return CELL_FS_EINVAL; + return CELL_EINVAL; } if (ringbuf->ringbuf_size % ringbuf->block_size) // check if a multiple of block_size { - return CELL_FS_EINVAL; + return CELL_EINVAL; } - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } if (file->flags & CELL_FS_O_WRONLY) { - return CELL_FS_EPERM; + return CELL_EPERM; } - std::lock_guard lock(file->mutex); - - if (!file->st_status.compare_and_swap_test(SSS_NOT_INITIALIZED, SSS_INITIALIZED)) - { - return CELL_FS_EBUSY; - } - - file->st_ringbuf_size = ringbuf->ringbuf_size; - file->st_block_size = ringbuf->ringbuf_size; - file->st_trans_rate = ringbuf->transfer_rate; - file->st_copyless = ringbuf->copy == CELL_FS_ST_COPYLESS; - - const u64 alloc_size = align(file->st_ringbuf_size, file->st_ringbuf_size < 1024 * 1024 ? 64 * 1024 : 1024 * 1024); - - file->st_buffer = vm::alloc(static_cast(alloc_size), vm::main); - file->st_read_size = 0; - file->st_total_read = 0; - file->st_copied = 0; + // TODO return CELL_OK; } s32 cellFsStReadFinish(u32 fd) { - cellFs.warning("cellFsStReadFinish(fd=%d)", fd); + cellFs.todo("cellFsStReadFinish(fd=%d)", fd); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; // ??? + return CELL_EBADF; // ??? } - std::lock_guard lock(file->mutex); - - if (!file->st_status.compare_and_swap_test(SSS_INITIALIZED, SSS_NOT_INITIALIZED)) - { - return CELL_FS_ENXIO; - } - - vm::dealloc(file->st_buffer, vm::main); + // TODO return CELL_OK; } s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr ringbuf) { - cellFs.warning("cellFsStReadGetRingBuf(fd=%d, ringbuf=*0x%x)", fd, ringbuf); + cellFs.todo("cellFsStReadGetRingBuf(fd=%d, ringbuf=*0x%x)", fd, ringbuf); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - if (file->st_status == SSS_NOT_INITIALIZED) - { - return CELL_FS_ENXIO; - } - - ringbuf->ringbuf_size = file->st_ringbuf_size; - ringbuf->block_size = file->st_block_size; - ringbuf->transfer_rate = file->st_trans_rate; - ringbuf->copy = file->st_copyless ? CELL_FS_ST_COPYLESS : CELL_FS_ST_COPY; + // TODO return CELL_OK; } s32 cellFsStReadGetStatus(u32 fd, vm::ptr status) { - cellFs.warning("cellFsStReadGetRingBuf(fd=%d, status=*0x%x)", fd, status); + cellFs.todo("cellFsStReadGetRingBuf(fd=%d, status=*0x%x)", fd, status); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - switch (file->st_status.load()) - { - case SSS_INITIALIZED: - case SSS_STOPPED: - { - *status = CELL_FS_ST_INITIALIZED | CELL_FS_ST_STOP; - break; - } - case SSS_STARTED: - { - *status = CELL_FS_ST_INITIALIZED | CELL_FS_ST_PROGRESS; - break; - } - default: - { - *status = CELL_FS_ST_NOT_INITIALIZED | CELL_FS_ST_STOP; - break; - } - } + // TODO return CELL_OK; } s32 cellFsStReadGetRegid(u32 fd, vm::ptr regid) { - cellFs.warning("cellFsStReadGetRingBuf(fd=%d, regid=*0x%x)", fd, regid); + cellFs.todo("cellFsStReadGetRingBuf(fd=%d, regid=*0x%x)", fd, regid); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - if (file->st_status == SSS_NOT_INITIALIZED) - { - return CELL_FS_ENXIO; - } - - *regid = file->st_total_read - file->st_copied; + // TODO return CELL_OK; } s32 cellFsStReadStart(u32 fd, u64 offset, u64 size) { - cellFs.warning("cellFsStReadStart(fd=%d, offset=0x%llx, size=0x%llx)", fd, offset, size); + cellFs.todo("cellFsStReadStart(fd=%d, offset=0x%llx, size=0x%llx)", fd, offset, size); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - switch (auto status = file->st_status.compare_and_swap(SSS_INITIALIZED, SSS_STARTED)) - { - case SSS_NOT_INITIALIZED: - { - return CELL_FS_ENXIO; - } - - case SSS_STARTED: - { - return CELL_FS_EBUSY; - } - } - - offset = std::min(file->file.size(), offset); - size = std::min(file->file.size() - offset, size); - - file->st_read_size = size; - - file->st_thread = thread_ctrl::spawn("FS ST Thread", [=]() - { - std::unique_lock lock(file->mutex); - - while (file->st_status == SSS_STARTED && !Emu.IsStopped()) - { - // check free space in buffer and available data in stream - if (file->st_total_read - file->st_copied <= file->st_ringbuf_size - file->st_block_size && file->st_total_read < file->st_read_size) - { - // get buffer position - const u32 position = vm::cast(file->st_buffer + file->st_total_read % file->st_ringbuf_size, HERE); - - // read data - auto old = file->file.pos(); - file->file.seek(offset + file->st_total_read); - auto res = file->file.read(vm::base(position), file->st_block_size); - file->file.seek(old); - - // notify - file->st_total_read += res; - file->cv.notify_one(); - } - - // check callback condition if set - if (file->st_callback.load().func) - { - const u64 available = file->st_total_read - file->st_copied; - - if (available >= file->st_callback.load().size) - { - const auto func = file->st_callback.exchange({}).func; - - Emu.GetCallbackManager().Async([=](PPUThread& ppu) - { - func(ppu, fd, available); - }); - } - } - - file->cv.wait_for(lock, 1ms); - } - - file->st_status.compare_and_swap(SSS_STOPPED, SSS_INITIALIZED); - file->st_read_size = 0; - file->st_total_read = 0; - file->st_copied = 0; - file->st_callback.store({}); - }); + // TODO return CELL_OK; } s32 cellFsStReadStop(u32 fd) { - cellFs.warning("cellFsStReadStop(fd=%d)", fd); + cellFs.todo("cellFsStReadStop(fd=%d)", fd); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - switch (auto status = file->st_status.compare_and_swap(SSS_STARTED, SSS_STOPPED)) - { - case SSS_NOT_INITIALIZED: - { - return CELL_FS_ENXIO; - } - - case SSS_INITIALIZED: - case SSS_STOPPED: - { - return CELL_OK; - } - } - - file->cv.notify_all(); - file->st_thread->join(); + // TODO return CELL_OK; } s32 cellFsStRead(u32 fd, vm::ptr buf, u64 size, vm::ptr rsize) { - cellFs.warning("cellFsStRead(fd=%d, buf=*0x%x, size=0x%llx, rsize=*0x%x)", fd, buf, size, rsize); + cellFs.todo("cellFsStRead(fd=%d, buf=*0x%x, size=0x%llx, rsize=*0x%x)", fd, buf, size, rsize); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - if (file->st_status == SSS_NOT_INITIALIZED || file->st_copyless) - { - return CELL_FS_ENXIO; - } + // TODO - const u64 copied = file->st_copied; - const u32 position = vm::cast(file->st_buffer + copied % file->st_ringbuf_size, HERE); - const u64 total_read = file->st_total_read; - const u64 copy_size = (*rsize = std::min(size, total_read - copied)); // write rsize - - // copy data - const u64 first_size = std::min(copy_size, file->st_ringbuf_size - (position - file->st_buffer)); - std::memcpy(buf.get_ptr(), vm::base(position), first_size); - std::memcpy((buf + first_size).get_ptr(), vm::base(file->st_buffer), copy_size - first_size); - - // notify - file->st_copied += copy_size; - file->cv.notify_one(); - - // check end of stream - return total_read < file->st_read_size ? CELL_OK : CELL_FS_ERANGE; + return CELL_OK; } s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr addr, vm::ptr size) { - cellFs.warning("cellFsStReadGetCurrentAddr(fd=%d, addr=*0x%x, size=*0x%x)", fd, addr, size); + cellFs.todo("cellFsStReadGetCurrentAddr(fd=%d, addr=*0x%x, size=*0x%x)", fd, addr, size); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - if (file->st_status == SSS_NOT_INITIALIZED || !file->st_copyless) - { - return CELL_FS_ENXIO; - } + // TODO - const u64 copied = file->st_copied; - const u32 position = vm::cast(file->st_buffer + copied % file->st_ringbuf_size, HERE); - const u64 total_read = file->st_total_read; - - if ((*size = std::min(file->st_ringbuf_size - (position - file->st_buffer), total_read - copied))) - { - *addr = position; - } - else - { - *addr = 0; - } - - // check end of stream - return total_read < file->st_read_size ? CELL_OK : CELL_FS_ERANGE; + return CELL_OK; } s32 cellFsStReadPutCurrentAddr(u32 fd, vm::ptr addr, u64 size) { - cellFs.warning("cellFsStReadPutCurrentAddr(fd=%d, addr=*0x%x, size=0x%llx)", fd, addr, size); + cellFs.todo("cellFsStReadPutCurrentAddr(fd=%d, addr=*0x%x, size=0x%llx)", fd, addr, size); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - if (file->st_status == SSS_NOT_INITIALIZED || !file->st_copyless) - { - return CELL_FS_ENXIO; - } + // TODO - const u64 copied = file->st_copied; - const u64 total_read = file->st_total_read; - - // notify - file->st_copied += size; - file->cv.notify_one(); - - // check end of stream - return total_read < file->st_read_size ? CELL_OK : CELL_FS_ERANGE; + return CELL_OK; } s32 cellFsStReadWait(u32 fd, u64 size) { - cellFs.warning("cellFsStReadWait(fd=%d, size=0x%llx)", fd, size); + cellFs.todo("cellFsStReadWait(fd=%d, size=0x%llx)", fd, size); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - if (file->st_status == SSS_NOT_INITIALIZED) - { - return CELL_FS_ENXIO; - } - - std::unique_lock lock(file->mutex); - - // wait for size availability or stream end - while (file->st_total_read - file->st_copied < size && file->st_total_read < file->st_read_size) - { - CHECK_EMU_STATUS; - - file->cv.wait_for(lock, 1ms); - } + // TODO return CELL_OK; } -s32 cellFsStReadWaitCallback(u32 fd, u64 size, fs_st_cb_t func) +s32 cellFsStReadWaitCallback(u32 fd, u64 size, vm::ptr func) { - cellFs.warning("cellFsStReadWaitCallback(fd=%d, size=0x%llx, func=*0x%x)", fd, size, func); + cellFs.todo("cellFsStReadWaitCallback(fd=%d, size=0x%llx, func=*0x%x)", fd, size, func); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - if (file->st_status == SSS_NOT_INITIALIZED) - { - return CELL_FS_ENXIO; - } - - if (!file->st_callback.compare_and_swap_test({}, { size, func })) - { - return CELL_FS_EIO; - } + // TODO return CELL_OK; } @@ -831,7 +650,7 @@ s32 cellFsSdataOpen(vm::cptr path, s32 flags, vm::ptr fd, vm::cptr[2]>({ 0x180, 0x10 }), 8); @@ -866,6 +685,12 @@ s32 cellFsSdataOpenByFd(u32 mself_fd, s32 flags, vm::ptr sdata_fd, u64 offs using fs_aio_cb_t = vm::ptr xaio, s32 error, s32 xid, u64 size)>; +// temporarily +struct lv2_fs_mount_point +{ + std::mutex mutex; +}; + void fsAio(vm::ptr aio, bool write, s32 xid, fs_aio_cb_t func) { cellFs.notice("FS AIO Request(%d): fd=%d, offset=0x%llx, buf=*0x%x, size=0x%llx, user_data=0x%llx", xid, aio->fd, aio->offset, aio->buf, aio->size, aio->user_data); @@ -873,21 +698,21 @@ void fsAio(vm::ptr aio, bool write, s32 xid, fs_aio_cb_t func) s32 error = CELL_OK; u64 result = 0; - const auto file = idm::get(aio->fd); + const auto file = idm::get(aio->fd); if (!file || (!write && file->flags & CELL_FS_O_WRONLY) || (write && !(file->flags & CELL_FS_O_ACCMODE))) { - error = CELL_FS_EBADF; + error = CELL_EBADF; } else { - std::lock_guard lock(file->mutex); + std::lock_guard lock(file->mp->mutex); const auto old_pos = file->file.pos(); file->file.seek(aio->offset); result = write - ? file->file.write(aio->buf.get_ptr(), aio->size) - : file->file.read(aio->buf.get_ptr(), aio->size); + ? file->op_write(aio->buf, aio->size) + : file->op_read(aio->buf, aio->size); file->file.seek(old_pos); } @@ -949,11 +774,11 @@ s32 cellFsAioWrite(vm::ptr aio, vm::ptr id, fs_aio_cb_t func) s32 cellFsAioCancel(s32 id) { - cellFs.warning("cellFsAioCancel(id=%d) -> CELL_FS_EINVAL", id); + cellFs.warning("cellFsAioCancel(id=%d) -> CELL_EINVAL", id); - // TODO: cancelled requests return CELL_FS_ECANCELED through their own callbacks + // TODO: cancelled requests return CELL_ECANCELED through their own callbacks - return CELL_FS_EINVAL; + return CELL_EINVAL; } s32 cellFsSetDefaultContainer(u32 id, u32 total_limit) @@ -967,11 +792,11 @@ s32 cellFsSetIoBufferFromDefaultContainer(u32 fd, u32 buffer_size, u32 page_type { cellFs.todo("cellFsSetIoBufferFromDefaultContainer(fd=%d, buffer_size=%d, page_type=%d)", fd, buffer_size, page_type); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } return CELL_OK; @@ -1020,6 +845,7 @@ s32 cellFsChangeFileSizeWithoutAllocation() s32 cellFsAllocateFileAreaWithoutZeroFill(vm::cptr path, u64 size) { cellFs.warning("cellFsAllocateFileAreaWithoutZeroFill(path=*0x%x, size=0x%llx)", path, size); + return sys_fs_truncate(path, size); } @@ -1099,7 +925,7 @@ DECLARE(ppu_module_manager::cellFs)("sys_fs", []() REG_FUNC(sys_fs, cellFsAllocateFileAreaByFdWithInitialData); REG_FUNC(sys_fs, cellFsTruncate2); REG_FUNC(sys_fs, cellFsChangeFileSizeWithoutAllocation); - REG_FUNC(sys_fs, cellFsAllocateFileAreaWithoutZeroFill); + REG_FUNC(sys_fs, cellFsAllocateFileAreaWithoutZeroFill, MFF_FORCED_HLE); REG_FUNC(sys_fs, cellFsChangeFileSizeByFdWithoutAllocation); REG_FUNC(sys_fs, cellFsSetDiscReadRetrySetting); REG_FUNC(sys_fs, cellFsRegisterConversionCallback); diff --git a/rpcs3/Emu/Cell/Modules/cellFs.h b/rpcs3/Emu/Cell/Modules/cellFs.h index b74d0df31b..5d22a8417b 100644 --- a/rpcs3/Emu/Cell/Modules/cellFs.h +++ b/rpcs3/Emu/Cell/Modules/cellFs.h @@ -1,6 +1,6 @@ #pragma once -namespace vm { using namespace ps3; } +#include "Emu/Cell/lv2/sys_fs.h" struct CellFsDirectoryEntry { @@ -42,7 +42,7 @@ struct CellFsAio { be_t fd; be_t offset; - vm::bptr buf; + vm::bptrb buf; be_t size; be_t user_data; }; diff --git a/rpcs3/Emu/Cell/Modules/cellGifDec.cpp b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp index f5420ed299..c52c816762 100644 --- a/rpcs3/Emu/Cell/Modules/cellGifDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp @@ -61,7 +61,7 @@ s32 cellGifDecOpen(PMainHandle mainHandle, PPSubHandle subHandle, PSrc src, POpe if (!file_s) return CELL_GIFDEC_ERROR_OPEN_FILE; current_subHandle.fileSize = file_s.size(); - current_subHandle.fd = idm::make(std::move(file_s), 0, 0); + current_subHandle.fd = idm::make(src->fileName.get_ptr(), std::move(file_s), 0, 0); break; } } @@ -97,7 +97,7 @@ s32 cellGifDecReadHeader(PMainHandle mainHandle, PSubHandle subHandle, PInfo inf case CELL_GIFDEC_FILE: { - auto file = idm::get(fd); + auto file = idm::get(fd); file->file.seek(0); file->file.read(buffer, sizeof(buffer)); break; @@ -181,7 +181,7 @@ s32 cellGifDecDecodeData(PMainHandle mainHandle, PSubHandle subHandle, vm::ptr(fd); + auto file = idm::get(fd); file->file.seek(0); file->file.read(gif.get(), fileSize); break; @@ -283,7 +283,7 @@ s32 cellGifDecClose(PMainHandle mainHandle, PSubHandle subHandle) { cellGifDec.warning("cellGifDecClose(mainHandle=*0x%x, subHandle=*0x%x)", mainHandle, subHandle); - idm::remove(subHandle->fd); + idm::remove(subHandle->fd); vm::dealloc(subHandle.addr()); diff --git a/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp index 2cfc9f5efc..6a436ae247 100644 --- a/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp @@ -51,7 +51,7 @@ s32 cellJpgDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptr(std::move(file_s), 0, 0); + current_subHandle.fd = idm::make(src->fileName.get_ptr(), std::move(file_s), 0, 0); break; } } @@ -78,7 +78,7 @@ s32 cellJpgDecClose(u32 mainHandle, u32 subHandle) return CELL_JPGDEC_ERROR_FATAL; } - idm::remove(subHandle_data->fd); + idm::remove(subHandle_data->fd); idm::remove(subHandle); return CELL_OK; @@ -110,7 +110,7 @@ s32 cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr case CELL_JPGDEC_FILE: { - auto file = idm::get(fd); + auto file = idm::get(fd); file->file.seek(0); file->file.read(buffer.get(), fileSize); break; @@ -189,7 +189,7 @@ s32 cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, vm::cp case CELL_JPGDEC_FILE: { - auto file = idm::get(fd); + auto file = idm::get(fd); file->file.seek(0); file->file.read(jpg.get(), fileSize); break; diff --git a/rpcs3/Emu/Cell/Modules/cellPngDec.cpp b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp index 2a40efa27d..79991b56f9 100644 --- a/rpcs3/Emu/Cell/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp @@ -65,7 +65,7 @@ void pngDecReadBuffer(png_structp png_ptr, png_bytep out, png_size_t length) if (buffer.file) { // Get the file - auto file = idm::get(buffer.fd); + auto file = idm::get(buffer.fd); // Read the data file->file.read(out, length); @@ -364,7 +364,7 @@ s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source, } // Get the file descriptor - buffer->fd = idm::make(std::move(file_stream), 0, 0); + buffer->fd = idm::make(stream->source.fileName.get_ptr(), std::move(file_stream), 0, 0); // Indicate that we need to read from a file stream buffer->file = true; @@ -447,7 +447,7 @@ s32 pngDecClose(PPUThread& ppu, PHandle handle, PStream stream) // Remove the file descriptor, if a file descriptor was used for decoding if (stream->buffer->file) { - idm::remove(stream->buffer->fd); + idm::remove(stream->buffer->fd); } // Deallocate the PNG buffer structure used to decode from memory, if we decoded from memory diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 3dbab511eb..22969c1da0 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -1,24 +1,58 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/IdManager.h" - -#include "Emu/Cell/ErrorCodes.h" #include "sys_fs.h" +#include + +#include "Emu/VFS.h" #include "Utilities/StrUtil.h" -#include + +namespace vm { using namespace ps3; } logs::channel sys_fs("sys_fs", logs::level::notice); -s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr arg3, u32 arg4, vm::ptr arg5, u32 arg6) +struct lv2_fs_mount_point +{ + std::mutex mutex; +}; + +lv2_fs_mount_point g_mp_sys_dev_hdd0; +lv2_fs_mount_point g_mp_sys_dev_hdd1; +lv2_fs_mount_point g_mp_sys_dev_usb; +lv2_fs_mount_point g_mp_sys_dev_bdvd; +lv2_fs_mount_point g_mp_sys_app_home; +lv2_fs_mount_point g_mp_sys_host_root; + +lv2_fs_mount_point* lv2_fs_object::get_mp(const char* filename) +{ + // TODO + return &g_mp_sys_dev_hdd0; +} + +u64 lv2_file::op_read(vm::ps3::ptr buf, u64 size) +{ + // Copy data from intermediate buffer (avoid passing vm pointer to a native API) + std::unique_ptr local_buf(new u8[size]); + const u64 result = file.read(local_buf.get(), size); + std::memcpy(buf.get_ptr(), local_buf.get(), result); + return result; +} + +u64 lv2_file::op_write(vm::ps3::cptr buf, u64 size) +{ + // Copy data to intermediate buffer (avoid passing vm pointer to a native API) + std::unique_ptr local_buf(new u8[size]); + std::memcpy(local_buf.get(), buf.get_ptr(), size); + return file.write(local_buf.get(), size); +} + +ppu_error_code sys_fs_test(u32 arg1, u32 arg2, vm::ptr arg3, u32 arg4, vm::ptr arg5, u32 arg6) { sys_fs.todo("sys_fs_test(arg1=0x%x, arg2=0x%x, arg3=*0x%x, arg4=0x%x, arg5=*0x%x, arg6=0x%x) -> CELL_OK", arg1, arg2, arg3, arg4, arg5, arg6); return CELL_OK; } -s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::cptr arg, u64 size) +ppu_error_code sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::cptr arg, u64 size) { sys_fs.warning("sys_fs_open(path=*0x%x, flags=%#o, fd=*0x%x, mode=%#o, arg=*0x%x, size=0x%llx)", path, flags, fd, mode, arg, size); sys_fs.warning("*** path = '%s'", path.get_ptr()); @@ -26,14 +60,15 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c if (!path[0]) { sys_fs.error("sys_fs_open('%s') failed: path is invalid", path.get_ptr()); - return CELL_FS_EINVAL; + return CELL_EINVAL; } const std::string& local_path = vfs::get(path.get_ptr()); + if (local_path.empty()) { sys_fs.error("sys_fs_open('%s') failed: device not mounted", path.get_ptr()); - return CELL_FS_ENOTMOUNTED; + return CELL_ENOTMOUNTED; } // TODO: other checks for path @@ -41,7 +76,7 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c if (fs::is_dir(local_path)) { sys_fs.error("sys_fs_open('%s') failed: path is a directory", path.get_ptr()); - return CELL_FS_EISDIR; + return CELL_EISDIR; } bitset_t open_mode{}; @@ -103,18 +138,18 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c if (open_mode & fs::excl) { - return CELL_FS_EEXIST; // approximation + return CELL_EEXIST; // approximation } - return CELL_FS_ENOENT; + return CELL_ENOENT; } - const auto _file = idm::make_ptr(std::move(file), mode, flags); + const auto _file = idm::make_ptr(path.get_ptr(), std::move(file), mode, flags); if (!_file) { // out of file descriptors - return CELL_FS_EMFILE; + return CELL_EMFILE; } *fd = _file->id; @@ -122,7 +157,7 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c return CELL_OK; } -s32 sys_fs_read(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nread) +ppu_error_code sys_fs_read(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nread) { sys_fs.trace("sys_fs_read(fd=%d, buf=*0x%x, nbytes=0x%llx, nread=*0x%x)", fd, buf, nbytes, nread); @@ -131,80 +166,93 @@ s32 sys_fs_read(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nread) return CELL_EFAULT; } - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file || file->flags & CELL_FS_O_WRONLY) { - return CELL_FS_EBADF; + return CELL_EBADF; } - std::lock_guard lock(file->mutex); + std::lock_guard lock(file->mp->mutex); - std::unique_ptr local_buf(new u8[nbytes]); - std::memcpy(buf.get_ptr(), local_buf.get(), *nread = file->file.read(local_buf.get(), nbytes)); + *nread = file->op_read(buf, nbytes); return CELL_OK; } -s32 sys_fs_write(u32 fd, vm::cptr buf, u64 nbytes, vm::ptr nwrite) +ppu_error_code sys_fs_write(u32 fd, vm::cptr buf, u64 nbytes, vm::ptr nwrite) { sys_fs.trace("sys_fs_write(fd=%d, buf=*0x%x, nbytes=0x%llx, nwrite=*0x%x)", fd, buf, nbytes, nwrite); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file || !(file->flags & CELL_FS_O_ACCMODE)) { - return CELL_FS_EBADF; + return CELL_EBADF; } - // TODO: return CELL_FS_EBUSY if locked by stream + // TODO: return CELL_EBUSY if locked by stream - std::lock_guard lock(file->mutex); + std::lock_guard lock(file->mp->mutex); - std::unique_ptr local_buf(new u8[nbytes]); - std::memcpy(local_buf.get(), buf.get_ptr(), nbytes); - *nwrite = file->file.write(local_buf.get(), nbytes); + *nwrite = file->op_write(buf, nbytes); return CELL_OK; } -s32 sys_fs_close(u32 fd) +ppu_error_code sys_fs_close(u32 fd) { sys_fs.trace("sys_fs_close(fd=%d)", fd); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - // TODO: return CELL_FS_EBUSY if locked + // TODO: return CELL_EBUSY if locked - idm::remove(fd); + idm::remove(fd); return CELL_OK; } -s32 sys_fs_opendir(vm::cptr path, vm::ptr fd) +ppu_error_code sys_fs_opendir(vm::cptr path, vm::ptr fd) { sys_fs.warning("sys_fs_opendir(path=*0x%x, fd=*0x%x)", path, fd); sys_fs.warning("*** path = '%s'", path.get_ptr()); - fs::dir dir(vfs::get(path.get_ptr())); + const std::string& local_path = vfs::get(path.get_ptr()); + + if (local_path.empty()) + { + sys_fs.error("sys_fs_opendir('%s') failed: device not mounted", path.get_ptr()); + return CELL_ENOTMOUNTED; + } + + // TODO: other checks for path + + if (fs::is_file(local_path)) + { + sys_fs.error("sys_fs_opendir('%s') failed: path is a file", path.get_ptr()); + return CELL_ENOTDIR; + } + + fs::dir dir(local_path); if (!dir) { sys_fs.error("sys_fs_opendir('%s'): failed to open directory", path.get_ptr()); - return CELL_FS_ENOENT; + return CELL_ENOENT; } - const auto _dir = idm::make_ptr(std::move(dir)); + const auto _dir = idm::make_ptr(path.get_ptr(), std::move(dir)); if (!_dir) { // out of file descriptors - return CELL_FS_EMFILE; + return CELL_EMFILE; } *fd = _dir->id; @@ -212,15 +260,15 @@ s32 sys_fs_opendir(vm::cptr path, vm::ptr fd) return CELL_OK; } -s32 sys_fs_readdir(u32 fd, vm::ptr dir, vm::ptr nread) +ppu_error_code sys_fs_readdir(u32 fd, vm::ptr dir, vm::ptr nread) { sys_fs.warning("sys_fs_readdir(fd=%d, dir=*0x%x, nread=*0x%x)", fd, dir, nread); - const auto directory = idm::get(fd); + const auto directory = idm::get(fd); if (!directory) { - return CELL_FS_EBADF; + return CELL_EBADF; } fs::dir_entry info; @@ -240,23 +288,23 @@ s32 sys_fs_readdir(u32 fd, vm::ptr dir, vm::ptr nread) return CELL_OK; } -s32 sys_fs_closedir(u32 fd) +ppu_error_code sys_fs_closedir(u32 fd) { sys_fs.trace("sys_fs_closedir(fd=%d)", fd); - const auto directory = idm::get(fd); + const auto directory = idm::get(fd); if (!directory) { - return CELL_FS_EBADF; + return CELL_EBADF; } - idm::remove(fd); + idm::remove(fd); return CELL_OK; } -s32 sys_fs_stat(vm::cptr path, vm::ptr sb) +ppu_error_code sys_fs_stat(vm::cptr path, vm::ptr sb) { sys_fs.warning("sys_fs_stat(path=*0x%x, sb=*0x%x)", path, sb); sys_fs.warning("*** path = '%s'", path.get_ptr()); @@ -266,7 +314,7 @@ s32 sys_fs_stat(vm::cptr path, vm::ptr sb) if (local_path.empty()) { sys_fs.warning("sys_fs_stat('%s') failed: not mounted", path.get_ptr()); - return CELL_FS_ENOTMOUNTED; + return CELL_ENOTMOUNTED; } fs::stat_t info; @@ -274,7 +322,7 @@ s32 sys_fs_stat(vm::cptr path, vm::ptr sb) if (!fs::stat(local_path, info)) { sys_fs.error("sys_fs_stat('%s') failed: not found", path.get_ptr()); - return CELL_FS_ENOENT; + return CELL_ENOENT; } sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; @@ -289,18 +337,18 @@ s32 sys_fs_stat(vm::cptr path, vm::ptr sb) return CELL_OK; } -s32 sys_fs_fstat(u32 fd, vm::ptr sb) +ppu_error_code sys_fs_fstat(u32 fd, vm::ptr sb) { sys_fs.warning("sys_fs_fstat(fd=%d, sb=*0x%x)", fd, sb); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - std::lock_guard lock(file->mutex); + std::lock_guard lock(file->mp->mutex); const fs::stat_t& info = file->file.stat(); @@ -316,7 +364,7 @@ s32 sys_fs_fstat(u32 fd, vm::ptr sb) return CELL_OK; } -s32 sys_fs_mkdir(vm::cptr path, s32 mode) +ppu_error_code sys_fs_mkdir(vm::cptr path, s32 mode) { sys_fs.warning("sys_fs_mkdir(path=*0x%x, mode=%#o)", path, mode); sys_fs.warning("*** path = '%s'", path.get_ptr()); @@ -325,19 +373,19 @@ s32 sys_fs_mkdir(vm::cptr path, s32 mode) if (fs::is_dir(local_path)) { - return CELL_FS_EEXIST; + return CELL_EEXIST; } if (!fs::create_path(local_path)) { - return CELL_FS_EIO; // ??? + return CELL_EIO; // ??? } sys_fs.notice("sys_fs_mkdir(): directory '%s' created", path.get_ptr()); return CELL_OK; } -s32 sys_fs_rename(vm::cptr from, vm::cptr to) +ppu_error_code sys_fs_rename(vm::cptr from, vm::cptr to) { sys_fs.warning("sys_fs_rename(from=*0x%x, to=*0x%x)", from, to); sys_fs.warning("*** from = '%s'", from.get_ptr()); @@ -345,14 +393,14 @@ s32 sys_fs_rename(vm::cptr from, vm::cptr to) if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr()))) { - return CELL_FS_ENOENT; // ??? + return CELL_ENOENT; // ??? } sys_fs.notice("sys_fs_rename(): '%s' renamed to '%s'", from.get_ptr(), to.get_ptr()); return CELL_OK; } -s32 sys_fs_rmdir(vm::cptr path) +ppu_error_code sys_fs_rmdir(vm::cptr path) { sys_fs.warning("sys_fs_rmdir(path=*0x%x)", path); sys_fs.warning("*** path = '%s'", path.get_ptr()); @@ -361,18 +409,18 @@ s32 sys_fs_rmdir(vm::cptr path) { switch (auto error = fs::g_tls_error) { - case fs::error::noent: return CELL_FS_ENOENT; + case fs::error::noent: return CELL_ENOENT; default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error); } - return CELL_FS_EIO; // ??? + return CELL_EIO; // ??? } sys_fs.notice("sys_fs_rmdir(): directory '%s' removed", path.get_ptr()); return CELL_OK; } -s32 sys_fs_unlink(vm::cptr path) +ppu_error_code sys_fs_unlink(vm::cptr path) { sys_fs.warning("sys_fs_unlink(path=*0x%x)", path); sys_fs.warning("*** path = '%s'", path.get_ptr()); @@ -381,57 +429,107 @@ s32 sys_fs_unlink(vm::cptr path) { switch (auto error = fs::g_tls_error) { - case fs::error::noent: return CELL_FS_ENOENT; + case fs::error::noent: return CELL_ENOENT; default: sys_fs.error("sys_fs_unlink(): unknown error %d", error); } - return CELL_FS_EIO; // ??? + return CELL_EIO; // ??? } sys_fs.notice("sys_fs_unlink(): file '%s' deleted", path.get_ptr()); return CELL_OK; } -s32 sys_fs_fcntl(u32 fd, s32 flags, u32 addr, u32 arg4, u32 arg5, u32 arg6) +ppu_error_code sys_fs_fcntl(u32 fd, u32 op, vm::ptr _arg, u32 _size) { - sys_fs.todo("sys_fs_fcntl(fd=0x%x, flags=0x%x, addr=*0x%x, arg4=0x%x, arg5=0x%x, arg6=0x%x) -> CELL_OK", fd, flags, addr, arg4, arg5, arg6); + sys_fs.trace("sys_fs_fcntl(fd=%d, op=0x%x, arg=*0x%x, size=0x%x)", fd, op, _arg, _size); + + switch (op) + { + case 0x8000000A: // Read with offset + case 0x8000000B: // Write with offset + { + const auto arg = vm::static_ptr_cast(_arg); + + if (_size < arg.size()) + { + return CELL_EINVAL; + } + + const auto file = idm::get(fd); + + if (!file) + { + return CELL_EBADF; + } + + if (op == 0x8000000A && file->flags & CELL_FS_O_WRONLY) + { + return CELL_EBADF; + } + + if (op == 0x8000000B && !(file->flags & CELL_FS_O_ACCMODE)) + { + return CELL_EBADF; + } + + std::lock_guard lock(file->mp->mutex); + + const u64 old_pos = file->file.pos(); + const u64 new_pos = file->file.seek(arg->offset); + + arg->out_size = op == 0x8000000A + ? file->op_read(arg->buf, arg->size) + : file->op_write(arg->buf, arg->size); + + VERIFY(old_pos == file->file.seek(old_pos)); + + arg->out_code = CELL_OK; + + break; + } + default: + { + sys_fs.todo("sys_fs_fcntl(): Unknown operation 0x%08x (fd=%d, arg=*0x%x, size=0x%x)", op, fd, _arg, _size); + } + } return CELL_OK; } -s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr pos) +ppu_error_code sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr pos) { sys_fs.trace("sys_fs_lseek(fd=%d, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos); if (whence >= 3) { sys_fs.error("sys_fs_lseek(): invalid seek whence (%d)", whence); - return CELL_FS_EINVAL; + return CELL_EINVAL; } - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } - std::lock_guard lock(file->mutex); + std::lock_guard lock(file->mp->mutex); *pos = file->file.seek(offset, static_cast(whence)); return CELL_OK; } -s32 sys_fs_fget_block_size(u32 fd, vm::ptr sector_size, vm::ptr block_size, vm::ptr arg4, vm::ptr arg5) +ppu_error_code sys_fs_fget_block_size(u32 fd, vm::ptr sector_size, vm::ptr block_size, vm::ptr arg4, vm::ptr arg5) { sys_fs.todo("sys_fs_fget_block_size(fd=%d, sector_size=*0x%x, block_size=*0x%x, arg4=*0x%x, arg5=*0x%x)", fd, sector_size, block_size, arg4, arg5); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file) { - return CELL_FS_EBADF; + return CELL_EBADF; } *sector_size = 4096; // ? @@ -440,7 +538,7 @@ s32 sys_fs_fget_block_size(u32 fd, vm::ptr sector_size, vm::ptr block_ return CELL_OK; } -s32 sys_fs_get_block_size(vm::cptr path, vm::ptr sector_size, vm::ptr block_size, vm::ptr arg4) +ppu_error_code sys_fs_get_block_size(vm::cptr path, vm::ptr sector_size, vm::ptr block_size, vm::ptr arg4) { sys_fs.todo("sys_fs_get_block_size(path=*0x%x, sector_size=*0x%x, block_size=*0x%x, arg4=*0x%x, arg5=*0x%x)", path, sector_size, block_size, arg4); sys_fs.todo("*** path = '%s'", path.get_ptr()); @@ -451,7 +549,7 @@ s32 sys_fs_get_block_size(vm::cptr path, vm::ptr sector_size, vm::ptr return CELL_OK; } -s32 sys_fs_truncate(vm::cptr path, u64 size) +ppu_error_code sys_fs_truncate(vm::cptr path, u64 size) { sys_fs.warning("sys_fs_truncate(path=*0x%x, size=0x%llx)", path, size); sys_fs.warning("*** path = '%s'", path.get_ptr()); @@ -460,28 +558,28 @@ s32 sys_fs_truncate(vm::cptr path, u64 size) { switch (auto error = fs::g_tls_error) { - case fs::error::noent: return CELL_FS_ENOENT; + case fs::error::noent: return CELL_ENOENT; default: sys_fs.error("sys_fs_truncate(): unknown error %d", error); } - return CELL_FS_EIO; // ??? + return CELL_EIO; // ??? } return CELL_OK; } -s32 sys_fs_ftruncate(u32 fd, u64 size) +ppu_error_code sys_fs_ftruncate(u32 fd, u64 size) { sys_fs.warning("sys_fs_ftruncate(fd=%d, size=0x%llx)", fd, size); - const auto file = idm::get(fd); + const auto file = idm::get(fd); if (!file || !(file->flags & CELL_FS_O_ACCMODE)) { - return CELL_FS_EBADF; + return CELL_EBADF; } - std::lock_guard lock(file->mutex); + std::lock_guard lock(file->mp->mutex); if (!file->file.trunc(size)) { @@ -491,13 +589,13 @@ s32 sys_fs_ftruncate(u32 fd, u64 size) default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error); } - return CELL_FS_EIO; // ??? + return CELL_EIO; // ??? } return CELL_OK; } -s32 sys_fs_chmod(vm::cptr path, s32 mode) +ppu_error_code sys_fs_chmod(vm::cptr path, s32 mode) { sys_fs.todo("sys_fs_chmod(path=*0x%x, mode=%#o) -> CELL_OK", path, mode); sys_fs.todo("*** path = '%s'", path.get_ptr()); diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index d1f56d59a3..e3fea5aa6b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -1,67 +1,8 @@ #pragma once -#include "Utilities/Thread.h" - -#include -#include - -namespace vm { using namespace ps3; } - -// Error Codes -enum : s32 -{ - CELL_FS_EDOM = CELL_EDOM, - CELL_FS_EFAULT = CELL_EFAULT, - CELL_FS_EFBIG = CELL_EFBIG, - CELL_FS_EFPOS = CELL_EFPOS, - CELL_FS_EMLINK = CELL_EMLINK, - CELL_FS_ENFILE = CELL_ENFILE, - CELL_FS_ENOENT = CELL_ENOENT, - CELL_FS_ENOSPC = CELL_ENOSPC, - CELL_FS_ENOTTY = CELL_ENOTTY, - CELL_FS_EPIPE = CELL_EPIPE, - CELL_FS_ERANGE = CELL_ERANGE, - CELL_FS_EROFS = CELL_EROFS, - CELL_FS_ESPIPE = CELL_ESPIPE, - CELL_FS_E2BIG = CELL_E2BIG, - CELL_FS_EACCES = CELL_EACCES, - CELL_FS_EAGAIN = CELL_EAGAIN, - CELL_FS_EBADF = CELL_EBADF, - CELL_FS_EBUSY = CELL_EBUSY, - //CELL_FS_ECHILD = CELL_ECHILD, - CELL_FS_EEXIST = CELL_EEXIST, - CELL_FS_EINTR = CELL_EINTR, - CELL_FS_EINVAL = CELL_EINVAL, - CELL_FS_EIO = CELL_EIO, - CELL_FS_EISDIR = CELL_EISDIR, - CELL_FS_EMFILE = CELL_EMFILE, - CELL_FS_ENODEV = CELL_ENODEV, - CELL_FS_ENOEXEC = CELL_ENOEXEC, - CELL_FS_ENOMEM = CELL_ENOMEM, - CELL_FS_ENOTDIR = CELL_ENOTDIR, - CELL_FS_ENXIO = CELL_ENXIO, - CELL_FS_EPERM = CELL_EPERM, - CELL_FS_ESRCH = CELL_ESRCH, - CELL_FS_EXDEV = CELL_EXDEV, - CELL_FS_EBADMSG = CELL_EBADMSG, - CELL_FS_ECANCELED = CELL_ECANCELED, - CELL_FS_EDEADLK = CELL_EDEADLK, - CELL_FS_EILSEQ = CELL_EILSEQ, - CELL_FS_EINPROGRESS = CELL_EINPROGRESS, - CELL_FS_EMSGSIZE = CELL_EMSGSIZE, - CELL_FS_ENAMETOOLONG = CELL_ENAMETOOLONG, - CELL_FS_ENOLCK = CELL_ENOLCK, - CELL_FS_ENOSYS = CELL_ENOSYS, - CELL_FS_ENOTEMPTY = CELL_ENOTEMPTY, - CELL_FS_ENOTSUP = CELL_ENOTSUP, - CELL_FS_ETIMEDOUT = CELL_ETIMEDOUT, - CELL_FS_EFSSPECIFIC = CELL_EFSSPECIFIC, - CELL_FS_EOVERFLOW = CELL_EOVERFLOW, - CELL_FS_ENOTMOUNTED = CELL_ENOTMOUNTED, - CELL_FS_ENOTMSELF = CELL_ENOTMSELF, - CELL_FS_ENOTSDATA = CELL_ENOTSDATA, - CELL_FS_EAUTHFATAL = CELL_EAUTHFATAL, -}; +#include "Emu/Memory/Memory.h" +#include "Emu/Cell/ErrorCodes.h" +#include "Emu/IdManager.h" // Open Flags enum : s32 @@ -92,7 +33,7 @@ enum : s32 CELL_FS_MAX_MP_LENGTH = 31, }; -enum CellFsMode : s32 +enum : s32 { CELL_FS_S_IFMT = 0170000, CELL_FS_S_IFDIR = 0040000, // directory @@ -151,98 +92,117 @@ struct CellFsUtimbuf CHECK_SIZE_ALIGN(CellFsUtimbuf, 16, 4); -// Stream Support Status (st_status) -enum : u32 -{ - SSS_NOT_INITIALIZED = 0, - SSS_INITIALIZED, - SSS_STARTED, - SSS_STOPPED, -}; +struct lv2_fs_mount_point; -using fs_st_cb_t = vm::ptr; - -struct alignas(16) fs_st_cb_rec_t +struct lv2_fs_object { - u64 size; - fs_st_cb_t func; - u32 pad; -}; - -struct lv2_fs_object_t -{ - using id_base = lv2_fs_object_t; + // ID Manager setups + using id_base = lv2_fs_object; static constexpr u32 id_min = 3; static constexpr u32 id_max = 255; const id_value<> id{}; + + // Mount Point + const std::add_pointer_t mp; + + lv2_fs_object(lv2_fs_mount_point* mp) + : mp(mp) + { + } + + static lv2_fs_mount_point* get_mp(const char* filename); }; -struct lv2_file_t : lv2_fs_object_t +struct lv2_file : lv2_fs_object { const fs::file file; const s32 mode; const s32 flags; - std::mutex mutex; - std::condition_variable cv; - - atomic_t st_status; - - u64 st_ringbuf_size; - u64 st_block_size; - u64 st_trans_rate; - bool st_copyless; - - std::shared_ptr st_thread; - - u32 st_buffer; - u64 st_read_size; - atomic_t st_total_read; - atomic_t st_copied; - - atomic_t st_callback; - - lv2_file_t(fs::file file, s32 mode, s32 flags) - : file(std::move(file)) + lv2_file(const char* filename, fs::file&& file, s32 mode, s32 flags) + : lv2_fs_object(lv2_fs_object::get_mp(filename)) + , file(std::move(file)) , mode(mode) , flags(flags) - , st_status(SSS_NOT_INITIALIZED) - , st_callback(fs_st_cb_rec_t{}) { } + + // File reading with intermediate buffer + u64 op_read(vm::ps3::ptr buf, u64 size); + + // File writing with intermediate buffer + u64 op_write(vm::ps3::cptr buf, u64 size); }; -struct lv2_dir_t : lv2_fs_object_t +struct lv2_dir : lv2_fs_object { const fs::dir dir; - lv2_dir_t(fs::dir dir) - : dir(std::move(dir)) + lv2_dir(const char* filename, fs::dir&& dir) + : lv2_fs_object(lv2_fs_object::get_mp(filename)) + , dir(std::move(dir)) { } }; +// sys_fs_fcntl arg base class (left empty for PODness) +struct lv2_file_op +{ +}; + +namespace vtable +{ + struct lv2_file_op + { + // Speculation + vm::bptrb(vm::ptrb)> get_data; + vm::bptrb)> get_size; + vm::bptrb)> _dtor1; + vm::bptrb)> _dtor2; + }; +} + +// sys_fs_fcntl: read with offset, write with offset +struct lv2_file_op_rw : lv2_file_op +{ + vm::bptrb _vtable; + + be_t op; + be_t _x8; // ??? + be_t _xc; // ??? + + be_t fd; // File descriptor (3..255) + vm::bptrb buf; // Buffer for data + be_t offset; // File offset + be_t size; // Access size + + be_t out_code; // Op result + be_t out_size; // Size processed +}; + +CHECK_SIZE(lv2_file_op_rw, 0x38); + // SysCalls -s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr arg3, u32 arg4, vm::ptr arg5, u32 arg6); -s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::cptr arg, u64 size); -s32 sys_fs_read(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nread); -s32 sys_fs_write(u32 fd, vm::cptr buf, u64 nbytes, vm::ptr nwrite); -s32 sys_fs_close(u32 fd); -s32 sys_fs_opendir(vm::cptr path, vm::ptr fd); -s32 sys_fs_readdir(u32 fd, vm::ptr dir, vm::ptr nread); -s32 sys_fs_closedir(u32 fd); -s32 sys_fs_stat(vm::cptr path, vm::ptr sb); -s32 sys_fs_fstat(u32 fd, vm::ptr sb); -s32 sys_fs_mkdir(vm::cptr path, s32 mode); -s32 sys_fs_rename(vm::cptr from, vm::cptr to); -s32 sys_fs_rmdir(vm::cptr path); -s32 sys_fs_unlink(vm::cptr path); -s32 sys_fs_fcntl(u32 fd, s32 flags, u32 addr, u32 arg4, u32 arg5, u32 arg6); -s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr pos); -s32 sys_fs_fget_block_size(u32 fd, vm::ptr sector_size, vm::ptr block_size, vm::ptr arg4, vm::ptr arg5); -s32 sys_fs_get_block_size(vm::cptr path, vm::ptr sector_size, vm::ptr block_size, vm::ptr arg4); -s32 sys_fs_truncate(vm::cptr path, u64 size); -s32 sys_fs_ftruncate(u32 fd, u64 size); -s32 sys_fs_chmod(vm::cptr path, s32 mode); +ppu_error_code sys_fs_test(u32 arg1, u32 arg2, vm::ps3::ptr arg3, u32 arg4, vm::ps3::ptr arg5, u32 arg6); +ppu_error_code sys_fs_open(vm::ps3::cptr path, s32 flags, vm::ps3::ptr fd, s32 mode, vm::ps3::cptr arg, u64 size); +ppu_error_code sys_fs_read(u32 fd, vm::ps3::ptr buf, u64 nbytes, vm::ps3::ptr nread); +ppu_error_code sys_fs_write(u32 fd, vm::ps3::cptr buf, u64 nbytes, vm::ps3::ptr nwrite); +ppu_error_code sys_fs_close(u32 fd); +ppu_error_code sys_fs_opendir(vm::ps3::cptr path, vm::ps3::ptr fd); +ppu_error_code sys_fs_readdir(u32 fd, vm::ps3::ptr dir, vm::ps3::ptr nread); +ppu_error_code sys_fs_closedir(u32 fd); +ppu_error_code sys_fs_stat(vm::ps3::cptr path, vm::ps3::ptr sb); +ppu_error_code sys_fs_fstat(u32 fd, vm::ps3::ptr sb); +ppu_error_code sys_fs_mkdir(vm::ps3::cptr path, s32 mode); +ppu_error_code sys_fs_rename(vm::ps3::cptr from, vm::ps3::cptr to); +ppu_error_code sys_fs_rmdir(vm::ps3::cptr path); +ppu_error_code sys_fs_unlink(vm::ps3::cptr path); +ppu_error_code sys_fs_fcntl(u32 fd, u32 op, vm::ps3::ptr arg, u32 size); +ppu_error_code sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ps3::ptr pos); +ppu_error_code sys_fs_fget_block_size(u32 fd, vm::ps3::ptr sector_size, vm::ps3::ptr block_size, vm::ps3::ptr arg4, vm::ps3::ptr arg5); +ppu_error_code sys_fs_get_block_size(vm::ps3::cptr path, vm::ps3::ptr sector_size, vm::ps3::ptr block_size, vm::ps3::ptr arg4); +ppu_error_code sys_fs_truncate(vm::ps3::cptr path, u64 size); +ppu_error_code sys_fs_ftruncate(u32 fd, u64 size); +ppu_error_code sys_fs_chmod(vm::ps3::cptr path, s32 mode); diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 09ac2af5f9..284286b299 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -89,7 +89,7 @@ s32 sys_process_get_number_of_object(u32 object, vm::ptr nump) case SYS_LWMUTEX_OBJECT: *nump = idm::get_count(); break; case SYS_TIMER_OBJECT: *nump = idm::get_count(); break; case SYS_SEMAPHORE_OBJECT: *nump = idm::get_count(); break; - case SYS_FS_FD_OBJECT: *nump = idm::get_count(); break; + case SYS_FS_FD_OBJECT: *nump = idm::get_count(); break; case SYS_LWCOND_OBJECT: *nump = idm::get_count(); break; case SYS_EVENT_FLAG_OBJECT: *nump = idm::get_count(); break; @@ -136,7 +136,7 @@ s32 sys_process_get_id(u32 object, vm::ptr buffer, u32 size, vm::ptr s case SYS_LWMUTEX_OBJECT: idm_get_set(objects); break; case SYS_TIMER_OBJECT: idm_get_set(objects); break; case SYS_SEMAPHORE_OBJECT: idm_get_set(objects); break; - case SYS_FS_FD_OBJECT: idm_get_set(objects); break; + case SYS_FS_FD_OBJECT: idm_get_set(objects); break; case SYS_LWCOND_OBJECT: idm_get_set(objects); break; case SYS_EVENT_FLAG_OBJECT: idm_get_set(objects); break; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 8627aad7d9..1bb8b69fc5 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -28,10 +28,17 @@ cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot", true); cfg::bool_entry g_cfg_autoexit(cfg::root.misc, "Exit RPCS3 when process finishes"); -std::string g_cfg_defaults; +cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_executable_dir() +cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/"); +cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/"); +cfg::string_entry g_cfg_vfs_dev_flash(cfg::root.vfs, "/dev_flash/", "$(EmulatorDir)dev_flash/"); +cfg::string_entry g_cfg_vfs_dev_usb000(cfg::root.vfs, "/dev_usb000/", "$(EmulatorDir)dev_usb000/"); +cfg::string_entry g_cfg_vfs_dev_bdvd(cfg::root.vfs, "/dev_bdvd/"); // Not mounted +cfg::string_entry g_cfg_vfs_app_home(cfg::root.vfs, "/app_home/"); // Not mounted -extern cfg::string_entry g_cfg_vfs_dev_bdvd; -extern cfg::string_entry g_cfg_vfs_app_home; +cfg::bool_entry g_cfg_vfs_allow_host_root(cfg::root.vfs, "Enable /host_root/", true); + +std::string g_cfg_defaults; extern atomic_t g_thread_count; @@ -124,6 +131,22 @@ bool Emulator::BootGame(const std::string& path, bool direct) return false; } +std::string Emulator::GetGameDir() +{ + const std::string& emu_dir_ = g_cfg_vfs_emulator_dir; + const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_; + + return fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir) + "game/"; +} + +std::string Emulator::GetLibDir() +{ + const std::string& emu_dir_ = g_cfg_vfs_emulator_dir; + const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_; + + return fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir) + "sys/external/"; +} + void Emulator::Load() { Stop(); @@ -208,33 +231,49 @@ void Emulator::Load() LOG_NOTICE(LOADER, "Title: %s", GetTitle()); LOG_NOTICE(LOADER, "Serial: %s", GetTitleID()); - LOG_NOTICE(LOADER, ""); - LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string()); + // Mount all devices + const std::string& emu_dir_ = g_cfg_vfs_emulator_dir; + const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_; + const std::string& bdvd_dir = g_cfg_vfs_dev_bdvd; + const std::string& home_dir = g_cfg_vfs_app_home; - // Mount /dev_bdvd/ - if (g_cfg_vfs_dev_bdvd.size() == 0 && fs::is_file(elf_dir + "/../../PS3_DISC.SFB")) + vfs::mount("dev_hdd0", fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir)); + vfs::mount("dev_hdd1", fmt::replace_all(g_cfg_vfs_dev_hdd1, "$(EmulatorDir)", emu_dir)); + vfs::mount("dev_flash", fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir)); + vfs::mount("dev_usb", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir)); + vfs::mount("dev_usb000", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir)); + vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir)); + + // Mount /dev_bdvd/ if necessary + if (bdvd_dir.empty() && fs::is_file(elf_dir + "/../../PS3_DISC.SFB")) { const auto dir_list = fmt::split(elf_dir, { "/", "\\" }); // Check latest two directories if (dir_list.size() >= 2 && dir_list.back() == "USRDIR" && *(dir_list.end() - 2) == "PS3_GAME") { - g_cfg_vfs_dev_bdvd = elf_dir.substr(0, elf_dir.length() - 15); + vfs::mount("dev_bdvd", elf_dir.substr(0, elf_dir.length() - 15)); } else { - g_cfg_vfs_dev_bdvd = elf_dir + "/../../"; + vfs::mount("dev_bdvd", elf_dir + "/../../"); } - } - // Mount /app_home/ - if (g_cfg_vfs_app_home.size() == 0) + LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd")); + } + else if (bdvd_dir.size()) { - g_cfg_vfs_app_home = elf_dir + '/'; + vfs::mount("dev_bdvd", fmt::replace_all(bdvd_dir, "$(EmulatorDir)", emu_dir)); } - vfs::dump(); + // Mount /host_root/ if necessary + if (g_cfg_vfs_allow_host_root) + { + vfs::mount("host_root", {}); + } + + LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string()); ppu_load_exec(ppu_exec); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 0d7d720b23..3923035d0b 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -172,6 +172,9 @@ public: bool BootGame(const std::string& path, bool direct = false); + static std::string GetGameDir(); + static std::string GetLibDir(); + void Load(); void Run(); bool Pause(); diff --git a/rpcs3/Emu/VFS.cpp b/rpcs3/Emu/VFS.cpp index 32e54511ed..4ec9670e70 100644 --- a/rpcs3/Emu/VFS.cpp +++ b/rpcs3/Emu/VFS.cpp @@ -1,79 +1,51 @@ #include "stdafx.h" -#include "Utilities/Config.h" -#include "Emu/System.h" - +#include "IdManager.h" #include "VFS.h" -#include "Utilities/StrUtil.h" +#include -cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_executable_dir() -cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/"); -cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/"); -cfg::string_entry g_cfg_vfs_dev_flash(cfg::root.vfs, "/dev_flash/", "$(EmulatorDir)dev_flash/"); -cfg::string_entry g_cfg_vfs_dev_usb000(cfg::root.vfs, "/dev_usb000/", "$(EmulatorDir)dev_usb000/"); -cfg::string_entry g_cfg_vfs_dev_bdvd(cfg::root.vfs, "/dev_bdvd/"); // Not mounted -cfg::string_entry g_cfg_vfs_app_home(cfg::root.vfs, "/app_home/"); // Not mounted - -cfg::bool_entry g_cfg_vfs_allow_host_root(cfg::root.vfs, "Enable /host_root/", true); - -void vfs::dump() +struct vfs_manager { - LOG_NOTICE(LOADER, "Mount info:"); - LOG_NOTICE(LOADER, "/dev_hdd0/ -> %s", g_cfg_vfs_dev_hdd0.get()); - LOG_NOTICE(LOADER, "/dev_hdd1/ -> %s", g_cfg_vfs_dev_hdd1.get()); - LOG_NOTICE(LOADER, "/dev_flash/ -> %s", g_cfg_vfs_dev_flash.get()); - LOG_NOTICE(LOADER, "/dev_usb/ -> %s", g_cfg_vfs_dev_usb000.get()); - LOG_NOTICE(LOADER, "/dev_usb000/ -> %s", g_cfg_vfs_dev_usb000.get()); - if (g_cfg_vfs_dev_bdvd.size()) LOG_NOTICE(LOADER, "/dev_bdvd/ -> %s", g_cfg_vfs_dev_bdvd.get()); - if (g_cfg_vfs_app_home.size()) LOG_NOTICE(LOADER, "/app_home/ -> %s", g_cfg_vfs_app_home.get()); - if (g_cfg_vfs_allow_host_root) LOG_NOTICE(LOADER, "/host_root/ -> ."); - LOG_NOTICE(LOADER, ""); + shared_mutex mutex; + + // Device name -> Real path + std::unordered_map mounted; +}; + +const std::regex s_regex_ps3("^/+(.*?)(?:$|/)(.*)", std::regex::optimize); +const std::regex s_regex_psv("^(.*?):(.*)", std::regex::optimize); + +bool vfs::mount(const std::string& dev_name, const std::string& path) +{ + const auto table = fxm::get_always(); + + writer_lock lock(table->mutex); + + return table->mounted.emplace(dev_name, path).second; } -std::string vfs::get(const std::string& vpath) +std::string vfs::get(const std::string& vpath, vfs::type _type) { - const cfg::string_entry* vdir = nullptr; - std::size_t f_pos = vpath.find_first_not_of('/'); - std::size_t start = 0; + std::smatch match; - // Compare vpath with device name - auto detect = [&](const auto& vdev) -> bool + if (!std::regex_match(vpath, match, _type == type::ps3 ? s_regex_ps3 : s_regex_psv)) { - const std::size_t size = ::size32(vdev) - 1; // Char array size - - if (f_pos && f_pos != -1 && vpath.compare(f_pos - 1, size, vdev, size) == 0) - { - start = size; - return true; - } - - return false; - }; - - if (g_cfg_vfs_allow_host_root && detect("/host_root/")) - return vpath.substr(start); // Accessing host FS directly - else if (detect("/dev_hdd0/")) - vdir = &g_cfg_vfs_dev_hdd0; - else if (detect("/dev_hdd1/")) - vdir = &g_cfg_vfs_dev_hdd1; - else if (detect("/dev_flash/")) - vdir = &g_cfg_vfs_dev_flash; - else if (detect("/dev_usb000/")) - vdir = &g_cfg_vfs_dev_usb000; - else if (detect("/dev_usb/")) - vdir = &g_cfg_vfs_dev_usb000; - else if (detect("/dev_bdvd/")) - vdir = &g_cfg_vfs_dev_bdvd; - else if (detect("/app_home/")) - vdir = &g_cfg_vfs_app_home; - - // Return empty path if not mounted - if (!vdir || !start) - { - LOG_WARNING(GENERAL, "vfs::get() failed for %s", vpath); + LOG_WARNING(GENERAL, "vfs::get(): invalid input: %s", vpath); return{}; } - // Replace $(EmulatorDir), concatenate - return fmt::replace_all(*vdir, "$(EmulatorDir)", g_cfg_vfs_emulator_dir.size() == 0 ? fs::get_executable_dir() : g_cfg_vfs_emulator_dir) + vpath.substr(start); + const auto table = fxm::get_always(); + + reader_lock lock(table->mutex); + + const auto found = table->mounted.find(match.str(1)); + + if (found == table->mounted.end()) + { + LOG_WARNING(GENERAL, "vfs::get(): device not found: %s", vpath); + return{}; + } + + // Concatenate + return found->second + match.str(2); } diff --git a/rpcs3/Emu/VFS.h b/rpcs3/Emu/VFS.h index 55c6ceeb57..9397b01395 100644 --- a/rpcs3/Emu/VFS.h +++ b/rpcs3/Emu/VFS.h @@ -2,9 +2,16 @@ namespace vfs { - // Print mounted directories - void dump(); + // VFS type + enum class type + { + ps3, + psv, + }; - // Convert PS3/PSV path to fs-compatible path - std::string get(const std::string& vpath); + // Mount VFS device + bool mount(const std::string& dev_name, const std::string& path); + + // Convert VFS path to fs path + std::string get(const std::string& vpath, type _type = type::ps3); } diff --git a/rpcs3/Gui/GameViewer.cpp b/rpcs3/Gui/GameViewer.cpp index 46d2e6a2fa..495f403aa1 100644 --- a/rpcs3/Gui/GameViewer.cpp +++ b/rpcs3/Gui/GameViewer.cpp @@ -42,7 +42,6 @@ GameViewer::GameViewer(wxWindow* parent) : wxListView(parent) m_sortColumn = 1; m_sortAscending = true; - m_path = "/dev_hdd0/game/"; m_popup = new wxMenu(); Bind(wxEVT_LIST_ITEM_ACTIVATED, &GameViewer::DClick, this); @@ -80,7 +79,7 @@ void GameViewer::LoadGames() { m_games.clear(); - for (const auto& entry : fs::dir(vfs::get(m_path))) + for (const auto& entry : fs::dir(Emu.GetGameDir())) { if (entry.is_directory) { @@ -93,10 +92,13 @@ void GameViewer::LoadPSF() { m_game_data.clear(); + const std::string& game_path = Emu.GetGameDir(); + for (u32 i = 0; i < m_games.size(); ++i) { - const std::string sfb = vfs::get(m_path) + m_games[i] + "/PS3_DISC.SFB"; - const std::string sfo = vfs::get(m_path) + m_games[i] + (fs::is_file(sfb) ? "/PS3_GAME/PARAM.SFO" : "/PARAM.SFO"); + const std::string& dir = game_path + m_games[i]; + const std::string& sfb = dir + "/PS3_DISC.SFB"; + const std::string& sfo = dir + (fs::is_file(sfb) ? "/PS3_GAME/PARAM.SFO" : "/PARAM.SFO"); const fs::file sfo_file(sfo); if (!sfo_file) @@ -125,27 +127,27 @@ void GameViewer::LoadPSF() if (game.category == "HG") { game.category = "HDD Game"; - game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG"; + game.icon_path = dir + "/ICON0.PNG"; } else if (game.category == "DG") { game.category = "Disc Game"; - game.icon_path = vfs::get(m_path) + m_games[i] + "/PS3_GAME/ICON0.PNG"; + game.icon_path = dir + "/PS3_GAME/ICON0.PNG"; } else if (game.category == "HM") { game.category = "Home"; - game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG"; + game.icon_path = dir + "/ICON0.PNG"; } else if (game.category == "AV") { game.category = "Audio/Video"; - game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG"; + game.icon_path = dir + "/ICON0.PNG"; } else if (game.category == "GD") { game.category = "Game Data"; - game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG"; + game.icon_path = dir + "/ICON0.PNG"; } m_game_data.push_back(game); @@ -183,13 +185,13 @@ void GameViewer::DClick(wxListEvent& event) long i = GetFirstSelected(); if (i < 0) return; - const std::string& path = m_path + m_game_data[i].root; + const std::string& path = Emu.GetGameDir() + m_game_data[i].root; Emu.Stop(); - if (!Emu.BootGame(vfs::get(path))) + if (!Emu.BootGame(path)) { - LOG_ERROR(LOADER, "Failed to boot %s", path); + LOG_ERROR(LOADER, "Failed to boot /dev_hdd0/game/%s", m_game_data[i].root); } } @@ -238,7 +240,7 @@ void GameViewer::RemoveGame(wxCommandEvent& event) if (wxMessageBox("Permanently delete game files?", "Confirm Delete", wxYES_NO | wxNO_DEFAULT) == wxYES) { - fs::remove_all(vfs::get(m_path) + this->GetItemText(i, 6).ToStdString()); + fs::remove_all(Emu.GetGameDir() + this->GetItemText(i, 6).ToStdString()); } Refresh(); diff --git a/rpcs3/Gui/GameViewer.h b/rpcs3/Gui/GameViewer.h index 9b286244bd..b6b9b4df4c 100644 --- a/rpcs3/Gui/GameViewer.h +++ b/rpcs3/Gui/GameViewer.h @@ -63,7 +63,6 @@ class GameViewer : public wxListView { int m_sortColumn; bool m_sortAscending; - std::string m_path; std::vector m_games; std::vector m_game_data; ColumnsArr m_columns; diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index 3b826a7c9d..6dc1406cf7 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -253,7 +253,7 @@ void MainFrame::InstallPkg(wxCommandEvent& WXUNUSED(event)) pkg_f.seek(0); // Get full path - const auto& local_path = vfs::get("/dev_hdd0/game/") + std::string(std::begin(title_id), std::end(title_id)); + const auto& local_path = Emu.GetGameDir() + std::string(std::begin(title_id), std::end(title_id)); if (!fs::create_dir(local_path)) { diff --git a/rpcs3/Gui/SettingsDialog.cpp b/rpcs3/Gui/SettingsDialog.cpp index 2feb06bcc6..c2e74f3843 100644 --- a/rpcs3/Gui/SettingsDialog.cpp +++ b/rpcs3/Gui/SettingsDialog.cpp @@ -332,7 +332,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent) chbox_list_core_lle->Check(chbox_list_core_lle->Append(unk)); } - const std::string& lle_dir = vfs::get("/dev_flash/sys/external/"); // TODO + const std::string& lle_dir = Emu.GetLibDir(); // TODO std::unordered_set set(data.begin(), data.end()); std::vector lle_module_list_unselected;