From dbcba511b278a95d74711d91bde24fe57c543939 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 21 Nov 2018 18:10:49 -0300 Subject: [PATCH] Add checking for memory block slab heap usage, return errors if full, exit gracefully --- Ryujinx.HLE/HOS/Horizon.cs | 25 ++ Ryujinx.HLE/HOS/Kernel/HleScheduler.cs | 2 +- .../HOS/Kernel/KMemoryBlockAllocator.cs | 21 ++ Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs | 244 +++++++++++++++--- .../HOS/Kernel/KMemoryRegionManager.cs | 2 + Ryujinx.HLE/HOS/Kernel/KProcess.cs | 46 +++- Ryujinx.HLE/HOS/Kernel/KernelResult.cs | 1 + Ryujinx.HLE/HOS/Kernel/SvcMemory.cs | 6 +- Ryujinx.HLE/HOS/Kernel/SvcSystem.cs | 4 + Ryujinx.HLE/HOS/ProgramLoader.cs | 2 + 10 files changed, 301 insertions(+), 52 deletions(-) create mode 100644 Ryujinx.HLE/HOS/Kernel/KMemoryBlockAllocator.cs diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index ea0850cce8..4370fb40b9 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -39,6 +39,9 @@ namespace Ryujinx.HLE.HOS internal KMemoryRegionManager[] MemoryRegions { get; private set; } + internal KMemoryBlockAllocator MemoryBlockAllocatorSys { get; private set; } + internal KMemoryBlockAllocator MemoryBlockAllocator2 { get; private set; } + internal KSlabHeap UserSlabHeapPages { get; private set; } internal KCriticalSection CriticalSection { get; private set; } @@ -55,6 +58,10 @@ namespace Ryujinx.HLE.HOS private long ProcessId; private long ThreadUid; + internal CountdownEvent ThreadCounter; + + internal LinkedList Processes; + internal AppletStateMgr AppletState { get; private set; } internal KSharedMemory HidSharedMem { get; private set; } @@ -90,6 +97,9 @@ namespace Ryujinx.HLE.HOS MemoryRegions = KernelInit.GetMemoryRegions(); + MemoryBlockAllocatorSys = new KMemoryBlockAllocator(0x4e20000); + MemoryBlockAllocator2 = new KMemoryBlockAllocator(0x2710000); + UserSlabHeapPages = new KSlabHeap( UserSlabHeapBase, UserSlabHeapItemSize, @@ -112,6 +122,10 @@ namespace Ryujinx.HLE.HOS KernelInitialized = true; + ThreadCounter = new CountdownEvent(1); + + Processes = new LinkedList(); + KMemoryRegionManager Region = MemoryRegions[(int)MemoryRegion.Service]; ulong HidPa = Region.Address; @@ -571,6 +585,17 @@ namespace Ryujinx.HLE.HOS { if (Disposing) { + //Force all threads to exit. + foreach (KProcess Process in Processes) + { + Process.StopAllThreads(); + } + + //It's only safe to release resources once all threads + //have exited. + ThreadCounter.Signal(); + ThreadCounter.Wait(); + Scheduler.Dispose(); TimeManager.Dispose(); diff --git a/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs b/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs index d7cec8b462..87dbe5538b 100644 --- a/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs +++ b/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs @@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Kernel public bool MultiCoreScheduling { get; set; } - private HleCoreManager CoreManager; + public HleCoreManager CoreManager { get; private set; } private bool KeepPreempting; diff --git a/Ryujinx.HLE/HOS/Kernel/KMemoryBlockAllocator.cs b/Ryujinx.HLE/HOS/Kernel/KMemoryBlockAllocator.cs new file mode 100644 index 0000000000..0fbac1f4cb --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KMemoryBlockAllocator.cs @@ -0,0 +1,21 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + class KMemoryBlockAllocator + { + private const int KMemoryBlockSize = 0x40; + + private ulong Size; + + public int Count { get; set; } + + public KMemoryBlockAllocator(ulong Size) + { + this.Size = Size; + } + + public bool CanAllocate(int Count) + { + return (ulong)(this.Count + Count) * KMemoryBlockSize <= Size; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs index 1277383cf2..cd992b2915 100644 --- a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs @@ -3,15 +3,17 @@ using Ryujinx.Common; using System; using System.Collections.Generic; -using static Ryujinx.HLE.HOS.ErrorCode; - namespace Ryujinx.HLE.HOS.Kernel { class KMemoryManager { public const int PageSize = 0x1000; - private const int KMemoryBlockSize = 0x40; + public const int KMemoryBlockSize = 0x40; + + //We need 2 blocks for the case where a big block + //needs to be split in 2, plus one block that will be the new one inserted. + private const int MaxBlocksNeededForInsertion = 2; private LinkedList Blocks; @@ -41,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Kernel private ulong HeapCapacity; - public ulong PersonalMmHeapUsage { get; private set; } + public ulong PhysicalMemoryUsage { get; private set; } private MemoryRegion MemRegion; @@ -52,6 +54,8 @@ namespace Ryujinx.HLE.HOS.Kernel private bool IsKernel; private bool AslrEnabled; + private KMemoryBlockAllocator BlockAllocator; + private int ContextId; private MersenneTwister RandomNumberGenerator; @@ -67,12 +71,13 @@ namespace Ryujinx.HLE.HOS.Kernel private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 }; public KernelResult InitializeForProcess( - AddressSpaceType AddrSpaceType, - bool AslrEnabled, - bool AslrDisabled, - MemoryRegion MemRegion, - ulong Address, - ulong Size) + AddressSpaceType AddrSpaceType, + bool AslrEnabled, + bool AslrDisabled, + MemoryRegion MemRegion, + ulong Address, + ulong Size, + KMemoryBlockAllocator BlockAllocator) { if ((uint)AddrSpaceType > (uint)AddressSpaceType.Addr39Bits) { @@ -92,7 +97,8 @@ namespace Ryujinx.HLE.HOS.Kernel AddrSpaceSize, MemRegion, Address, - Size); + Size, + BlockAllocator); if (Result != KernelResult.Success) { @@ -111,14 +117,15 @@ namespace Ryujinx.HLE.HOS.Kernel } private KernelResult CreateUserAddressSpace( - AddressSpaceType AddrSpaceType, - bool AslrEnabled, - bool AslrDisabled, - ulong AddrSpaceStart, - ulong AddrSpaceEnd, - MemoryRegion MemRegion, - ulong Address, - ulong Size) + AddressSpaceType AddrSpaceType, + bool AslrEnabled, + bool AslrDisabled, + ulong AddrSpaceStart, + ulong AddrSpaceEnd, + MemoryRegion MemRegion, + ulong Address, + ulong Size, + KMemoryBlockAllocator BlockAllocator) { ulong EndAddr = Address + Size; @@ -211,9 +218,13 @@ namespace Ryujinx.HLE.HOS.Kernel ulong AslrMaxOffset = MapAvailableSize - MapTotalSize; + this.AslrEnabled = AslrEnabled; + this.AddrSpaceStart = AddrSpaceStart; this.AddrSpaceEnd = AddrSpaceEnd; + this.BlockAllocator = BlockAllocator; + if (MapAvailableSize < MapTotalSize) { return KernelResult.OutOfMemory; @@ -274,14 +285,12 @@ namespace Ryujinx.HLE.HOS.Kernel CurrentHeapAddr = HeapRegionStart; HeapCapacity = 0; - PersonalMmHeapUsage = 0; + PhysicalMemoryUsage = 0; this.MemRegion = MemRegion; this.AslrDisabled = AslrDisabled; - InitializeBlocks(AddrSpaceStart, AddrSpaceEnd); - - return KernelResult.Success; + return InitializeBlocks(AddrSpaceStart, AddrSpaceEnd); } private ulong GetRandomValue(ulong Min, ulong Max) @@ -313,11 +322,20 @@ namespace Ryujinx.HLE.HOS.Kernel } } - private void InitializeBlocks(ulong AddrSpaceStart, ulong AddrSpaceEnd) + private KernelResult InitializeBlocks(ulong AddrSpaceStart, ulong AddrSpaceEnd) { + //First insertion will always need only a single block, + //because there's nothing else to split. + if (!BlockAllocator.CanAllocate(1)) + { + return KernelResult.OutOfResource; + } + ulong AddrSpacePagesCount = (AddrSpaceEnd - AddrSpaceStart) / PageSize; InsertBlock(AddrSpaceStart, AddrSpacePagesCount, MemoryState.Unmapped); + + return KernelResult.Success; } public KernelResult MapPages( @@ -342,6 +360,11 @@ namespace Ryujinx.HLE.HOS.Kernel return KernelResult.InvalidMemState; } + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + KernelResult Result = MapPages(Address, PageList, Permission); if (Result == KernelResult.Success) @@ -403,6 +426,11 @@ namespace Ryujinx.HLE.HOS.Kernel out _, out _)) { + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + KernelResult Result = MmuUnmap(Address, PagesCount); if (Result == KernelResult.Success) @@ -525,6 +553,11 @@ namespace Ryujinx.HLE.HOS.Kernel return KernelResult.OutOfMemory; } + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + MemoryOperation Operation = Map ? MemoryOperation.MapPa : MemoryOperation.Allocate; @@ -568,6 +601,11 @@ namespace Ryujinx.HLE.HOS.Kernel return KernelResult.InvalidMemState; } + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + KernelResult Result = DoMmuOperation( Address, PagesCount, @@ -609,6 +647,11 @@ namespace Ryujinx.HLE.HOS.Kernel if (Success) { + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2)) + { + return KernelResult.OutOfResource; + } + KPageList PageList = new KPageList(); AddVaRangeToPageList(PageList, Src, PagesCount); @@ -684,6 +727,13 @@ namespace Ryujinx.HLE.HOS.Kernel return Result; } + //TODO: Missing some checks here. + + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2)) + { + return KernelResult.OutOfResource; + } + InsertBlock(Dst, PagesCount, MemoryState.Unmapped); InsertBlock(Src, PagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite); @@ -705,6 +755,8 @@ namespace Ryujinx.HLE.HOS.Kernel return KernelResult.OutOfMemory; } + KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); + ulong CurrentHeapSize = GetHeapSize(); if (CurrentHeapSize <= Size) @@ -714,19 +766,49 @@ namespace Ryujinx.HLE.HOS.Kernel lock (Blocks) { + if (CurrentProcess.ResourceLimit != null && DiffSize != 0 && + !CurrentProcess.ResourceLimit.Reserve(LimitableResource.Memory, DiffSize)) + { + return KernelResult.ResLimitExceeded; + } + ulong PagesCount = DiffSize / PageSize; KMemoryRegionManager Region = GetMemoryRegionManager(); KernelResult Result = Region.AllocatePages(PagesCount, AslrDisabled, out KPageList PageList); + void CleanUpForError() + { + if (PageList != null) + { + Region.FreePages(PageList); + } + + if (CurrentProcess.ResourceLimit != null && DiffSize != 0) + { + CurrentProcess.ResourceLimit.Release(LimitableResource.Memory, DiffSize); + } + } + if (Result != KernelResult.Success) { + CleanUpForError(); + return Result; } + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + CleanUpForError(); + + return KernelResult.OutOfResource; + } + if (!IsUnmapped(CurrentHeapAddr, DiffSize)) { + CleanUpForError(); + return KernelResult.InvalidMemState; } @@ -739,6 +821,8 @@ namespace Ryujinx.HLE.HOS.Kernel if (Result != KernelResult.Success) { + CleanUpForError(); + return Result; } @@ -753,6 +837,11 @@ namespace Ryujinx.HLE.HOS.Kernel lock (Blocks) { + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + if (!CheckRange( FreeAddr, DiffSize, @@ -779,6 +868,8 @@ namespace Ryujinx.HLE.HOS.Kernel return Result; } + CurrentProcess.ResourceLimit?.Release(LimitableResource.Memory, BitUtils.AlignDown(DiffSize, PageSize)); + InsertBlock(FreeAddr, PagesCount, MemoryState.Unmapped); } } @@ -794,7 +885,7 @@ namespace Ryujinx.HLE.HOS.Kernel { lock (Blocks) { - return GetHeapSize() + PersonalMmHeapUsage; + return GetHeapSize() + PhysicalMemoryUsage; } } @@ -813,7 +904,7 @@ namespace Ryujinx.HLE.HOS.Kernel return KernelResult.Success; } - public long SetMemoryAttribute( + public KernelResult SetMemoryAttribute( ulong Address, ulong Size, MemoryAttribute AttributeMask, @@ -835,6 +926,11 @@ namespace Ryujinx.HLE.HOS.Kernel out MemoryPermission Permission, out MemoryAttribute Attribute)) { + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + ulong PagesCount = Size / PageSize; Attribute &= ~AttributeMask; @@ -842,11 +938,13 @@ namespace Ryujinx.HLE.HOS.Kernel InsertBlock(Address, PagesCount, State, Permission, Attribute); - return 0; + return KernelResult.Success; + } + else + { + return KernelResult.InvalidMemState; } } - - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); } public KMemoryInfo QueryMemory(ulong Address) @@ -896,6 +994,11 @@ namespace Ryujinx.HLE.HOS.Kernel if (Success) { + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2)) + { + return KernelResult.OutOfResource; + } + ulong PagesCount = Size / PageSize; KPageList PageList = new KPageList(); @@ -953,6 +1056,11 @@ namespace Ryujinx.HLE.HOS.Kernel out _, out _)) { + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + KernelResult Result = MmuUnmap(Address, PagesCount); if (Result == KernelResult.Success) @@ -1005,6 +1113,11 @@ namespace Ryujinx.HLE.HOS.Kernel if (Success) { + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2)) + { + return KernelResult.OutOfResource; + } + ulong PagesCount = Size / PageSize; KPageList SrcPageList = new KPageList(); @@ -1046,7 +1159,7 @@ namespace Ryujinx.HLE.HOS.Kernel } } - public long ReserveTransferMemory(ulong Address, ulong Size, MemoryPermission Permission) + public KernelResult ReserveTransferMemory(ulong Address, ulong Size, MemoryPermission Permission) { lock (Blocks) { @@ -1064,20 +1177,29 @@ namespace Ryujinx.HLE.HOS.Kernel out _, out MemoryAttribute Attribute)) { + //TODO: Missing checks. + + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + ulong PagesCount = Size / PageSize; Attribute |= MemoryAttribute.Borrowed; InsertBlock(Address, PagesCount, State, Permission, Attribute); - return 0; + return KernelResult.Success; + } + else + { + return KernelResult.InvalidMemState; } } - - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); } - public long ResetTransferMemory(ulong Address, ulong Size) + public KernelResult ResetTransferMemory(ulong Address, ulong Size) { lock (Blocks) { @@ -1095,15 +1217,22 @@ namespace Ryujinx.HLE.HOS.Kernel out _, out _)) { + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + ulong PagesCount = Size / PageSize; InsertBlock(Address, PagesCount, State, MemoryPermission.ReadAndWrite); - return 0; + return KernelResult.Success; + } + else + { + return KernelResult.InvalidMemState; } } - - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); } public KernelResult SetProcessMemoryPermission(ulong Address, ulong Size, MemoryPermission Permission) @@ -1146,6 +1275,11 @@ namespace Ryujinx.HLE.HOS.Kernel if (NewState != OldState || Permission != OldPermission) { + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + ulong PagesCount = Size / PageSize; MemoryOperation Operation = (Permission & MemoryPermission.Execute) != 0 @@ -1217,16 +1351,33 @@ namespace Ryujinx.HLE.HOS.Kernel KernelResult Result = Region.AllocatePages(RemainingPages, AslrDisabled, out KPageList PageList); + void CleanUpForError() + { + if (PageList != null) + { + Region.FreePages(PageList); + } + + CurrentProcess.ResourceLimit?.Release(LimitableResource.Memory, RemainingSize); + } + if (Result != KernelResult.Success) { - CurrentProcess.ResourceLimit?.Release(LimitableResource.Memory, RemainingSize); + CleanUpForError(); return Result; } + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + CleanUpForError(); + + return KernelResult.OutOfResource; + } + MapPhysicalMemory(PageList, Address, EndAddr); - PersonalMmHeapUsage += RemainingSize; + PhysicalMemoryUsage += RemainingSize; ulong PagesCount = Size / PageSize; @@ -1294,6 +1445,11 @@ namespace Ryujinx.HLE.HOS.Kernel return KernelResult.Success; } + if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) + { + return KernelResult.OutOfResource; + } + //Try to unmap all the heap mapped memory inside range. KernelResult Result = KernelResult.Success; @@ -1329,7 +1485,7 @@ namespace Ryujinx.HLE.HOS.Kernel { GetMemoryRegionManager().FreePages(PageList); - PersonalMmHeapUsage -= HeapMappedSize; + PhysicalMemoryUsage -= HeapMappedSize; KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); @@ -1545,6 +1701,8 @@ namespace Ryujinx.HLE.HOS.Kernel //Insert new block on the list only on areas where the state //of the block matches the state specified on the Old* state //arguments, otherwise leave it as is. + int OldCount = Blocks.Count; + OldAttribute |= MemoryAttribute.IpcAndDeviceMapped; ulong EndAddr = PagesCount * PageSize + BaseAddress; @@ -1637,6 +1795,8 @@ namespace Ryujinx.HLE.HOS.Kernel Node = NextNode; } + + BlockAllocator.Count += Blocks.Count - OldCount; } private void InsertBlock( @@ -1650,6 +1810,8 @@ namespace Ryujinx.HLE.HOS.Kernel //existing blocks as needed. KMemoryBlock Block = new KMemoryBlock(BaseAddress, PagesCount, State, Permission, Attribute); + int OldCount = Blocks.Count; + ulong EndAddr = PagesCount * PageSize + BaseAddress; LinkedListNode NewNode = null; @@ -1729,6 +1891,8 @@ namespace Ryujinx.HLE.HOS.Kernel } MergeEqualStateNeighbours(NewNode); + + BlockAllocator.Count += Blocks.Count - OldCount; } private void MergeEqualStateNeighbours(LinkedListNode Node) diff --git a/Ryujinx.HLE/HOS/Kernel/KMemoryRegionManager.cs b/Ryujinx.HLE/HOS/Kernel/KMemoryRegionManager.cs index 81f8e06675..8933432b66 100644 --- a/Ryujinx.HLE/HOS/Kernel/KMemoryRegionManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/KMemoryRegionManager.cs @@ -288,6 +288,8 @@ namespace Ryujinx.HLE.HOS.Kernel FreePages(PageNode.Address, PageNode.PagesCount); } + PageList = null; + return KernelResult.OutOfMemory; } diff --git a/Ryujinx.HLE/HOS/Kernel/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/KProcess.cs index ea29372ec8..0cd68107c9 100644 --- a/Ryujinx.HLE/HOS/Kernel/KProcess.cs +++ b/Ryujinx.HLE/HOS/Kernel/KProcess.cs @@ -124,13 +124,18 @@ namespace Ryujinx.HLE.HOS.Kernel ulong CodeSize = (ulong)CreationInfo.CodePagesCount * KMemoryManager.PageSize; + KMemoryBlockAllocator MemoryBlockAllocator = (MmuFlags & 0x40) != 0 + ? System.MemoryBlockAllocatorSys + : System.MemoryBlockAllocator2; + KernelResult Result = MemoryManager.InitializeForProcess( AddrSpaceType, AslrEnabled, !AslrEnabled, MemRegion, CodeAddress, - CodeSize); + CodeSize, + MemoryBlockAllocator); if (Result != KernelResult.Success) { @@ -205,9 +210,17 @@ namespace Ryujinx.HLE.HOS.Kernel PersonalMmHeapPagesCount = (ulong)CreationInfo.PersonalMmHeapPagesCount; + KMemoryBlockAllocator MemoryBlockAllocator; + if (PersonalMmHeapPagesCount != 0) { - + MemoryBlockAllocator = new KMemoryBlockAllocator(PersonalMmHeapPagesCount * KMemoryManager.PageSize); + } + else + { + MemoryBlockAllocator = (MmuFlags & 0x40) != 0 + ? System.MemoryBlockAllocatorSys + : System.MemoryBlockAllocator2; } AddressSpaceType AddrSpaceType = (AddressSpaceType)((CreationInfo.MmuFlags >> 1) & 7); @@ -224,7 +237,8 @@ namespace Ryujinx.HLE.HOS.Kernel !AslrEnabled, MemRegion, CodeAddress, - CodeSize); + CodeSize, + MemoryBlockAllocator); if (Result != KernelResult.Success) { @@ -314,8 +328,8 @@ namespace Ryujinx.HLE.HOS.Kernel return false; } - if (MemoryManager.InsideHeapRegion(Address, Size) || - MemoryManager.InsideAliasRegion (Address, Size)) + if (MemoryManager.InsideHeapRegion (Address, Size) || + MemoryManager.InsideAliasRegion(Address, Size)) { return false; } @@ -771,10 +785,14 @@ namespace Ryujinx.HLE.HOS.Kernel public void IncrementThreadCount() { Interlocked.Increment(ref ThreadCount); + + System.ThreadCounter.AddCount(); } public void DecrementThreadCountAndTerminateIfZero() { + System.ThreadCounter.Signal(); + if (Interlocked.Decrement(ref ThreadCount) == 0) { Terminate(); @@ -801,8 +819,7 @@ namespace Ryujinx.HLE.HOS.Kernel public ulong GetMemoryUsage() { - //TODO: Personal Mm Heap. - return ImageSize + MainThreadStackSize + MemoryManager.GetTotalHeapSize(); + return ImageSize + MainThreadStackSize + MemoryManager.GetTotalHeapSize() + GetPersonalMmHeapSize(); } public ulong GetMemoryCapacityWithoutPersonalMmHeap() @@ -895,7 +912,7 @@ namespace Ryujinx.HLE.HOS.Kernel if (ShallTerminate) { - UnpauseAndTerminateAllThreadsExcept(System.Scheduler.GetCurrentThread()); + //UnpauseAndTerminateAllThreadsExcept(System.Scheduler.GetCurrentThread()); HandleTable.Destroy(); @@ -955,6 +972,19 @@ namespace Ryujinx.HLE.HOS.Kernel return Result; } + public void StopAllThreads() + { + lock (ThreadingLock) + { + foreach (KThread Thread in Threads) + { + Thread.Context.StopExecution(); + + System.Scheduler.CoreManager.Set(Thread.Context.Work); + } + } + } + private void CpuTraceHandler(object sender, EventArgs e) { System.Scheduler.GetCurrentThread().PrintGuestStackTrace(); diff --git a/Ryujinx.HLE/HOS/Kernel/KernelResult.cs b/Ryujinx.HLE/HOS/Kernel/KernelResult.cs index ad0be5a20c..d20fc52428 100644 --- a/Ryujinx.HLE/HOS/Kernel/KernelResult.cs +++ b/Ryujinx.HLE/HOS/Kernel/KernelResult.cs @@ -7,6 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel ThreadTerminating = 0x7601, InvalidSize = 0xca01, InvalidAddress = 0xcc01, + OutOfResource = 0xce01, OutOfMemory = 0xd001, HandleTableFull = 0xd201, InvalidMemState = 0xd401, diff --git a/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs b/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs index d639602ab2..c12acf6335 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs @@ -72,15 +72,15 @@ namespace Ryujinx.HLE.HOS.Kernel return; } - long Result = Process.MemoryManager.SetMemoryAttribute( + KernelResult Result = Process.MemoryManager.SetMemoryAttribute( Position, Size, AttributeMask, AttributeValue); - if (Result != 0) + if (Result != KernelResult.Success) { - Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\"."); } else { diff --git a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs index d6bf5b03a0..fe240d2fc8 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs @@ -221,6 +221,8 @@ namespace Ryujinx.HLE.HOS.Kernel Message, MessagePtr)); + System.ThreadCounter.AddCount(); + System.CriticalSection.Leave(); ThreadState.X0 = (ulong)CurrentThread.ObjSyncResult; @@ -245,6 +247,8 @@ namespace Ryujinx.HLE.HOS.Kernel IpcMessage.Message, IpcMessage.MessagePtr); + System.ThreadCounter.Signal(); + IpcMessage.Thread.Reschedule(ThreadSchedState.Running); } diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs index 6f6e063abc..2cf5e14c56 100644 --- a/Ryujinx.HLE/HOS/ProgramLoader.cs +++ b/Ryujinx.HLE/HOS/ProgramLoader.cs @@ -151,6 +151,8 @@ namespace Ryujinx.HLE.HOS return false; } + System.Processes.AddLast(Process); + return true; } }