diff --git a/rpcs3/Emu/Memory/Memory.cpp b/rpcs3/Emu/Memory/Memory.cpp index 343bab55c2..3069864685 100644 --- a/rpcs3/Emu/Memory/Memory.cpp +++ b/rpcs3/Emu/Memory/Memory.cpp @@ -543,7 +543,7 @@ VirtualMemoryBlock::VirtualMemoryBlock() : MemoryBlock() bool VirtualMemoryBlock::IsInMyRange(const u64 addr) { - return addr >= GetStartAddr() && addr < GetStartAddr() + GetSize(); + return addr >= GetStartAddr() && addr < GetStartAddr() + GetSize() - GetResevedAmount(); } bool VirtualMemoryBlock::IsInMyRange(const u64 addr, const u32 size) @@ -576,10 +576,11 @@ u64 VirtualMemoryBlock::Map(u64 realaddr, u32 size, u64 addr) } else { - for(u64 addr = GetStartAddr(); addr <= GetEndAddr() - size;) + for(u64 addr = GetStartAddr(); addr <= GetEndAddr() - GetResevedAmount() - size;) { bool is_good_addr = true; + // check if address is already mapped for(u32 i=0; i= m_mapped_memory[i].addr && addr < m_mapped_memory[i].addr + m_mapped_memory[i].size) || @@ -602,32 +603,34 @@ u64 VirtualMemoryBlock::Map(u64 realaddr, u32 size, u64 addr) } } -bool VirtualMemoryBlock::UnmapRealAddress(u64 realaddr) +u32 VirtualMemoryBlock::UnmapRealAddress(u64 realaddr) { for(u32 i=0; i GetEndAddr() - GetStartAddr()) + return false; + + m_reserve_size += size; + return true; +} + +bool VirtualMemoryBlock::Unreserve(u32 size) +{ + if(size > GetResevedAmount()) + return false; + + m_reserve_size -= size; + return true; +} + +u32 VirtualMemoryBlock::GetResevedAmount() +{ + return m_reserve_size; } \ No newline at end of file diff --git a/rpcs3/Emu/Memory/MemoryBlock.h b/rpcs3/Emu/Memory/MemoryBlock.h index 793af5ca4d..76c4891e05 100644 --- a/rpcs3/Emu/Memory/MemoryBlock.h +++ b/rpcs3/Emu/Memory/MemoryBlock.h @@ -226,6 +226,7 @@ private: class VirtualMemoryBlock : public MemoryBlock { Array m_mapped_memory; + u32 m_reserve_size; public: VirtualMemoryBlock(); @@ -239,11 +240,20 @@ public: // 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 real address (please specify only starting point, no midway memory will be unmapped), returns the size of the unmapped area + virtual u32 UnmapRealAddress(u64 realaddr); - // Unmap address (please specify only starting point, no midway memory will be unmapped) - virtual bool UnmapAddress(u64 addr); + // Unmap address (please specify only starting point, no midway memory will be unmapped), returns the size of the unmapped area + virtual u32 UnmapAddress(u64 addr); + + // Reserve a certain amount so no one can use it, returns true on succces, false on failure + virtual bool Reserve(u32 size); + + // Unreserve a certain amount of bytes, returns true on succcess, false if size is bigger than the reserved amount + virtual bool Unreserve(u32 size); + + // Return the total amount of reserved memory + virtual u32 GetResevedAmount(); virtual bool Read8(const u64 addr, u8* value); virtual bool Read16(const u64 addr, u16* value); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp index bd71d2d0d7..998df1d900 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp @@ -12,9 +12,11 @@ u32 local_addr = NULL; enum { CELL_GCM_ERROR_FAILURE = 0x802100ff, + CELL_GCM_ERROR_NO_IO_PAGE_TABLE = 0x80210001, CELL_GCM_ERROR_INVALID_ENUM = 0x80210002, CELL_GCM_ERROR_INVALID_VALUE = 0x80210003, CELL_GCM_ERROR_INVALID_ALIGNMENT = 0x80210004, + CELL_GCM_ERROR_ADDRESS_OVERWRAP = 0x80210005 }; /*------------------------------------------------------------ @@ -28,12 +30,16 @@ struct gcm_offset }; void InitOffsetTable(); -int cellGcmAddressToOffset(u32 address, mem32_t offset); -u32 cellGcmGetMaxIoMapSize(); +int32_t cellGcmAddressToOffset(u64 address, mem32_t offset); +uint32_t 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); - +int32_t cellGcmIoOffsetToAddress(u32 ioOffset, u64 address); +int32_t cellGcmMapEaIoAddress(const u32 ea, const u32 io, const u32 size); +int32_t cellGcmMapMainMemory(u64 ea, u32 size, mem32_t offset); +int32_t cellGcmReserveIoMapSize(const u32 size); +int32_t cellGcmUnmapEaIoAddress(u64 ea); +int32_t cellGcmUnmapIoAddress(u64 io); +int32_t cellGcmUnreserveIoMapSize(u32 size); //------------------------------------------------------------ @@ -44,19 +50,6 @@ gcmInfo gcm_info; u32 map_offset_addr = 0; u32 map_offset_pos = 0; -int cellGcmMapMainMemory(u32 address, u32 size, mem32_t offset) -{ - cellGcmSys.Warning("cellGcmMapMainMemory(address=0x%x,size=0x%x,offset_addr=0x%x)", address, size, offset.GetAddr()); - if(!offset.IsGood()) return CELL_EFAULT; - - Emu.GetGSManager().GetRender().m_main_mem_addr = Emu.GetGSManager().GetRender().m_ioAddress; - - offset = address - Emu.GetGSManager().GetRender().m_main_mem_addr; - Emu.GetGSManager().GetRender().m_main_mem_info.AddCpy(MemInfo(address, size)); - - 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); @@ -82,7 +75,7 @@ int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress) InitOffsetTable(); Memory.RSXCMDMem.Alloc(cmdSize); Memory.MemoryBlocks.push_back(Memory.RSXIOMem.SetRange(0xE0000000, 0x10000000/*256MB*/));//TODO: implement allocateAdressSpace in memoryBase - cellGcmMapEaIoAddress(ioAddress, ioSize, 0); + cellGcmMapEaIoAddress(ioAddress, 0, ioSize); u32 ctx_begin = ioAddress/* + 0x1000*/; u32 ctx_size = 0x6ffc; @@ -596,61 +589,43 @@ void InitOffsetTable() } } -int cellGcmAddressToOffset(u32 address, mem32_t offset) +int32_t cellGcmAddressToOffset(u64 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); - } + cellGcmSys.Warning("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.GetAddr()); - u32 sa; - bool is_main_mem = false; - const auto& main_mem_info = Emu.GetGSManager().GetRender().m_main_mem_info; - for(u32 i=0; i= 0xD0000000/*not on main memory or local*/) + return CELL_GCM_ERROR_FAILURE; + + u32 result; + + // If address is in range of local memory + if(Memory.RSXFBMem.IsInMyRange(address)) { - //main memory - if(address >= main_mem_info[i].addr && address < main_mem_info[i].addr + main_mem_info[i].size) + result = address - Memory.RSXFBMem.GetStartAddr(); + } + // else check if the adress (main memory) is mapped in IO + else + { + u16 upper12Bits = Memory.Read16(offsetTable.io + sizeof(u16)*(address >> 20)); + + if(upper12Bits != 0xFFFF) { - is_main_mem = true; - break; + result = (((u64)upper12Bits << 20) | (address & (0xFFFFF))); + } + // address is not mapped in IO + else + { + return CELL_GCM_ERROR_FAILURE; } } - 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; - + offset = result; return CELL_OK; } -u32 cellGcmGetMaxIoMapSize() +uint32_t cellGcmGetMaxIoMapSize() { - UNIMPLEMENTED_FUNC(cellGcmSys); - return 0x10000000;//256MB TODO + return Memory.RSXIOMem.GetEndAddr() - Memory.RSXIOMem.GetStartAddr() - Memory.RSXIOMem.GetResevedAmount(); } void cellGcmGetOffsetTable(mem_ptr_t table) @@ -659,7 +634,7 @@ void cellGcmGetOffsetTable(mem_ptr_t table) table->ea = re(offsetTable.ea); } -int32_t cellGcmIoOffsetToAddress(u32 ioOffset, mem_ptr_t address) +int32_t cellGcmIoOffsetToAddress(u32 ioOffset, u64 address) { u64 realAddr; @@ -673,7 +648,7 @@ int32_t cellGcmIoOffsetToAddress(u32 ioOffset, mem_ptr_t address) return CELL_OK; } -int cellGcmMapEaIoAddress(const u32 ea, const u32 io, const u32 size) +int32_t 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); @@ -683,10 +658,10 @@ int cellGcmMapEaIoAddress(const u32 ea, const u32 io, const u32 size) if(Memory.RSXIOMem.Map(ea, size, Memory.RSXIOMem.GetStartAddr() + io)) { //fill the offset table - for(int i=0; i> 20); i++) { - Memory.Write16(offsetTable.io + ea/(1024*1024) + i, io/(1024*1024) + i); - Memory.Write16(offsetTable.ea + io/(1024*1024) + i, ea/(1024*1024) + i); + Memory.Write16(offsetTable.io + ((ea >> 20) + i)*sizeof(u16), (io >> 20) + i); + Memory.Write16(offsetTable.ea + ((io >> 20) + i)*sizeof(u16), (ea >> 20) + i); } } else @@ -694,20 +669,18 @@ int cellGcmMapEaIoAddress(const u32 ea, const u32 io, const u32 size) return CELL_GCM_ERROR_FAILURE; } - //Emu.GetGSManager().GetRender().m_ioAddress = io; - Emu.GetGSManager().GetRender().m_report_main_addr = ea; return CELL_OK; } -int32_t cellGcmMapLocalMemory(mem_ptr_t address, mem_ptr_t size) +int32_t cellGcmMapLocalMemory(u64 address, u64 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); + Memory.Write32(address, local_addr); + Memory.Write32(size, local_size); } else { @@ -718,6 +691,107 @@ int32_t cellGcmMapLocalMemory(mem_ptr_t address, mem_ptr_t size return CELL_OK; } +int32_t cellGcmMapMainMemory(u64 ea, u32 size, mem32_t offset) +{ + cellGcmSys.Warning("cellGcmMapMainMemory(ea=0x%x,size=0x%x,offset_addr=0x%x)", ea, size, offset.GetAddr()); + + u64 io; + + if((ea & 0xFFFFF) || (size & 0xFFFFF)) return CELL_GCM_ERROR_FAILURE; + + //check if the mapping was successfull + if(io = Memory.RSXIOMem.Map(ea, size, 0)) + { + //fill the offset table + for(u32 i=0; i<(size >> 20); i++) + { + Memory.Write16(offsetTable.io + ((ea >> 20) + i)*sizeof(u16), (io >> 20) + i); + Memory.Write16(offsetTable.ea + ((io >> 20) + i)*sizeof(u16), (ea >> 20) + i); + } + } + else + { + return CELL_GCM_ERROR_NO_IO_PAGE_TABLE; + } + + Emu.GetGSManager().GetRender().m_main_mem_addr = Emu.GetGSManager().GetRender().m_ioAddress; + Emu.GetGSManager().GetRender().m_main_mem_info.AddCpy(MemInfo(ea, size)); + + return CELL_OK; +} + +int32_t cellGcmReserveIoMapSize(const u32 size) +{ + if(size & 0xFFFFF) + return CELL_GCM_ERROR_INVALID_ALIGNMENT; + + if(size > cellGcmGetMaxIoMapSize()) + return CELL_GCM_ERROR_INVALID_VALUE; + + Memory.RSXIOMem.Reserve(size); + return CELL_OK; +} + +int32_t cellGcmUnmapEaIoAddress(u64 ea) +{ + u32 size; + if(size = Memory.RSXIOMem.UnmapRealAddress(ea)) + { + u64 io; + ea = ea >> 20; + io = Memory.Read16(offsetTable.io + (ea*sizeof(u16))); + + for(int i=0; i> 20; + ea = Memory.Read16(offsetTable.ea + (io*sizeof(u16))); + + for(int i=0; i Memory.RSXIOMem.GetResevedAmount()) + return CELL_GCM_ERROR_INVALID_VALUE; + + Memory.RSXIOMem.Unreserve(size); + return CELL_OK; +} + +//------------------------------------------------------------ + void cellGcmSys_init() { current_config.ioAddress = NULL; @@ -745,7 +819,6 @@ void cellGcmSys_init() cellGcmSys.AddFunc(0xd9b7653e, cellGcmUnbindTile); cellGcmSys.AddFunc(0xa75640e8, cellGcmUnbindZcull); cellGcmSys.AddFunc(0xa41ef7e8, cellGcmSetFlipHandler); - cellGcmSys.AddFunc(0xa114ec67, cellGcmMapMainMemory); cellGcmSys.AddFunc(0xf80196c1, cellGcmGetLabelAddress); cellGcmSys.AddFunc(0x107bf3a1, cellGcmInitCursor); cellGcmSys.AddFunc(0x1a0de550, cellGcmSetCursorPosition); @@ -777,4 +850,9 @@ void cellGcmSys_init() cellGcmSys.AddFunc(0x2a6fba9c, cellGcmIoOffsetToAddress); cellGcmSys.AddFunc(0x63441cb4, cellGcmMapEaIoAddress); cellGcmSys.AddFunc(0xdb769b32, cellGcmMapLocalMemory); + cellGcmSys.AddFunc(0xa114ec67, cellGcmMapMainMemory); + cellGcmSys.AddFunc(0xa7ede268, cellGcmReserveIoMapSize); + cellGcmSys.AddFunc(0xefd00f54, cellGcmUnmapEaIoAddress); + cellGcmSys.AddFunc(0xdb23e867, cellGcmUnmapIoAddress); + cellGcmSys.AddFunc(0x3b9bd5bd, cellGcmUnreserveIoMapSize); } diff --git a/rpcs3/Emu/SysCalls/Modules/cellResc.cpp b/rpcs3/Emu/SysCalls/Modules/cellResc.cpp index 55700fd4fc..24c8971206 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellResc.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellResc.cpp @@ -76,7 +76,7 @@ CCellRescInternal* s_rescInternalInstance = new CCellRescInternal(); // Extern Functions extern int cellGcmSetFlipMode(u32 mode); extern int cellGcmSetFlipHandler(u32 handler_addr); -extern int cellGcmAddressToOffset(u32 address, mem32_t offset); +extern int32_t cellGcmAddressToOffset(u64 address, mem32_t offset); extern int cellGcmSetDisplayBuffer(u32 id, u32 offset, u32 pitch, u32 width, u32 height); extern int cellGcmSetPrepareFlip(mem_ptr_t ctx, u32 id); extern int cellGcmSetSecondVFrequency(u32 freq);