Add checking for memory block slab heap usage, return errors if full, exit gracefully

This commit is contained in:
gdkchan 2018-11-21 18:10:49 -03:00
commit dbcba511b2
10 changed files with 301 additions and 52 deletions

View file

@ -39,6 +39,9 @@ namespace Ryujinx.HLE.HOS
internal KMemoryRegionManager[] MemoryRegions { get; private set; } 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 KSlabHeap UserSlabHeapPages { get; private set; }
internal KCriticalSection CriticalSection { get; private set; } internal KCriticalSection CriticalSection { get; private set; }
@ -55,6 +58,10 @@ namespace Ryujinx.HLE.HOS
private long ProcessId; private long ProcessId;
private long ThreadUid; private long ThreadUid;
internal CountdownEvent ThreadCounter;
internal LinkedList<KProcess> Processes;
internal AppletStateMgr AppletState { get; private set; } internal AppletStateMgr AppletState { get; private set; }
internal KSharedMemory HidSharedMem { get; private set; } internal KSharedMemory HidSharedMem { get; private set; }
@ -90,6 +97,9 @@ namespace Ryujinx.HLE.HOS
MemoryRegions = KernelInit.GetMemoryRegions(); MemoryRegions = KernelInit.GetMemoryRegions();
MemoryBlockAllocatorSys = new KMemoryBlockAllocator(0x4e20000);
MemoryBlockAllocator2 = new KMemoryBlockAllocator(0x2710000);
UserSlabHeapPages = new KSlabHeap( UserSlabHeapPages = new KSlabHeap(
UserSlabHeapBase, UserSlabHeapBase,
UserSlabHeapItemSize, UserSlabHeapItemSize,
@ -112,6 +122,10 @@ namespace Ryujinx.HLE.HOS
KernelInitialized = true; KernelInitialized = true;
ThreadCounter = new CountdownEvent(1);
Processes = new LinkedList<KProcess>();
KMemoryRegionManager Region = MemoryRegions[(int)MemoryRegion.Service]; KMemoryRegionManager Region = MemoryRegions[(int)MemoryRegion.Service];
ulong HidPa = Region.Address; ulong HidPa = Region.Address;
@ -571,6 +585,17 @@ namespace Ryujinx.HLE.HOS
{ {
if (Disposing) 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(); Scheduler.Dispose();
TimeManager.Dispose(); TimeManager.Dispose();

View file

@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Kernel
public bool MultiCoreScheduling { get; set; } public bool MultiCoreScheduling { get; set; }
private HleCoreManager CoreManager; public HleCoreManager CoreManager { get; private set; }
private bool KeepPreempting; private bool KeepPreempting;

View file

@ -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;
}
}
}

View file

@ -3,15 +3,17 @@ using Ryujinx.Common;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.HLE.HOS.ErrorCode;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel
{ {
class KMemoryManager class KMemoryManager
{ {
public const int PageSize = 0x1000; 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<KMemoryBlock> Blocks; private LinkedList<KMemoryBlock> Blocks;
@ -41,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Kernel
private ulong HeapCapacity; private ulong HeapCapacity;
public ulong PersonalMmHeapUsage { get; private set; } public ulong PhysicalMemoryUsage { get; private set; }
private MemoryRegion MemRegion; private MemoryRegion MemRegion;
@ -52,6 +54,8 @@ namespace Ryujinx.HLE.HOS.Kernel
private bool IsKernel; private bool IsKernel;
private bool AslrEnabled; private bool AslrEnabled;
private KMemoryBlockAllocator BlockAllocator;
private int ContextId; private int ContextId;
private MersenneTwister RandomNumberGenerator; private MersenneTwister RandomNumberGenerator;
@ -72,7 +76,8 @@ namespace Ryujinx.HLE.HOS.Kernel
bool AslrDisabled, bool AslrDisabled,
MemoryRegion MemRegion, MemoryRegion MemRegion,
ulong Address, ulong Address,
ulong Size) ulong Size,
KMemoryBlockAllocator BlockAllocator)
{ {
if ((uint)AddrSpaceType > (uint)AddressSpaceType.Addr39Bits) if ((uint)AddrSpaceType > (uint)AddressSpaceType.Addr39Bits)
{ {
@ -92,7 +97,8 @@ namespace Ryujinx.HLE.HOS.Kernel
AddrSpaceSize, AddrSpaceSize,
MemRegion, MemRegion,
Address, Address,
Size); Size,
BlockAllocator);
if (Result != KernelResult.Success) if (Result != KernelResult.Success)
{ {
@ -118,7 +124,8 @@ namespace Ryujinx.HLE.HOS.Kernel
ulong AddrSpaceEnd, ulong AddrSpaceEnd,
MemoryRegion MemRegion, MemoryRegion MemRegion,
ulong Address, ulong Address,
ulong Size) ulong Size,
KMemoryBlockAllocator BlockAllocator)
{ {
ulong EndAddr = Address + Size; ulong EndAddr = Address + Size;
@ -211,9 +218,13 @@ namespace Ryujinx.HLE.HOS.Kernel
ulong AslrMaxOffset = MapAvailableSize - MapTotalSize; ulong AslrMaxOffset = MapAvailableSize - MapTotalSize;
this.AslrEnabled = AslrEnabled;
this.AddrSpaceStart = AddrSpaceStart; this.AddrSpaceStart = AddrSpaceStart;
this.AddrSpaceEnd = AddrSpaceEnd; this.AddrSpaceEnd = AddrSpaceEnd;
this.BlockAllocator = BlockAllocator;
if (MapAvailableSize < MapTotalSize) if (MapAvailableSize < MapTotalSize)
{ {
return KernelResult.OutOfMemory; return KernelResult.OutOfMemory;
@ -274,14 +285,12 @@ namespace Ryujinx.HLE.HOS.Kernel
CurrentHeapAddr = HeapRegionStart; CurrentHeapAddr = HeapRegionStart;
HeapCapacity = 0; HeapCapacity = 0;
PersonalMmHeapUsage = 0; PhysicalMemoryUsage = 0;
this.MemRegion = MemRegion; this.MemRegion = MemRegion;
this.AslrDisabled = AslrDisabled; this.AslrDisabled = AslrDisabled;
InitializeBlocks(AddrSpaceStart, AddrSpaceEnd); return InitializeBlocks(AddrSpaceStart, AddrSpaceEnd);
return KernelResult.Success;
} }
private ulong GetRandomValue(ulong Min, ulong Max) 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; ulong AddrSpacePagesCount = (AddrSpaceEnd - AddrSpaceStart) / PageSize;
InsertBlock(AddrSpaceStart, AddrSpacePagesCount, MemoryState.Unmapped); InsertBlock(AddrSpaceStart, AddrSpacePagesCount, MemoryState.Unmapped);
return KernelResult.Success;
} }
public KernelResult MapPages( public KernelResult MapPages(
@ -342,6 +360,11 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.InvalidMemState; return KernelResult.InvalidMemState;
} }
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
KernelResult Result = MapPages(Address, PageList, Permission); KernelResult Result = MapPages(Address, PageList, Permission);
if (Result == KernelResult.Success) if (Result == KernelResult.Success)
@ -403,6 +426,11 @@ namespace Ryujinx.HLE.HOS.Kernel
out _, out _,
out _)) out _))
{ {
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
KernelResult Result = MmuUnmap(Address, PagesCount); KernelResult Result = MmuUnmap(Address, PagesCount);
if (Result == KernelResult.Success) if (Result == KernelResult.Success)
@ -525,6 +553,11 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.OutOfMemory; return KernelResult.OutOfMemory;
} }
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
MemoryOperation Operation = Map MemoryOperation Operation = Map
? MemoryOperation.MapPa ? MemoryOperation.MapPa
: MemoryOperation.Allocate; : MemoryOperation.Allocate;
@ -568,6 +601,11 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.InvalidMemState; return KernelResult.InvalidMemState;
} }
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
KernelResult Result = DoMmuOperation( KernelResult Result = DoMmuOperation(
Address, Address,
PagesCount, PagesCount,
@ -609,6 +647,11 @@ namespace Ryujinx.HLE.HOS.Kernel
if (Success) if (Success)
{ {
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2))
{
return KernelResult.OutOfResource;
}
KPageList PageList = new KPageList(); KPageList PageList = new KPageList();
AddVaRangeToPageList(PageList, Src, PagesCount); AddVaRangeToPageList(PageList, Src, PagesCount);
@ -684,6 +727,13 @@ namespace Ryujinx.HLE.HOS.Kernel
return Result; return Result;
} }
//TODO: Missing some checks here.
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2))
{
return KernelResult.OutOfResource;
}
InsertBlock(Dst, PagesCount, MemoryState.Unmapped); InsertBlock(Dst, PagesCount, MemoryState.Unmapped);
InsertBlock(Src, PagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite); InsertBlock(Src, PagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
@ -705,6 +755,8 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.OutOfMemory; return KernelResult.OutOfMemory;
} }
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
ulong CurrentHeapSize = GetHeapSize(); ulong CurrentHeapSize = GetHeapSize();
if (CurrentHeapSize <= Size) if (CurrentHeapSize <= Size)
@ -714,19 +766,49 @@ namespace Ryujinx.HLE.HOS.Kernel
lock (Blocks) lock (Blocks)
{ {
if (CurrentProcess.ResourceLimit != null && DiffSize != 0 &&
!CurrentProcess.ResourceLimit.Reserve(LimitableResource.Memory, DiffSize))
{
return KernelResult.ResLimitExceeded;
}
ulong PagesCount = DiffSize / PageSize; ulong PagesCount = DiffSize / PageSize;
KMemoryRegionManager Region = GetMemoryRegionManager(); KMemoryRegionManager Region = GetMemoryRegionManager();
KernelResult Result = Region.AllocatePages(PagesCount, AslrDisabled, out KPageList PageList); 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) if (Result != KernelResult.Success)
{ {
CleanUpForError();
return Result; return Result;
} }
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
CleanUpForError();
return KernelResult.OutOfResource;
}
if (!IsUnmapped(CurrentHeapAddr, DiffSize)) if (!IsUnmapped(CurrentHeapAddr, DiffSize))
{ {
CleanUpForError();
return KernelResult.InvalidMemState; return KernelResult.InvalidMemState;
} }
@ -739,6 +821,8 @@ namespace Ryujinx.HLE.HOS.Kernel
if (Result != KernelResult.Success) if (Result != KernelResult.Success)
{ {
CleanUpForError();
return Result; return Result;
} }
@ -753,6 +837,11 @@ namespace Ryujinx.HLE.HOS.Kernel
lock (Blocks) lock (Blocks)
{ {
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
if (!CheckRange( if (!CheckRange(
FreeAddr, FreeAddr,
DiffSize, DiffSize,
@ -779,6 +868,8 @@ namespace Ryujinx.HLE.HOS.Kernel
return Result; return Result;
} }
CurrentProcess.ResourceLimit?.Release(LimitableResource.Memory, BitUtils.AlignDown(DiffSize, PageSize));
InsertBlock(FreeAddr, PagesCount, MemoryState.Unmapped); InsertBlock(FreeAddr, PagesCount, MemoryState.Unmapped);
} }
} }
@ -794,7 +885,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
lock (Blocks) lock (Blocks)
{ {
return GetHeapSize() + PersonalMmHeapUsage; return GetHeapSize() + PhysicalMemoryUsage;
} }
} }
@ -813,7 +904,7 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.Success; return KernelResult.Success;
} }
public long SetMemoryAttribute( public KernelResult SetMemoryAttribute(
ulong Address, ulong Address,
ulong Size, ulong Size,
MemoryAttribute AttributeMask, MemoryAttribute AttributeMask,
@ -835,6 +926,11 @@ namespace Ryujinx.HLE.HOS.Kernel
out MemoryPermission Permission, out MemoryPermission Permission,
out MemoryAttribute Attribute)) out MemoryAttribute Attribute))
{ {
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
ulong PagesCount = Size / PageSize; ulong PagesCount = Size / PageSize;
Attribute &= ~AttributeMask; Attribute &= ~AttributeMask;
@ -842,11 +938,13 @@ namespace Ryujinx.HLE.HOS.Kernel
InsertBlock(Address, PagesCount, State, Permission, Attribute); 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) public KMemoryInfo QueryMemory(ulong Address)
@ -896,6 +994,11 @@ namespace Ryujinx.HLE.HOS.Kernel
if (Success) if (Success)
{ {
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2))
{
return KernelResult.OutOfResource;
}
ulong PagesCount = Size / PageSize; ulong PagesCount = Size / PageSize;
KPageList PageList = new KPageList(); KPageList PageList = new KPageList();
@ -953,6 +1056,11 @@ namespace Ryujinx.HLE.HOS.Kernel
out _, out _,
out _)) out _))
{ {
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
KernelResult Result = MmuUnmap(Address, PagesCount); KernelResult Result = MmuUnmap(Address, PagesCount);
if (Result == KernelResult.Success) if (Result == KernelResult.Success)
@ -1005,6 +1113,11 @@ namespace Ryujinx.HLE.HOS.Kernel
if (Success) if (Success)
{ {
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2))
{
return KernelResult.OutOfResource;
}
ulong PagesCount = Size / PageSize; ulong PagesCount = Size / PageSize;
KPageList SrcPageList = new KPageList(); 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) lock (Blocks)
{ {
@ -1064,20 +1177,29 @@ namespace Ryujinx.HLE.HOS.Kernel
out _, out _,
out MemoryAttribute Attribute)) out MemoryAttribute Attribute))
{ {
//TODO: Missing checks.
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
ulong PagesCount = Size / PageSize; ulong PagesCount = Size / PageSize;
Attribute |= MemoryAttribute.Borrowed; Attribute |= MemoryAttribute.Borrowed;
InsertBlock(Address, PagesCount, State, Permission, Attribute); InsertBlock(Address, PagesCount, State, Permission, Attribute);
return 0; return KernelResult.Success;
}
else
{
return KernelResult.InvalidMemState;
}
} }
} }
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); public KernelResult ResetTransferMemory(ulong Address, ulong Size)
}
public long ResetTransferMemory(ulong Address, ulong Size)
{ {
lock (Blocks) lock (Blocks)
{ {
@ -1095,15 +1217,22 @@ namespace Ryujinx.HLE.HOS.Kernel
out _, out _,
out _)) out _))
{ {
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
ulong PagesCount = Size / PageSize; ulong PagesCount = Size / PageSize;
InsertBlock(Address, PagesCount, State, MemoryPermission.ReadAndWrite); 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) public KernelResult SetProcessMemoryPermission(ulong Address, ulong Size, MemoryPermission Permission)
@ -1146,6 +1275,11 @@ namespace Ryujinx.HLE.HOS.Kernel
if (NewState != OldState || Permission != OldPermission) if (NewState != OldState || Permission != OldPermission)
{ {
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
ulong PagesCount = Size / PageSize; ulong PagesCount = Size / PageSize;
MemoryOperation Operation = (Permission & MemoryPermission.Execute) != 0 MemoryOperation Operation = (Permission & MemoryPermission.Execute) != 0
@ -1217,16 +1351,33 @@ namespace Ryujinx.HLE.HOS.Kernel
KernelResult Result = Region.AllocatePages(RemainingPages, AslrDisabled, out KPageList PageList); 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) if (Result != KernelResult.Success)
{ {
CurrentProcess.ResourceLimit?.Release(LimitableResource.Memory, RemainingSize); CleanUpForError();
return Result; return Result;
} }
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
CleanUpForError();
return KernelResult.OutOfResource;
}
MapPhysicalMemory(PageList, Address, EndAddr); MapPhysicalMemory(PageList, Address, EndAddr);
PersonalMmHeapUsage += RemainingSize; PhysicalMemoryUsage += RemainingSize;
ulong PagesCount = Size / PageSize; ulong PagesCount = Size / PageSize;
@ -1294,6 +1445,11 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.Success; return KernelResult.Success;
} }
if (!BlockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
{
return KernelResult.OutOfResource;
}
//Try to unmap all the heap mapped memory inside range. //Try to unmap all the heap mapped memory inside range.
KernelResult Result = KernelResult.Success; KernelResult Result = KernelResult.Success;
@ -1329,7 +1485,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
GetMemoryRegionManager().FreePages(PageList); GetMemoryRegionManager().FreePages(PageList);
PersonalMmHeapUsage -= HeapMappedSize; PhysicalMemoryUsage -= HeapMappedSize;
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); 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 //Insert new block on the list only on areas where the state
//of the block matches the state specified on the Old* state //of the block matches the state specified on the Old* state
//arguments, otherwise leave it as is. //arguments, otherwise leave it as is.
int OldCount = Blocks.Count;
OldAttribute |= MemoryAttribute.IpcAndDeviceMapped; OldAttribute |= MemoryAttribute.IpcAndDeviceMapped;
ulong EndAddr = PagesCount * PageSize + BaseAddress; ulong EndAddr = PagesCount * PageSize + BaseAddress;
@ -1637,6 +1795,8 @@ namespace Ryujinx.HLE.HOS.Kernel
Node = NextNode; Node = NextNode;
} }
BlockAllocator.Count += Blocks.Count - OldCount;
} }
private void InsertBlock( private void InsertBlock(
@ -1650,6 +1810,8 @@ namespace Ryujinx.HLE.HOS.Kernel
//existing blocks as needed. //existing blocks as needed.
KMemoryBlock Block = new KMemoryBlock(BaseAddress, PagesCount, State, Permission, Attribute); KMemoryBlock Block = new KMemoryBlock(BaseAddress, PagesCount, State, Permission, Attribute);
int OldCount = Blocks.Count;
ulong EndAddr = PagesCount * PageSize + BaseAddress; ulong EndAddr = PagesCount * PageSize + BaseAddress;
LinkedListNode<KMemoryBlock> NewNode = null; LinkedListNode<KMemoryBlock> NewNode = null;
@ -1729,6 +1891,8 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
MergeEqualStateNeighbours(NewNode); MergeEqualStateNeighbours(NewNode);
BlockAllocator.Count += Blocks.Count - OldCount;
} }
private void MergeEqualStateNeighbours(LinkedListNode<KMemoryBlock> Node) private void MergeEqualStateNeighbours(LinkedListNode<KMemoryBlock> Node)

