Add checking for memory block slab heap usage, return errors if full, exit gracefully
This commit is contained in:
parent
bba8b4dbab
commit
dbcba511b2
10 changed files with 301 additions and 52 deletions
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
21
Ryujinx.HLE/HOS/Kernel/KMemoryBlockAllocator.cs
Normal file
21
Ryujinx.HLE/HOS/Kernel/KMemoryBlockAllocator.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,8 @@ namespace Ryujinx.HLE.HOS
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.Processes.AddLast(Process);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue