service/ldr_ro: Fix CRO loading when the buffer contained multiple VM areas (#5125)
* vm_manager: Handle multiple areas in ChangeMemoryState It is possible that a few areas have the same permisson and state, but with different backing pointers. Currently, this function assumes that only one continous area is found, but this is not always the case. * service/ldr_ro: Handle multiple areas in VerifyBufferState It is possible that the buffer passed from the game is made up of multiple areas with the same permisson and state but different backing pointers. Change the check to allow that.
This commit is contained in:
parent
475b0fb159
commit
3edc4a3055
|
@ -151,13 +151,16 @@ ResultCode VMManager::ChangeMemoryState(VAddr target, u32 size, MemoryState expe
|
||||||
}
|
}
|
||||||
|
|
||||||
CASCADE_RESULT(auto vma, CarveVMARange(target, size));
|
CASCADE_RESULT(auto vma, CarveVMARange(target, size));
|
||||||
ASSERT(vma->second.size == size);
|
|
||||||
|
|
||||||
|
const VMAIter end = vma_map.end();
|
||||||
|
// The comparison against the end of the range must be done using addresses since VMAs can be
|
||||||
|
// merged during this process, causing invalidation of the iterators.
|
||||||
|
while (vma != end && vma->second.base < target_end) {
|
||||||
vma->second.permissions = new_perms;
|
vma->second.permissions = new_perms;
|
||||||
vma->second.meminfo_state = new_state;
|
vma->second.meminfo_state = new_state;
|
||||||
UpdatePageTableForVMA(vma->second);
|
UpdatePageTableForVMA(vma->second);
|
||||||
|
vma = std::next(MergeAdjacent(vma));
|
||||||
MergeAdjacent(vma);
|
}
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,17 @@ static const ResultCode ERROR_NOT_LOADED = // 0xD8A12C0D
|
||||||
|
|
||||||
static bool VerifyBufferState(Kernel::Process& process, VAddr buffer_ptr, u32 size) {
|
static bool VerifyBufferState(Kernel::Process& process, VAddr buffer_ptr, u32 size) {
|
||||||
auto vma = process.vm_manager.FindVMA(buffer_ptr);
|
auto vma = process.vm_manager.FindVMA(buffer_ptr);
|
||||||
return vma != process.vm_manager.vma_map.end() &&
|
while (vma != process.vm_manager.vma_map.end()) {
|
||||||
vma->second.base + vma->second.size >= buffer_ptr + size &&
|
if (vma->second.permissions != Kernel::VMAPermission::ReadWrite ||
|
||||||
vma->second.permissions == Kernel::VMAPermission::ReadWrite &&
|
vma->second.meminfo_state != Kernel::MemoryState::Private) {
|
||||||
vma->second.meminfo_state == Kernel::MemoryState::Private;
|
return false;
|
||||||
|
}
|
||||||
|
if (vma->second.base + vma->second.size >= buffer_ptr + size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
vma = std::next(vma);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RO::Initialize(Kernel::HLERequestContext& ctx) {
|
void RO::Initialize(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
Reference in New Issue