View file

@ -288,6 +288,8 @@ namespace Ryujinx.HLE.HOS.Kernel
FreePages(PageNode.Address, PageNode.PagesCount); FreePages(PageNode.Address, PageNode.PagesCount);
} }
PageList = null;
return KernelResult.OutOfMemory; return KernelResult.OutOfMemory;
} }

View file

@ -124,13 +124,18 @@ namespace Ryujinx.HLE.HOS.Kernel
ulong CodeSize = (ulong)CreationInfo.CodePagesCount * KMemoryManager.PageSize; ulong CodeSize = (ulong)CreationInfo.CodePagesCount * KMemoryManager.PageSize;
KMemoryBlockAllocator MemoryBlockAllocator = (MmuFlags & 0x40) != 0
? System.MemoryBlockAllocatorSys
: System.MemoryBlockAllocator2;
KernelResult Result = MemoryManager.InitializeForProcess( KernelResult Result = MemoryManager.InitializeForProcess(
AddrSpaceType, AddrSpaceType,
AslrEnabled, AslrEnabled,
!AslrEnabled, !AslrEnabled,
MemRegion, MemRegion,
CodeAddress, CodeAddress,
CodeSize); CodeSize,
MemoryBlockAllocator);
if (Result != KernelResult.Success) if (Result != KernelResult.Success)
{ {
@ -205,9 +210,17 @@ namespace Ryujinx.HLE.HOS.Kernel
PersonalMmHeapPagesCount = (ulong)CreationInfo.PersonalMmHeapPagesCount; PersonalMmHeapPagesCount = (ulong)CreationInfo.PersonalMmHeapPagesCount;
KMemoryBlockAllocator MemoryBlockAllocator;
if (PersonalMmHeapPagesCount != 0) 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); AddressSpaceType AddrSpaceType = (AddressSpaceType)((CreationInfo.MmuFlags >> 1) & 7);
@ -224,7 +237,8 @@ namespace Ryujinx.HLE.HOS.Kernel
!AslrEnabled, !AslrEnabled,
MemRegion, MemRegion,
CodeAddress, CodeAddress,
CodeSize); CodeSize,
MemoryBlockAllocator);
if (Result != KernelResult.Success) if (Result != KernelResult.Success)
{ {
@ -314,8 +328,8 @@ namespace Ryujinx.HLE.HOS.Kernel
return false; return false;
} }
if (MemoryManager.InsideHeapRegion(Address, Size) || if (MemoryManager.InsideHeapRegion (Address, Size) ||
MemoryManager.InsideAliasRegion (Address, Size)) MemoryManager.InsideAliasRegion(Address, Size))
{ {
return false; return false;
} }
@ -771,10 +785,14 @@ namespace Ryujinx.HLE.HOS.Kernel
public void IncrementThreadCount() public void IncrementThreadCount()
{ {
Interlocked.Increment(ref ThreadCount); Interlocked.Increment(ref ThreadCount);
System.ThreadCounter.AddCount();
} }
public void DecrementThreadCountAndTerminateIfZero() public void DecrementThreadCountAndTerminateIfZero()
{ {
System.ThreadCounter.Signal();
if (Interlocked.Decrement(ref ThreadCount) == 0) if (Interlocked.Decrement(ref ThreadCount) == 0)
{ {
Terminate(); Terminate();
@ -801,8 +819,7 @@ namespace Ryujinx.HLE.HOS.Kernel
public ulong GetMemoryUsage() public ulong GetMemoryUsage()
{ {
//TODO: Personal Mm Heap. return ImageSize + MainThreadStackSize + MemoryManager.GetTotalHeapSize() + GetPersonalMmHeapSize();
return ImageSize + MainThreadStackSize + MemoryManager.GetTotalHeapSize();
} }
public ulong GetMemoryCapacityWithoutPersonalMmHeap() public ulong GetMemoryCapacityWithoutPersonalMmHeap()
@ -895,7 +912,7 @@ namespace Ryujinx.HLE.HOS.Kernel
if (ShallTerminate) if (ShallTerminate)
{ {
UnpauseAndTerminateAllThreadsExcept(System.Scheduler.GetCurrentThread()); //UnpauseAndTerminateAllThreadsExcept(System.Scheduler.GetCurrentThread());
HandleTable.Destroy(); HandleTable.Destroy();
@ -955,6 +972,19 @@ namespace Ryujinx.HLE.HOS.Kernel
return Result; 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) private void CpuTraceHandler(object sender, EventArgs e)
{ {
System.Scheduler.GetCurrentThread().PrintGuestStackTrace(); System.Scheduler.GetCurrentThread().PrintGuestStackTrace();

View file

@ -7,6 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel
ThreadTerminating = 0x7601, ThreadTerminating = 0x7601,
InvalidSize = 0xca01, InvalidSize = 0xca01,
InvalidAddress = 0xcc01, InvalidAddress = 0xcc01,
OutOfResource = 0xce01,
OutOfMemory = 0xd001, OutOfMemory = 0xd001,
HandleTableFull = 0xd201, HandleTableFull = 0xd201,
InvalidMemState = 0xd401, InvalidMemState = 0xd401,

View file

@ -72,15 +72,15 @@ namespace Ryujinx.HLE.HOS.Kernel
return; return;
} }
long Result = Process.MemoryManager.SetMemoryAttribute( KernelResult Result = Process.MemoryManager.SetMemoryAttribute(
Position, Position,
Size, Size,
AttributeMask, AttributeMask,
AttributeValue); 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 else
{ {

View file

@ -221,6 +221,8 @@ namespace Ryujinx.HLE.HOS.Kernel
Message, Message,
MessagePtr)); MessagePtr));
System.ThreadCounter.AddCount();
System.CriticalSection.Leave(); System.CriticalSection.Leave();
ThreadState.X0 = (ulong)CurrentThread.ObjSyncResult; ThreadState.X0 = (ulong)CurrentThread.ObjSyncResult;
@ -245,6 +247,8 @@ namespace Ryujinx.HLE.HOS.Kernel
IpcMessage.Message, IpcMessage.Message,
IpcMessage.MessagePtr); IpcMessage.MessagePtr);
System.ThreadCounter.Signal();
IpcMessage.Thread.Reschedule(ThreadSchedState.Running); IpcMessage.Thread.Reschedule(ThreadSchedState.Running);
} }

View file

@ -151,6 +151,8 @@ namespace Ryujinx.HLE.HOS
return false; return false;
} }
System.Processes.AddLast(Process);
return true; return true;
} }
} }