forked from suyu/suyu
Restore memory perms on svcUnmapMemory/UnloadNro
Prior to PR, Yuzu did not restore memory to RW- on unmap of mirrored memory or unloading of NRO. (In fact, in the NRO case, the memory was unmapped instead of reprotected to --- on Load, so it was actually lost entirely...) This PR addresses that, and restores memory to RW- as it should. This fixes a crash in Super Smash Bros when creating a World of Light save for the first time, and possibly other games/circumstances.
This commit is contained in:
parent
0b3901bdd0
commit
072a9796f5
2 changed files with 34 additions and 7 deletions
|
@ -318,7 +318,14 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return vm_manager.UnmapRange(dst_addr, size);
|
const auto unmap_res = vm_manager.UnmapRange(dst_addr, size);
|
||||||
|
|
||||||
|
// Reprotect the source mapping on success
|
||||||
|
if (unmap_res.IsSuccess()) {
|
||||||
|
ASSERT(vm_manager.ReprotectRange(src_addr, size, VMAPermission::ReadWrite).IsSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
return unmap_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connect to an OS service given the port name, returns the handle to the port to out
|
/// Connect to an OS service given the port name, returns the handle to the port to out
|
||||||
|
|
|
@ -345,14 +345,16 @@ public:
|
||||||
vm_manager
|
vm_manager
|
||||||
.MirrorMemory(*map_address, nro_address, nro_size, Kernel::MemoryState::ModuleCode)
|
.MirrorMemory(*map_address, nro_address, nro_size, Kernel::MemoryState::ModuleCode)
|
||||||
.IsSuccess());
|
.IsSuccess());
|
||||||
ASSERT(vm_manager.UnmapRange(nro_address, nro_size).IsSuccess());
|
ASSERT(vm_manager.ReprotectRange(nro_address, nro_size, Kernel::VMAPermission::None)
|
||||||
|
.IsSuccess());
|
||||||
|
|
||||||
if (bss_size > 0) {
|
if (bss_size > 0) {
|
||||||
ASSERT(vm_manager
|
ASSERT(vm_manager
|
||||||
.MirrorMemory(*map_address + nro_size, bss_address, bss_size,
|
.MirrorMemory(*map_address + nro_size, bss_address, bss_size,
|
||||||
Kernel::MemoryState::ModuleCode)
|
Kernel::MemoryState::ModuleCode)
|
||||||
.IsSuccess());
|
.IsSuccess());
|
||||||
ASSERT(vm_manager.UnmapRange(bss_address, bss_size).IsSuccess());
|
ASSERT(vm_manager.ReprotectRange(bss_address, bss_size, Kernel::VMAPermission::None)
|
||||||
|
.IsSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_manager.ReprotectRange(*map_address, header.text_size,
|
vm_manager.ReprotectRange(*map_address, header.text_size,
|
||||||
|
@ -364,7 +366,8 @@ public:
|
||||||
|
|
||||||
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
||||||
|
|
||||||
nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size});
|
nro.insert_or_assign(*map_address,
|
||||||
|
NROInfo{hash, nro_address, nro_size, bss_address, bss_size});
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
@ -409,9 +412,23 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& vm_manager = Core::CurrentProcess()->VMManager();
|
auto& vm_manager = Core::CurrentProcess()->VMManager();
|
||||||
const auto& nro_size = iter->second.size;
|
const auto& nro_info = iter->second;
|
||||||
|
|
||||||
ASSERT(vm_manager.UnmapRange(nro_address, nro_size).IsSuccess());
|
// Unmap the mirrored memory
|
||||||
|
ASSERT(
|
||||||
|
vm_manager.UnmapRange(nro_address, nro_info.nro_size + nro_info.bss_size).IsSuccess());
|
||||||
|
|
||||||
|
// Reprotect the source memory
|
||||||
|
ASSERT(vm_manager
|
||||||
|
.ReprotectRange(nro_info.nro_address, nro_info.nro_size,
|
||||||
|
Kernel::VMAPermission::ReadWrite)
|
||||||
|
.IsSuccess());
|
||||||
|
if (nro_info.bss_size > 0) {
|
||||||
|
ASSERT(vm_manager
|
||||||
|
.ReprotectRange(nro_info.bss_address, nro_info.bss_size,
|
||||||
|
Kernel::VMAPermission::ReadWrite)
|
||||||
|
.IsSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
||||||
|
|
||||||
|
@ -473,7 +490,10 @@ private:
|
||||||
|
|
||||||
struct NROInfo {
|
struct NROInfo {
|
||||||
SHA256Hash hash;
|
SHA256Hash hash;
|
||||||
u64 size;
|
VAddr nro_address;
|
||||||
|
u64 nro_size;
|
||||||
|
VAddr bss_address;
|
||||||
|
u64 bss_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
Loading…
Reference in a new issue