From 3d737dcd09bd531e220b898e3a079a11ac416c3c Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 28 Nov 2018 18:38:38 -0300 Subject: [PATCH] Fix some issues with UnloadNro on ldr:ro --- Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs | 67 +++++++++++++++++--- Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs | 46 ++++++++++---- 2 files changed, 91 insertions(+), 22 deletions(-) diff --git a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs index bfcd9f0ea1..0aa21e3f39 100644 --- a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs @@ -691,33 +691,43 @@ namespace Ryujinx.HLE.HOS.Kernel lock (Blocks) { bool Success = CheckRange( - Dst, + Src, Size, MemoryState.Mask, - MemoryState.CodeStatic, + MemoryState.Heap, MemoryPermission.None, MemoryPermission.None, MemoryAttribute.Mask, - MemoryAttribute.None, + MemoryAttribute.Borrowed, MemoryAttribute.IpcAndDeviceMapped, out _, out _, out _); Success &= CheckRange( - Src, - Size, - MemoryState.Mask, - MemoryState.Heap, - MemoryPermission.Mask, + Dst, + PageSize, + MemoryState.UnmapProcessCodeMemoryAllowed, + MemoryState.UnmapProcessCodeMemoryAllowed, + MemoryPermission.None, MemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, - out _, + out MemoryState State, out _, out _); + Success &= CheckRange( + Dst, + Size, + MemoryState.Mask, + State, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.None); + if (Success) { KernelResult Result = MmuUnmap(Dst, PagesCount); @@ -1688,6 +1698,45 @@ namespace Ryujinx.HLE.HOS.Kernel 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 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( ulong BaseAddress, ulong PagesCount, diff --git a/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs b/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs index 5c13e5be32..f0899bd402 100644 --- a/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs +++ b/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs @@ -286,7 +286,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldr KMemoryManager MemMgr = Context.Process.MemoryManager; - ulong TargetAddress = MemMgr.AddrSpaceStart; + ulong TargetAddress = MemMgr.GetAddrSpaceBaseAddr(); while (true) { @@ -400,25 +400,43 @@ namespace Ryujinx.HLE.HOS.Services.Ldr 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) { - if (Info.NroMappedAddress == NroMappedAddress && Info.Executable.SourceAddress == NroHeapAddress) + if (Info.NroMappedAddress == NroMappedAddress) { NroInfos.Remove(Info); - KernelResult Result = Context.Process.MemoryManager.UnmapProcessCodeMemory( - Info.NroMappedAddress, - Info.Executable.SourceAddress, - Info.TotalSize - (ulong)Info.Executable.BssSize); + ulong TextSize = (ulong)Info.Executable.Text.Length; + ulong ROSize = (ulong)Info.Executable.RO.Length; + ulong DataSize = (ulong)Info.Executable.Data.Length; + 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( - Info.NroMappedAddress + Info.TotalSize - (ulong)Info.Executable.BssSize, + Info.NroMappedAddress + TextSize + ROSize + DataSize, 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; @@ -470,17 +488,19 @@ namespace Ryujinx.HLE.HOS.Services.Ldr { long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization); + // Zero + Context.RequestData.ReadUInt64(); + ulong NroMappedAddress = Context.RequestData.ReadUInt64(); - ulong NroHeapAddress = Context.RequestData.ReadUInt64(); if (IsInitialized) { - if ((NroMappedAddress & 0xFFF) != 0 || (NroHeapAddress & 0xFFF) != 0) + if ((NroMappedAddress & 0xFFF) != 0) { return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress); } - Result = RemoveNroInfo(Context, NroMappedAddress, NroHeapAddress); + Result = RemoveNroInfo(Context, NroMappedAddress); } return Result;