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;
@ -67,12 +71,13 @@ namespace Ryujinx.HLE.HOS.Kernel
private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 }; private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
public KernelResult InitializeForProcess( public KernelResult InitializeForProcess(
AddressSpaceType AddrSpaceType, AddressSpaceType AddrSpaceType,
bool AslrEnabled, bool AslrEnabled,
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)
{ {
@ -111,14 +117,15 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
private KernelResult CreateUserAddressSpace( private KernelResult CreateUserAddressSpace(
AddressSpaceType AddrSpaceType, AddressSpaceType AddrSpaceType,
bool AslrEnabled, bool AslrEnabled,
bool AslrDisabled, bool AslrDisabled,
ulong AddrSpaceStart, ulong AddrSpaceStart,
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 long ResetTransferMemory(ulong Address, ulong Size) public KernelResult 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;
} }
} }