diff --git a/rpcs3/Emu/Memory/Memory.cpp b/rpcs3/Emu/Memory/Memory.cpp index 6fcea3252f..4188cb3170 100644 --- a/rpcs3/Emu/Memory/Memory.cpp +++ b/rpcs3/Emu/Memory/Memory.cpp @@ -509,3 +509,199 @@ template<> __forceinline u64 MemoryBase::ReverseData<1>(u64 val) { return val; } template<> __forceinline u64 MemoryBase::ReverseData<2>(u64 val) { return Reverse16(val); } template<> __forceinline u64 MemoryBase::ReverseData<4>(u64 val) { return Reverse32(val); } template<> __forceinline u64 MemoryBase::ReverseData<8>(u64 val) { return Reverse64(val); } + +VirtualMemoryBlock::VirtualMemoryBlock() : MemoryBlock() +{ +} + +bool VirtualMemoryBlock::IsInMyRange(const u64 addr) +{ + return addr >= GetStartAddr() && addr < GetStartAddr() + GetSize(); +} + +bool VirtualMemoryBlock::IsInMyRange(const u64 addr, const u32 size) +{ + return IsInMyRange(addr) && IsInMyRange(addr + size - 1); +} + +bool VirtualMemoryBlock::IsMyAddress(const u64 addr) +{ + for(u32 i=0; i= m_mapped_memory[i].addr && addr < m_mapped_memory[i].addr + m_mapped_memory[i].size) + { + return true; + } + } + + return false; +} + +u64 VirtualMemoryBlock::Map(u64 realaddr, u32 size, u64 addr) +{ + if(addr) + { + if(!IsInMyRange(addr, size) && (IsMyAddress(addr) || IsMyAddress(addr + size - 1))) + return 0; + + m_mapped_memory.Move(new VirtualMemInfo(addr, realaddr, size)); + return addr; + } + else + { + for(u64 addr = GetStartAddr(); addr <= GetEndAddr() - size;) + { + bool is_good_addr = true; + + for(u32 i=0; i= m_mapped_memory[i].addr && addr < m_mapped_memory[i].addr + m_mapped_memory[i].size) || + (m_mapped_memory[i].addr >= addr && m_mapped_memory[i].addr < addr + size)) + { + is_good_addr = false; + addr = m_mapped_memory[i].addr + m_mapped_memory[i].size; + break; + } + } + + if(!is_good_addr) continue; + + m_mapped_memory.Move(new VirtualMemInfo(addr, realaddr, size)); + + return addr; + } + + return 0; + } +} + +bool VirtualMemoryBlock::UnmapRealAddress(u64 realaddr) +{ + for(u32 i=0; i= m_mapped_memory[i].addr && addr < m_mapped_memory[i].addr + m_mapped_memory[i].size) + { + return m_mapped_memory[i].realAddress + (addr - m_mapped_memory[i].addr); + } + } + + return 0; +} + +u64 VirtualMemoryBlock::getMappedAddress(u64 realAddress) +{ + for(u32 i=0; i= m_mapped_memory[i].realAddress && realAddress < m_mapped_memory[i].realAddress + m_mapped_memory[i].size) + { + return m_mapped_memory[i].addr + (realAddress - m_mapped_memory[i].realAddress); + } + } + + return 0; +} + +void VirtualMemoryBlock::Delete() +{ + m_mapped_memory.Clear(); + + MemoryBlock::Delete(); +} \ No newline at end of file diff --git a/rpcs3/Emu/Memory/Memory.h b/rpcs3/Emu/Memory/Memory.h index 9f53cad357..28cb752c7d 100644 --- a/rpcs3/Emu/Memory/Memory.h +++ b/rpcs3/Emu/Memory/Memory.h @@ -24,6 +24,7 @@ public: DynamicMemoryBlock StackMem; MemoryBlock SpuRawMem; MemoryBlock SpuThrMem; + VirtualMemoryBlock RSXIOMem; struct { diff --git a/rpcs3/Emu/Memory/MemoryBlock.h b/rpcs3/Emu/Memory/MemoryBlock.h index 7d497bb1c4..793af5ca4d 100644 --- a/rpcs3/Emu/Memory/MemoryBlock.h +++ b/rpcs3/Emu/Memory/MemoryBlock.h @@ -40,6 +40,23 @@ struct MemBlockInfo : public MemInfo } }; +struct VirtualMemInfo : public MemInfo +{ + u64 realAddress; + + VirtualMemInfo(u64 _addr, u64 _realaddr, u32 _size) + : MemInfo(_addr, _size) + , realAddress(_realaddr) + { + } + + VirtualMemInfo() + : MemInfo(0, 0) + , realAddress(0) + { + } +}; + class MemoryBlock { protected: @@ -206,6 +223,47 @@ private: void AppendLockedMem(u64 addr, u32 size); }; +class VirtualMemoryBlock : public MemoryBlock +{ + Array m_mapped_memory; + +public: + VirtualMemoryBlock(); + + virtual bool IsInMyRange(const u64 addr); + virtual bool IsInMyRange(const u64 addr, const u32 size); + virtual bool IsMyAddress(const u64 addr); + virtual void Delete(); + + // maps real address to virtual address space, returns the mapped address or 0 on failure (if no address is specified the + // first mappable space is used) + virtual u64 Map(u64 realaddr, u32 size, u64 addr = 0); + + // Unmap real address (please specify only starting point, no midway memory will be unmapped) + virtual bool UnmapRealAddress(u64 realaddr); + + // Unmap address (please specify only starting point, no midway memory will be unmapped) + virtual bool UnmapAddress(u64 addr); + + virtual bool Read8(const u64 addr, u8* value); + virtual bool Read16(const u64 addr, u16* value); + virtual bool Read32(const u64 addr, u32* value); + virtual bool Read64(const u64 addr, u64* value); + virtual bool Read128(const u64 addr, u128* value); + + virtual bool Write8(const u64 addr, const u8 value); + virtual bool Write16(const u64 addr, const u16 value); + virtual bool Write32(const u64 addr, const u32 value); + virtual bool Write64(const u64 addr, const u64 value); + virtual bool Write128(const u64 addr, const u128 value); + + // return the real address given a mapped address, if not mapped return 0 + u64 getRealAddr(u64 addr); + + // return the mapped address given a real address, if not mapped return 0 + u64 getMappedAddress(u64 realAddress); +}; + #include "DynamicMemoryBlockBase.inl" typedef DynamicMemoryBlockBase DynamicMemoryBlock; diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp index 46bd67ad03..02a3e2958b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp @@ -6,6 +6,9 @@ void cellGcmSys_init(); Module cellGcmSys(0x0010, cellGcmSys_init); +u32 local_size = 0; +u32 local_addr = NULL; + enum { CELL_GCM_ERROR_FAILURE = 0x802100ff, @@ -14,14 +17,29 @@ enum CELL_GCM_ERROR_INVALID_ALIGNMENT = 0x80210004, }; +/*------------------------------------------------------------ + Memory Mapping +------------------------------------------------------------*/ + +struct gcm_offset +{ + u64 io; + u64 ea; +}; + +void InitOffsetTable(); +int cellGcmAddressToOffset(u32 address, mem32_t offset); +u32 cellGcmGetMaxIoMapSize(); +void cellGcmGetOffsetTable(mem_ptr_t table); +int32_t cellGcmIoOffsetToAddress(u32 ioOffset, mem_ptr_t address); +int cellGcmMapEaIoAddress(const u32 ea, const u32 io, const u32 size); + + +//------------------------------------------------------------ + CellGcmConfig current_config; CellGcmContextData current_context; gcmInfo gcm_info; -struct gcm_offset -{ - u16 ea; - u16 offset; -}; u32 map_offset_addr = 0; u32 map_offset_pos = 0; @@ -39,21 +57,16 @@ int cellGcmMapMainMemory(u32 address, u32 size, mem32_t offset) return CELL_OK; } -int cellGcmMapEaIoAddress(const u32 ea, const u32 io, const u32 size) -{ - cellGcmSys.Warning("cellGcmMapEaIoAddress(ea=0x%x, io=0x%x, size=0x%x)", ea, io, size); - //Memory.Map(io, ea, size); - //Emu.GetGSManager().GetRender().m_ioAddress = io; - Emu.GetGSManager().GetRender().m_report_main_addr = ea; - return CELL_OK; -} - int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress) { cellGcmSys.Warning("cellGcmInit(context_addr=0x%x,cmdSize=0x%x,ioSize=0x%x,ioAddress=0x%x)", context_addr, cmdSize, ioSize, ioAddress); - const u32 local_size = 0xf900000; //TODO - const u32 local_addr = Memory.RSXFBMem.GetStartAddr(); + if(!local_size && !local_addr) + { + local_size = 0xf900000; //TODO + local_addr = Memory.RSXFBMem.GetStartAddr(); + Memory.RSXFBMem.Alloc(local_size); + } cellGcmSys.Warning("*** local memory(addr=0x%x, size=0x%x)", local_addr, local_size); @@ -66,8 +79,10 @@ int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress) current_config.memoryFrequency = re32(650000000); current_config.coreFrequency = re32(500000000); - Memory.RSXFBMem.Alloc(local_size); + InitOffsetTable(); Memory.RSXCMDMem.Alloc(cmdSize); + Memory.MemoryBlocks.Add(Memory.RSXIOMem.SetRange(0xE0000000, 0x10000000/*256MB*/));//TODO: implement allocateAdressSpace in memoryBase + cellGcmMapEaIoAddress(ioAddress, ioSize, 0); u32 ctx_begin = ioAddress/* + 0x1000*/; u32 ctx_size = 0x6ffc; @@ -112,57 +127,6 @@ int cellGcmGetConfiguration(mem_ptr_t config) return CELL_OK; } -int cellGcmAddressToOffset(u32 address, mem32_t offset) -{ - cellGcmSys.Log("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.GetAddr()); - if(!offset.IsGood()) return CELL_EFAULT; - - if(!map_offset_addr) - { - map_offset_addr = Memory.Alloc(4*50, 4); - } - - u32 sa; - bool is_main_mem = false; - const auto& main_mem_info = Emu.GetGSManager().GetRender().m_main_mem_info; - for(u32 i=0; i= main_mem_info[i].addr && address < main_mem_info[i].addr + main_mem_info[i].size) - { - is_main_mem = true; - break; - } - } - - if(is_main_mem) - { - //main - sa = Emu.GetGSManager().GetRender().m_main_mem_addr; - //ConLog.Warning("cellGcmAddressToOffset: main memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); - } - else if(Memory.RSXFBMem.IsMyAddress(address)) - { - //local - sa = Emu.GetGSManager().GetRender().m_local_mem_addr; - //ConLog.Warning("cellGcmAddressToOffset: local memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); - } - else - { - //io - sa = Emu.GetGSManager().GetRender().m_ioAddress; - //ConLog.Warning("cellGcmAddressToOffset: io memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); - } - - offset = address - sa; - //ConLog.Warning("Address To Offset: 0x%x -> 0x%x", address, address - sa); - //Memory.Write16(map_offset_addr + map_offset_pos + 0, ea); - //Memory.Write16(map_offset_addr + map_offset_pos + 2, offset); - //map_offset_pos += 4; - - return CELL_OK; -} - int cellGcmSetDisplayBuffer(u32 id, u32 offset, u32 pitch, u32 width, u32 height) { cellGcmSys.Warning("cellGcmSetDisplayBuffer(id=0x%x,offset=0x%x,pitch=%d,width=%d,height=%d)", @@ -611,16 +575,160 @@ int cellGcmSetSecondVFrequency (u32 freq) return CELL_OK; } +/*------------------------------------------------------------ + Memory Mapping +------------------------------------------------------------*/ + +gcm_offset offsetTable = {0, 0}; + +void InitOffsetTable() +{ + offsetTable.io = Memory.Alloc(3072*sizeof(u16), 1); + for(int i=0; i<3072; i++) + { + Memory.Write16(offsetTable.io + sizeof(u16)*i, 0xFFFF); + } + + offsetTable.ea = Memory.Alloc(256*sizeof(u16), 1);//TODO: check flags + for(int i=0; i<256; i++) + { + Memory.Write16(offsetTable.ea + sizeof(u16)*i, 0xFFFF); + } +} + +int cellGcmAddressToOffset(u32 address, mem32_t offset) +{ + cellGcmSys.Log("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.GetAddr()); + if(!offset.IsGood()) return CELL_EFAULT; + + if(!map_offset_addr) + { + map_offset_addr = Memory.Alloc(4*50, 4); + } + + u32 sa; + bool is_main_mem = false; + const auto& main_mem_info = Emu.GetGSManager().GetRender().m_main_mem_info; + for(u32 i=0; i= main_mem_info[i].addr && address < main_mem_info[i].addr + main_mem_info[i].size) + { + is_main_mem = true; + break; + } + } + + if(is_main_mem) + { + //main + sa = Emu.GetGSManager().GetRender().m_main_mem_addr; + //ConLog.Warning("cellGcmAddressToOffset: main memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); + } + else if(Memory.RSXFBMem.IsMyAddress(address)) + { + //local + sa = Emu.GetGSManager().GetRender().m_local_mem_addr; + //ConLog.Warning("cellGcmAddressToOffset: local memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); + } + else + { + //io + sa = Emu.GetGSManager().GetRender().m_ioAddress; + //ConLog.Warning("cellGcmAddressToOffset: io memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); + } + + offset = address - sa; + //ConLog.Warning("Address To Offset: 0x%x -> 0x%x", address, address - sa); + //Memory.Write16(map_offset_addr + map_offset_pos + 0, ea); + //Memory.Write16(map_offset_addr + map_offset_pos + 2, offset); + //map_offset_pos += 4; + + return CELL_OK; +} + +u32 cellGcmGetMaxIoMapSize() +{ + UNIMPLEMENTED_FUNC(cellGcmSys); + return 0x10000000;//256MB TODO +} + +void cellGcmGetOffsetTable(mem_ptr_t table) +{ + table->io = re(offsetTable.io); + table->ea = re(offsetTable.ea); +} + +int32_t cellGcmIoOffsetToAddress(u32 ioOffset, mem_ptr_t address) +{ + u64 realAddr; + + realAddr = Memory.RSXIOMem.getRealAddr(Memory.RSXIOMem.GetStartAddr() + ioOffset); + + if(!realAddr) + return CELL_GCM_ERROR_FAILURE; + + Memory.Write64(address, realAddr); + + return CELL_OK; +} + +int cellGcmMapEaIoAddress(const u32 ea, const u32 io, const u32 size) +{ + cellGcmSys.Warning("cellGcmMapEaIoAddress(ea=0x%x, io=0x%x, size=0x%x)", ea, io, size); + + if((ea & 0xFFFFF) || (io & 0xFFFFF) || (size & 0xFFFFF)) return CELL_GCM_ERROR_FAILURE; + + //check if the mapping was successfull + if(Memory.RSXIOMem.Map(ea, size, Memory.RSXIOMem.GetStartAddr() + io)) + { + //fill the offset table + for(int i=0; i address, mem_ptr_t size) +{ + if(!local_size && !local_addr) + { + local_size = 0xf900000; //TODO + local_addr = Memory.RSXFBMem.GetStartAddr(); + Memory.RSXFBMem.Alloc(local_size); + Memory.Write32(address.GetAddr(), local_addr); + Memory.Write32(size.GetAddr(), local_size); + } + else + { + printf("RSX local memory already mapped"); + return CELL_GCM_ERROR_FAILURE; + } + + return CELL_OK; +} + void cellGcmSys_init() { + current_config.ioAddress = NULL; + current_config.localAddress = NULL; + cellGcmSys.AddFunc(0x055bd74d, cellGcmGetTiledPitchSize); cellGcmSys.AddFunc(0x06edea9e, cellGcmSetUserHandler); cellGcmSys.AddFunc(0x15bae46b, cellGcmInit); cellGcmSys.AddFunc(0x21397818, cellGcmSetFlipCommand); - cellGcmSys.AddFunc(0x21ac3697, cellGcmAddressToOffset); cellGcmSys.AddFunc(0x3a33c1fd, cellGcmFunc15); cellGcmSys.AddFunc(0x4ae8d215, cellGcmSetFlipMode); - cellGcmSys.AddFunc(0x63441cb4, cellGcmMapEaIoAddress); cellGcmSys.AddFunc(0x5e2ee0f0, cellGcmGetDefaultCommandWordSize); cellGcmSys.AddFunc(0x72a577ce, cellGcmGetFlipStatus); cellGcmSys.AddFunc(0x8cdf8c70, cellGcmGetDefaultSegmentWordSize); @@ -661,4 +769,12 @@ void cellGcmSys_init() cellGcmSys.AddFunc(0x4d7ce993, cellGcmSetSecondVFrequency); cellGcmSys.AddFunc(0xdc09357e, cellGcmSetFlip); cellGcmSys.AddFunc(0x983fb9aa, cellGcmSetWaitFlip); + + //Memory Mapping + cellGcmSys.AddFunc(0x21ac3697, cellGcmAddressToOffset); + cellGcmSys.AddFunc(0xfb81c03e, cellGcmGetMaxIoMapSize); + cellGcmSys.AddFunc(0x2922aed0, cellGcmGetOffsetTable); + cellGcmSys.AddFunc(0x2a6fba9c, cellGcmIoOffsetToAddress); + cellGcmSys.AddFunc(0x63441cb4, cellGcmMapEaIoAddress); + cellGcmSys.AddFunc(0xdb769b32, cellGcmMapLocalMemory); }