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 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<KProcess> 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<KProcess>();
|
||||
|
||||
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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
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.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<KMemoryBlock> 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<KMemoryBlock> NewNode = null;
|
||||
|
@ -1729,6 +1891,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
|
||||
MergeEqualStateNeighbours(NewNode);
|
||||
|
||||
BlockAllocator.Count += Blocks.Count - OldCount;
|
||||
}
|
||||
|
||||
private void MergeEqualStateNeighbours(LinkedListNode<KMemoryBlock> Node)
|
||||
|
|
|
@ -288,6 +288,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
FreePages(PageNode.Address, PageNode.PagesCount);
|
||||
}
|
||||
|
||||
PageList = null;
|
||||
|
||||
return KernelResult.OutOfMemory;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
ThreadTerminating = 0x7601,
|
||||
InvalidSize = 0xca01,
|
||||
InvalidAddress = 0xcc01,
|
||||
OutOfResource = 0xce01,
|
||||
OutOfMemory = 0xd001,
|
||||
HandleTableFull = 0xd201,
|
||||
InvalidMemState = 0xd401,
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -151,6 +151,8 @@ namespace Ryujinx.HLE.HOS
|
|||
return false;
|
||||
}
|
||||
|
||||
System.Processes.AddLast(Process);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue