Fix some issues with UnloadNro on ldr:ro

This commit is contained in:
gdkchan 2018-11-28 18:38:38 -03:00
commit 3d737dcd09
2 changed files with 91 additions and 22 deletions

View file

@ -691,33 +691,43 @@ namespace Ryujinx.HLE.HOS.Kernel
lock (Blocks) lock (Blocks)
{ {
bool Success = CheckRange( bool Success = CheckRange(
Dst, Src,
Size, Size,
MemoryState.Mask, MemoryState.Mask,
MemoryState.CodeStatic, MemoryState.Heap,
MemoryPermission.None, MemoryPermission.None,
MemoryPermission.None, MemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.Borrowed,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
out _, out _,
out _, out _,
out _); out _);
Success &= CheckRange( Success &= CheckRange(
Src, Dst,
Size, PageSize,
MemoryState.Mask, MemoryState.UnmapProcessCodeMemoryAllowed,
MemoryState.Heap, MemoryState.UnmapProcessCodeMemoryAllowed,
MemoryPermission.Mask, MemoryPermission.None,
MemoryPermission.None, MemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
out _, out MemoryState State,
out _, out _,
out _); out _);
Success &= CheckRange(
Dst,
Size,
MemoryState.Mask,
State,
MemoryPermission.None,
MemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None);
if (Success) if (Success)
{ {
KernelResult Result = MmuUnmap(Dst, PagesCount); KernelResult Result = MmuUnmap(Dst, PagesCount);
@ -1688,6 +1698,45 @@ namespace Ryujinx.HLE.HOS.Kernel
return false; return false;
} }
private bool CheckRange(
ulong Address,
ulong Size,
MemoryState StateMask,
MemoryState StateExpected,
MemoryPermission PermissionMask,
MemoryPermission PermissionExpected,
MemoryAttribute AttributeMask,
MemoryAttribute AttributeExpected)
{
ulong EndAddr = Address + Size - 1;
LinkedListNode<KMemoryBlock> Node = FindBlockNode(Address);
do
{
KMemoryInfo Info = Node.Value.GetInfo();
//Check if the block state matches what we expect.
if ((Info.State & StateMask) != StateExpected ||
(Info.Permission & PermissionMask) != PermissionExpected ||
(Info.Attribute & AttributeMask) != AttributeExpected)
{
break;
}
//Check if this is the last block on the range, if so return success.
if (EndAddr <= Info.Address + Info.Size - 1)
{
return true;
}
Node = Node.Next;
}
while (Node != null);
return false;
}
private void InsertBlock( private void InsertBlock(
ulong BaseAddress, ulong BaseAddress,
ulong PagesCount, ulong PagesCount,

View file

@ -286,7 +286,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
KMemoryManager MemMgr = Context.Process.MemoryManager; KMemoryManager MemMgr = Context.Process.MemoryManager;
ulong TargetAddress = MemMgr.AddrSpaceStart; ulong TargetAddress = MemMgr.GetAddrSpaceBaseAddr();
while (true) while (true)
{ {
@ -400,25 +400,43 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
return MakeError(ErrorModule.Loader, LoaderErr.BadNrrAddress); return MakeError(ErrorModule.Loader, LoaderErr.BadNrrAddress);
} }
private long RemoveNroInfo(ServiceCtx Context, ulong NroMappedAddress, ulong NroHeapAddress) private long RemoveNroInfo(ServiceCtx Context, ulong NroMappedAddress)
{ {
foreach (NroInfo Info in NroInfos) foreach (NroInfo Info in NroInfos)
{ {
if (Info.NroMappedAddress == NroMappedAddress && Info.Executable.SourceAddress == NroHeapAddress) if (Info.NroMappedAddress == NroMappedAddress)
{ {
NroInfos.Remove(Info); NroInfos.Remove(Info);
KernelResult Result = Context.Process.MemoryManager.UnmapProcessCodeMemory( ulong TextSize = (ulong)Info.Executable.Text.Length;
Info.NroMappedAddress, ulong ROSize = (ulong)Info.Executable.RO.Length;
Info.Executable.SourceAddress, ulong DataSize = (ulong)Info.Executable.Data.Length;
Info.TotalSize - (ulong)Info.Executable.BssSize); ulong BssSize = (ulong)Info.Executable.BssSize;
if (Result == KernelResult.Success && Info.Executable.BssSize != 0) KernelResult Result = KernelResult.Success;
if (Info.Executable.BssSize != 0)
{ {
Result = Context.Process.MemoryManager.UnmapProcessCodeMemory( Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(
Info.NroMappedAddress + Info.TotalSize - (ulong)Info.Executable.BssSize, Info.NroMappedAddress + TextSize + ROSize + DataSize,
Info.Executable.BssAddress, Info.Executable.BssAddress,
(ulong)Info.Executable.BssSize); BssSize);
}
if (Result == KernelResult.Success)
{
Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(
Info.NroMappedAddress + TextSize + ROSize,
Info.Executable.SourceAddress + TextSize + ROSize,
DataSize);
if (Result == KernelResult.Success)
{
Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(
Info.NroMappedAddress,
Info.Executable.SourceAddress,
TextSize + ROSize);
}
} }
return (long)Result; return (long)Result;
@ -470,17 +488,19 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
{ {
long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization); long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
// Zero
Context.RequestData.ReadUInt64();
ulong NroMappedAddress = Context.RequestData.ReadUInt64(); ulong NroMappedAddress = Context.RequestData.ReadUInt64();
ulong NroHeapAddress = Context.RequestData.ReadUInt64();
if (IsInitialized) if (IsInitialized)
{ {
if ((NroMappedAddress & 0xFFF) != 0 || (NroHeapAddress & 0xFFF) != 0) if ((NroMappedAddress & 0xFFF) != 0)
{ {
return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress); return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress);
} }
Result = RemoveNroInfo(Context, NroMappedAddress, NroHeapAddress); Result = RemoveNroInfo(Context, NroMappedAddress);
} }
return Result; return Result;