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); 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); map_offset_addr = 0; map_offset_pos = 0; current_config.ioSize = re32(ioSize); current_config.ioAddress = re32(ioAddress); current_config.localSize = re32(local_size); current_config.localAddress = re32(local_addr); current_config.memoryFrequency = re32(650000000); current_config.coreFrequency = re32(500000000); InitOffsetTable(); Memory.RSXCMDMem.Alloc(cmdSize); Memory.MemoryBlocks.push_back(Memory.RSXIOMem.SetRange(0xE0000000, 0x10000000/*256MB*/));//TODO: implement allocateAdressSpace in memoryBase cellGcmMapEaIoAddress(ioAddress, ioSize, 0); u32 ctx_begin = ioAddress/* + 0x1000*/; u32 ctx_size = 0x6ffc; current_context.begin = re(ctx_begin); current_context.end = re(ctx_begin + ctx_size); current_context.current = current_context.begin; current_context.callback = re32(Emu.GetRSXCallback() - 4); gcm_info.context_addr = Memory.MainMem.Alloc(0x1000); gcm_info.control_addr = gcm_info.context_addr + 0x40; Memory.WriteData(gcm_info.context_addr, current_context); Memory.Write32(context_addr, gcm_info.context_addr); CellGcmControl& ctrl = (CellGcmControl&)Memory[gcm_info.control_addr]; ctrl.put = 0; ctrl.get = 0; ctrl.ref = -1; auto& render = Emu.GetGSManager().GetRender(); render.m_ctxt_addr = context_addr; render.m_gcm_buffers_addr = Memory.Alloc(sizeof(gcmBuffer) * 8, sizeof(gcmBuffer)); render.m_zculls_addr = Memory.Alloc(sizeof(CellGcmZcullInfo) * 8, sizeof(CellGcmZcullInfo)); render.m_tiles_addr = Memory.Alloc(sizeof(CellGcmTileInfo) * 15, sizeof(CellGcmTileInfo)); render.m_gcm_buffers_count = 0; render.m_gcm_current_buffer = 0; render.m_main_mem_info.Clear(); render.m_main_mem_addr = 0; render.Init(ctx_begin, ctx_size, gcm_info.control_addr, local_addr); return CELL_OK; }
void MemoryBase::WriteMMIO32(u32 addr, const u32 data) { { std::lock_guard<std::recursive_mutex> lock(m_mutex); if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET]->Write32(addr, data)) { return; } } *(u32*)((u8*)GetBaseAddr() + addr) = re32(data); // provoke error }
void MemoryBase::WriteMMIO32(u32 addr, const u32 data) { { LV2_LOCK(0); if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Write32(addr, data)) { return; } } *(u32*)((u8*)GetBaseAddr() + addr) = re32(data); // provoke error }
u32 MemoryBase::ReadMMIO32(u32 addr) { u32 res; { std::lock_guard<std::recursive_mutex> lock(m_mutex); if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET]->Read32(addr, &res)) { return res; } } res = re32(*(u32*)((u8*)GetBaseAddr() + addr)); // provoke error return res; }
int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress) { cellGcmSys.Log("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(); map_offset_addr = 0; map_offset_pos = 0; current_config.ioSize = re32(ioSize); current_config.ioAddress = re32(ioAddress); current_config.localSize = re32(local_size); current_config.localAddress = re32(local_addr); current_config.memoryFrequency = re32(650000000); current_config.coreFrequency = re32(500000000); Memory.RSXFBMem.Alloc(local_size); Memory.RSXCMDMem.Alloc(cmdSize); u32 ctx_begin = ioAddress/* + 0x1000*/; u32 ctx_size = 0x6ffc; current_context.begin = re(ctx_begin); current_context.end = re(ctx_begin + ctx_size); current_context.current = current_context.begin; current_context.callback = re32(Emu.GetRSXCallback() - 4); gcm_info.context_addr = Memory.MainMem.Alloc(0x1000); gcm_info.control_addr = gcm_info.context_addr + 0x40; Memory.WriteData(gcm_info.context_addr, current_context); Memory.Write32(context_addr, gcm_info.context_addr); CellGcmControl& ctrl = (CellGcmControl&)Memory[gcm_info.control_addr]; ctrl.put = 0; ctrl.get = 0; ctrl.ref = -1; auto& render = Emu.GetGSManager().GetRender(); render.m_ctxt_addr = context_addr; render.m_gcm_buffers_addr = Memory.Alloc(sizeof(gcmBuffer) * 8, sizeof(gcmBuffer)); render.m_zculls_addr = Memory.Alloc(sizeof(CellGcmZcullInfo) * 8, sizeof(CellGcmZcullInfo)); render.m_tiles_addr = Memory.Alloc(sizeof(CellGcmTileInfo) * 15, sizeof(CellGcmTileInfo)); render.m_gcm_buffers_count = 0; render.m_gcm_current_buffer = 0; render.m_main_mem_info.Clear(); render.m_main_mem_addr = 0; render.Init(ctx_begin, ctx_size, gcm_info.control_addr, local_addr); return CELL_OK; }
u32 MemoryBase::ReadMMIO32(u32 addr) { u32 res; { LV2_LOCK(0); if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Read32(addr, &res)) { return res; } } res = re32(*(u32*)((u8*)GetBaseAddr() + addr)); // provoke error return res; }
u32 Memory::read32(u32 addr) { return re32(*(u32*)((u64)m_base + addr)); }
void Memory::write32(u32 addr, u32 value) { *(u32*)((u64)m_base + addr) = re32(value); }
int sdata_unpack(const std::string& packed_file, const std::string& unpacked_file) { std::shared_ptr<vfsFileBase> packed_stream(Emu.GetVFS().OpenFile(packed_file, vfsRead)); std::shared_ptr<vfsFileBase> unpacked_stream(Emu.GetVFS().OpenFile(unpacked_file, vfsWrite)); if(!packed_stream || !packed_stream->IsOpened()) { sys_fs.Error("'%s' not found! flags: 0x%08x", packed_file.c_str(), vfsRead); return CELL_ENOENT; } if(!unpacked_stream || !unpacked_stream->IsOpened()) { sys_fs.Error("'%s' couldn't be created! flags: 0x%08x", unpacked_file.c_str(), vfsWrite); return CELL_ENOENT; } char buffer [10200]; packed_stream->Read(buffer, 256); u32 format = re32(*(u32*)&buffer[0]); if (format != 0x4E504400) // "NPD\x00" { sys_fs.Error("Illegal format. Expected 0x4E504400, but got 0x%08x", format); return CELL_EFSSPECIFIC; } u32 version = re32(*(u32*)&buffer[0x04]); u32 flags = re32(*(u32*)&buffer[0x80]); u32 blockSize = re32(*(u32*)&buffer[0x84]); u64 filesizeOutput = re64(*(u64*)&buffer[0x88]); u64 filesizeInput = packed_stream->GetSize(); u32 blockCount = (filesizeOutput + blockSize-1) / blockSize; // SDATA file is compressed if (flags & 0x1) { sys_fs.Warning("cellFsSdataOpen: Compressed SDATA files are not supported yet."); return CELL_EFSSPECIFIC; } // SDATA file is NOT compressed else { u32 t1 = (flags & 0x20) ? 0x20 : 0x10; u32 startOffset = (blockCount * t1) + 0x100; u64 filesizeTmp = (filesizeOutput+0xF)&0xFFFFFFF0 + startOffset; if (!sdata_check(version, flags, filesizeInput, filesizeTmp)) { sys_fs.Error("cellFsSdataOpen: Wrong header information."); return CELL_EFSSPECIFIC; } if (flags & 0x20) packed_stream->Seek(0x100); else packed_stream->Seek(startOffset); for (u32 i = 0; i < blockCount; i++) { if (flags & 0x20) packed_stream->Seek(packed_stream->Tell() + t1); if (!(blockCount-i-1)) blockSize = filesizeOutput-i*blockSize; packed_stream->Read(buffer+256, blockSize); unpacked_stream->Write(buffer+256, blockSize); } } return CELL_OK; }
__forceinline void Write32(const fs::file& f, const u32 data) { Write32LE(f, re32(data)); }
__forceinline void Write32(vfsStream& f, const u32 data) { Write32LE(f, re32(data)); }
void StaticAnalyse(void* ptr, u32 size, u32 base) { u32* data = (u32*)ptr; size /= 4; if(!Ini.HLEHookStFunc.GetValue()) return; // TODO: optimize search for (u32 i = 0; i < size; i++) { for (u32 j = 0; j < g_static_funcs_list.GetCount(); j++) { if ((data[i] & g_static_funcs_list[j].ops[0].mask) == g_static_funcs_list[j].ops[0].crc) { bool found = true; u32 can_skip = 0; for (u32 k = i, x = 0; x + 1 <= g_static_funcs_list[j].ops.GetCount(); k++, x++) { if (k >= size) { found = false; break; } // skip NOP if (data[k] == se32(0x60000000)) { x--; continue; } const u32 mask = g_static_funcs_list[j].ops[x].mask; const u32 crc = g_static_funcs_list[j].ops[x].crc; if (!mask) { // TODO: define syntax if (crc < 4) // skip various number of instructions that don't match next pattern entry { can_skip += crc; k--; // process this position again } else if (data[k] != crc) // skippable pattern ("optional" instruction), no mask allowed { k--; if (can_skip) // cannot define this behaviour properly { ConLog.Warning("StaticAnalyse(): can_skip = %d (unchanged)", can_skip); } } else { if (can_skip) // cannot define this behaviour properly { ConLog.Warning("StaticAnalyse(): can_skip = %d (set to 0)", can_skip); can_skip = 0; } } } else if ((data[k] & mask) != crc) // masked pattern { if (can_skip) { can_skip--; } else { found = false; break; } } else { can_skip = 0; } } if (found) { ConLog.Write("Function '%s' hooked (addr=0x%x)", g_static_funcs_list[j].name, i * 4 + base); g_static_funcs_list[j].found++; data[i+0] = re32(0x39600000 | j); // li r11, j data[i+1] = se32(0x44000003); // sc 3 data[i+2] = se32(0x4e800020); // blr i += 2; // skip modified code } } } } // check function groups for (u32 i = 0; i < g_static_funcs_list.GetCount(); i++) { if (g_static_funcs_list[i].found) // start from some group { const u64 group = g_static_funcs_list[i].group; enum GroupSearchResult : u32 { GSR_SUCCESS = 0, // every function from this group has been found once GSR_MISSING = 1, // (error) some function not found GSR_EXCESS = 2, // (error) some function found twice or more }; u32 res = GSR_SUCCESS; // analyse for (u32 j = i; j < g_static_funcs_list.GetCount(); j++) if (g_static_funcs_list[j].group == group) { u32 count = g_static_funcs_list[j].found; if (count == 0) // not found { // check if this function has been found with different pattern for (u32 k = i; k < g_static_funcs_list.GetCount(); k++) if (g_static_funcs_list[k].group == group) { if (k != j && g_static_funcs_list[k].ptr == g_static_funcs_list[j].ptr) { count += g_static_funcs_list[k].found; } } if (count == 0) { res |= GSR_MISSING; ConLog.Error("Function '%s' not found", g_static_funcs_list[j].name); } else if (count > 1) { res |= GSR_EXCESS; } } else if (count == 1) // found { // ensure that this function has NOT been found with different pattern for (u32 k = i; k < g_static_funcs_list.GetCount(); k++) if (g_static_funcs_list[k].group == group) { if (k != j && g_static_funcs_list[k].ptr == g_static_funcs_list[j].ptr) { if (g_static_funcs_list[k].found) { res |= GSR_EXCESS; ConLog.Error("Function '%s' hooked twice", g_static_funcs_list[j].name); } } } } else { res |= GSR_EXCESS; ConLog.Error("Function '%s' hooked twice", g_static_funcs_list[j].name); } } // clear data for (u32 j = i; j < g_static_funcs_list.GetCount(); j++) { if (g_static_funcs_list[j].group == group) g_static_funcs_list[j].found = 0; } char name[9] = "????????"; *(u64*)name = group; if (res == GSR_SUCCESS) { ConLog.Success("Function group [%s] successfully hooked", std::string(name, 9).c_str()); } else { ConLog.Error("Function group [%s] failed:%s%s", std::string(name, 9).c_str(), (res & GSR_MISSING ? " missing;" : ""), (res & GSR_EXCESS ? " excess;" : "")); } } } }