mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 18:40:14 +00:00
LDR fixup memory synchronizer
This commit is contained in:
parent
009107937f
commit
3e400a517b
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user