LDR fixup memory synchronizer

This commit is contained in:
wwylele 2016-08-19 21:05:11 +08:00
parent 009107937f
commit 3e400a517b

View File

@ -2054,14 +2054,28 @@ const std::array<CROHelper::HeaderField, 4> CROHelper::FIX_BARRIERS {{
Fix3Barrier Fix3Barrier
}}; }};
// This is a work-around before we implement memory aliasing. /**
// CRS and CRO are mapped (aliased) to another memory when loading. * This is a work-around before we implement memory aliasing.
// Games can read from both the original buffer or the mapped memory, * CRS and CRO are mapped (aliased) to another memory when loading. Games can read
// and even write to the original buffer after CRO loading. * from both the original buffer and the mapping memory. So we use this to synchronize
// So we use this to synchronize all original buffer with mapped memory * all original buffers with mapping memory after modifying the content.
// after modifiying the content (rebasing, linking, etc.). */
class MemorySynchronizer { class MemorySynchronizer {
std::map<VAddr, std::tuple<VAddr, u32>> memory_blocks; struct MemoryBlock {
VAddr mapping;
VAddr original;
u32 size;
};
std::vector<MemoryBlock> memory_blocks;
auto FindMemoryBlock(VAddr mapping, VAddr original) {
auto block = std::find_if(memory_blocks.begin(), memory_blocks.end(), [=](MemoryBlock& b){
return b.original == original;
});
ASSERT(block->mapping == mapping);
return block;
}
public: public:
void Clear() { void Clear() {
@ -2069,30 +2083,20 @@ public:
} }
void AddMemoryBlock(VAddr mapping, VAddr original, u32 size) { void AddMemoryBlock(VAddr mapping, VAddr original, u32 size) {
memory_blocks[mapping] = std::make_tuple(original, size); memory_blocks.push_back(MemoryBlock{mapping, original, size});
} }
void RemoveMemoryBlock(VAddr source) { void ResizeMemoryBlock(VAddr mapping, VAddr original, u32 size) {
memory_blocks.erase(source); FindMemoryBlock(mapping, original)->size = size;
}
void RemoveMemoryBlock(VAddr mapping, VAddr original) {
memory_blocks.erase(FindMemoryBlock(mapping, original));
} }
void SynchronizeOriginalMemory() { void SynchronizeOriginalMemory() {
for (auto block : memory_blocks) { for (auto& block : memory_blocks) {
VAddr mapping = block.first; Memory::CopyBlock(block.original, block.mapping, block.size);
VAddr original;
u32 size;
std::tie(original, size) = block.second;
Memory::CopyBlock(original, mapping, size);
}
}
void SynchronizeMappingMemory() {
for (auto block : memory_blocks) {
VAddr mapping = block.first;
VAddr original;
u32 size;
std::tie(original, size) = block.second;
Memory::CopyBlock(mapping, original, size);
} }
} }
}; };
@ -2354,8 +2358,6 @@ static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) {
return; return;
} }
memory_synchronizer.SynchronizeMappingMemory();
cmd_buff[0] = IPC::MakeHeader(link_on_load_bug_fix ? 9 : 4, 2, 0); cmd_buff[0] = IPC::MakeHeader(link_on_load_bug_fix ? 9 : 4, 2, 0);
if (loaded_crs == 0) { if (loaded_crs == 0) {
@ -2483,7 +2485,7 @@ static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) {
} }
// Changes the block size // Changes the block size
memory_synchronizer.AddMemoryBlock(cro_address, cro_buffer_ptr, fix_size); memory_synchronizer.ResizeMemoryBlock(cro_address, cro_buffer_ptr, fix_size);
} }
VAddr exe_begin; VAddr exe_begin;
@ -2546,8 +2548,6 @@ static void UnloadCRO(Service::Interface* self) {
CROHelper cro(cro_address); CROHelper cro(cro_address);
memory_synchronizer.SynchronizeMappingMemory();
cmd_buff[0] = IPC::MakeHeader(5, 1, 0); cmd_buff[0] = IPC::MakeHeader(5, 1, 0);
if (loaded_crs == 0) { if (loaded_crs == 0) {
@ -2602,7 +2602,7 @@ static void UnloadCRO(Service::Interface* self) {
if (result.IsError()) { if (result.IsError()) {
LOG_ERROR(Service_LDR, "Error unmapping CRO %08X", result.raw); LOG_ERROR(Service_LDR, "Error unmapping CRO %08X", result.raw);
} }
memory_synchronizer.RemoveMemoryBlock(cro_address); memory_synchronizer.RemoveMemoryBlock(cro_address, cro_buffer_ptr);
} }
Core::g_app_core->ClearInstructionCache(); Core::g_app_core->ClearInstructionCache();
@ -2639,8 +2639,6 @@ static void LinkCRO(Service::Interface* self) {
CROHelper cro(cro_address); CROHelper cro(cro_address);
memory_synchronizer.SynchronizeMappingMemory();
cmd_buff[0] = IPC::MakeHeader(6, 1, 0); cmd_buff[0] = IPC::MakeHeader(6, 1, 0);
if (loaded_crs == 0) { if (loaded_crs == 0) {
@ -2703,8 +2701,6 @@ static void UnlinkCRO(Service::Interface* self) {
CROHelper cro(cro_address); CROHelper cro(cro_address);
memory_synchronizer.SynchronizeMappingMemory();
cmd_buff[0] = IPC::MakeHeader(7, 1, 0); cmd_buff[0] = IPC::MakeHeader(7, 1, 0);
if (loaded_crs == 0) { if (loaded_crs == 0) {
@ -2765,8 +2761,6 @@ static void Shutdown(Service::Interface* self) {
return; return;
} }
memory_synchronizer.SynchronizeMappingMemory();
if (loaded_crs == 0) { if (loaded_crs == 0) {
LOG_ERROR(Service_LDR, "Not initialized"); LOG_ERROR(Service_LDR, "Not initialized");
cmd_buff[1] = ERROR_NOT_INITIALIZED.raw; cmd_buff[1] = ERROR_NOT_INITIALIZED.raw;
@ -2788,7 +2782,7 @@ static void Shutdown(Service::Interface* self) {
if (result.IsError()) { if (result.IsError()) {
LOG_ERROR(Service_LDR, "Error unmapping CRS %08X", result.raw); LOG_ERROR(Service_LDR, "Error unmapping CRS %08X", result.raw);
} }
memory_synchronizer.RemoveMemoryBlock(loaded_crs); memory_synchronizer.RemoveMemoryBlock(loaded_crs, crs_buffer_ptr);
} }
loaded_crs = 0; loaded_crs = 0;