diff options
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel')
28 files changed, 750 insertions, 545 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs b/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs new file mode 100644 index 00000000..098d83d1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs @@ -0,0 +1,11 @@ +using System; + +namespace Ryujinx.HLE.HOS.Kernel.Common +{ + struct OnScopeExit : IDisposable + { + private readonly Action _action; + public OnScopeExit(Action action) => _action = action; + public void Dispose() => _action(); + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs index 0986adf7..fbd32845 100644 --- a/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs +++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs @@ -99,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc copySize, stateMask, stateMask, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, attributeMask, MemoryAttribute.None, desc.ServerAddress); @@ -125,7 +125,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc clientEndAddr - clientEndAddrTruncated, stateMask, stateMask, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, attributeMask, MemoryAttribute.None, serverEndAddrTruncated); diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs index 8d6669cf..c3b7d1dd 100644 --- a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs +++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs @@ -14,10 +14,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc public bool IsLight => _parent.IsLight; - // TODO: Remove that, we need it for now to allow HLE - // SM implementation to work with the new IPC system. - public IpcService Service { get; set; } - public KClientPort(KernelContext context, KPort parent, int maxSessions) : base(context) { _maxSessions = maxSessions; @@ -45,11 +41,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc KSession session = new KSession(KernelContext, this); - if (Service != null) - { - session.ClientSession.Service = Service; - } - KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession); if (result != KernelResult.Success) diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs index 2c2d9644..d535bf82 100644 --- a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs +++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs @@ -16,10 +16,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc public KClientPort ParentPort { get; } - // TODO: Remove that, we need it for now to allow HLE - // services implementation to work with the new IPC system. - public IpcService Service { get; set; } - public KClientSession(KernelContext context, KSession parent, KClientPort parentPort) : base(context) { _parent = parent; @@ -84,11 +80,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc { _parent.DisconnectClient(); _parent.DecrementReferenceCount(); - - if (Service is IDisposable disposableObj) - { - disposableObj.Dispose(); - } } } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs index 48669832..e9c6127f 100644 --- a/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs +++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs @@ -430,7 +430,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc descriptor.BufferAddress, MemoryState.IsPoolAllocated, MemoryState.IsPoolAllocated, - MemoryPermission.Read, + KMemoryPermission.Read, MemoryAttribute.Uncached, MemoryAttribute.None); @@ -473,9 +473,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc bool notReceiveDesc = isSendDesc || isExchangeDesc; bool isReceiveDesc = !notReceiveDesc; - MemoryPermission permission = index >= clientHeader.SendBuffersCount - ? MemoryPermission.ReadAndWrite - : MemoryPermission.Read; + KMemoryPermission permission = index >= clientHeader.SendBuffersCount + ? KMemoryPermission.ReadAndWrite + : KMemoryPermission.Read; uint sizeHigh4 = (descWord2 >> 24) & 0xf; @@ -559,9 +559,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc if (serverMsg.IsCustom || clientMsg.IsCustom) { - MemoryPermission permission = clientMsg.IsCustom - ? MemoryPermission.None - : MemoryPermission.Read; + KMemoryPermission permission = clientMsg.IsCustom + ? KMemoryPermission.None + : KMemoryPermission.Read; clientResult = clientProcess.MemoryManager.CopyDataToCurrentProcess( copyDst, @@ -795,7 +795,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc descriptor.BufferSize, MemoryState.IsPoolAllocated, MemoryState.IsPoolAllocated, - MemoryPermission.Read, + KMemoryPermission.Read, MemoryAttribute.Uncached, MemoryAttribute.None, descriptor.BufferAddress); @@ -849,9 +849,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc if (serverMsg.IsCustom || clientMsg.IsCustom) { - MemoryPermission permission = clientMsg.IsCustom - ? MemoryPermission.None - : MemoryPermission.Read; + KMemoryPermission permission = clientMsg.IsCustom + ? KMemoryPermission.None + : KMemoryPermission.Read; clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess( copyDst, @@ -898,11 +898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc return new MessageHeader(word0, word1, word2); } - private KernelResult GetCopyObjectHandle( - KThread srcThread, - KProcess dstProcess, - int srcHandle, - out int dstHandle) + private KernelResult GetCopyObjectHandle(KThread srcThread, KProcess dstProcess, int srcHandle, out int dstHandle) { dstHandle = 0; @@ -933,11 +929,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc } } - private KernelResult GetMoveObjectHandle( - KProcess srcProcess, - KProcess dstProcess, - int srcHandle, - out int dstHandle) + private KernelResult GetMoveObjectHandle(KProcess srcProcess, KProcess dstProcess, int srcHandle, out int dstHandle) { dstHandle = 0; diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs index 4b5886a9..d614857c 100644 --- a/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs +++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs @@ -4,7 +4,7 @@ using System; namespace Ryujinx.HLE.HOS.Kernel.Ipc { - class KSession : KAutoObject, IDisposable + class KSession : KAutoObject { public KServerSession ServerSession { get; } public KClientSession ClientSession { get; } @@ -37,19 +37,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc } } - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing && ClientSession.Service is IDisposable disposableService) - { - disposableService.Dispose(); - } - } - protected override void Destroy() { if (_hasBeenInitialized) diff --git a/Ryujinx.HLE/HOS/Kernel/KernelContext.cs b/Ryujinx.HLE/HOS/Kernel/KernelContext.cs index a2d8bc47..d19c43ee 100644 --- a/Ryujinx.HLE/HOS/Kernel/KernelContext.cs +++ b/Ryujinx.HLE/HOS/Kernel/KernelContext.cs @@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel Device = device; Memory = memory; - Syscall = new Syscall(device, this); + Syscall = new Syscall(this); SyscallHandler = new SyscallHandler(this); diff --git a/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs new file mode 100644 index 00000000..c7deadae --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs @@ -0,0 +1,38 @@ +using Ryujinx.HLE.HOS.Kernel.Threading; +using System; +using System.Threading.Tasks; + +namespace Ryujinx.HLE.HOS.Kernel +{ + static class KernelStatic + { + [ThreadStatic] + private static KernelContext Context; + + public static void YieldUntilCompletion(Action action) + { + YieldUntilCompletion(Task.Factory.StartNew(action)); + } + + public static void YieldUntilCompletion(Task task) + { + KThread currentThread = Context.Scheduler.GetCurrentThread(); + + Context.CriticalSection.Enter(); + + currentThread.Reschedule(ThreadSchedState.Paused); + + task.ContinueWith((antecedent) => + { + currentThread.Reschedule(ThreadSchedState.Running); + }); + + Context.CriticalSection.Leave(); + } + + internal static void SetKernelContext(KernelContext context) + { + Context = context; + } + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs index 04e14e1b..b93b68d9 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs @@ -8,9 +8,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory public ulong PagesCount { get; private set; } public MemoryState State { get; private set; } - public MemoryPermission Permission { get; private set; } + public KMemoryPermission Permission { get; private set; } public MemoryAttribute Attribute { get; private set; } - public MemoryPermission SourcePermission { get; private set; } + public KMemoryPermission SourcePermission { get; private set; } public int IpcRefCount { get; private set; } public int DeviceRefCount { get; private set; } @@ -19,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong baseAddress, ulong pagesCount, MemoryState state, - MemoryPermission permission, + KMemoryPermission permission, MemoryAttribute attribute, int ipcRefCount = 0, int deviceRefCount = 0) @@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory DeviceRefCount = deviceRefCount; } - public void SetState(MemoryPermission permission, MemoryState state, MemoryAttribute attribute) + public void SetState(KMemoryPermission permission, MemoryState state, MemoryAttribute attribute) { Permission = permission; State = state; @@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory Attribute |= attribute; } - public void SetIpcMappingPermission(MemoryPermission newPermission) + public void SetIpcMappingPermission(KMemoryPermission newPermission) { int oldIpcRefCount = IpcRefCount++; @@ -54,8 +54,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory { SourcePermission = Permission; - Permission &= ~MemoryPermission.ReadAndWrite; - Permission |= MemoryPermission.ReadAndWrite & newPermission; + Permission &= ~KMemoryPermission.ReadAndWrite; + Permission |= KMemoryPermission.ReadAndWrite & newPermission; } Attribute |= MemoryAttribute.IpcMapped; @@ -74,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory { Permission = SourcePermission; - SourcePermission = MemoryPermission.None; + SourcePermission = KMemoryPermission.None; Attribute &= ~MemoryAttribute.IpcMapped; } diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs index 21e9e494..af070ac2 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs @@ -6,9 +6,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory public ulong Size { get; } public MemoryState State { get; } - public MemoryPermission Permission { get; } + public KMemoryPermission Permission { get; } public MemoryAttribute Attribute { get; } - public MemoryPermission SourcePermission { get; } + public KMemoryPermission SourcePermission { get; } public int IpcRefCount { get; } public int DeviceRefCount { get; } @@ -17,9 +17,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong address, ulong size, MemoryState state, - MemoryPermission permission, + KMemoryPermission permission, MemoryAttribute attribute, - MemoryPermission sourcePermission, + KMemoryPermission sourcePermission, int ipcRefCount, int deviceRefCount) { diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs index 43e7ad69..63ac8583 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs @@ -1,9 +1,10 @@ using Ryujinx.Common; -using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.Memory; using System; using System.Collections.Generic; +using System.Diagnostics; namespace Ryujinx.HLE.HOS.Kernel.Memory { @@ -27,11 +28,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory // 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 readonly LinkedList<KMemoryBlock> _blocks; - private MemoryManager _cpuMemory; + private readonly IVirtualMemoryManager _cpuMemory; - private KernelContext _context; + private readonly KernelContext _context; public ulong AddrSpaceStart { get; private set; } public ulong AddrSpaceEnd { get; private set; } @@ -73,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory private MersenneTwister _randomNumberGenerator; - public KMemoryManager(KernelContext context, MemoryManager cpuMemory) + public KMemoryManager(KernelContext context, IVirtualMemoryManager cpuMemory) { _context = context; _cpuMemory = cpuMemory; @@ -352,7 +353,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory addrSpaceStart, addrSpacePagesCount, MemoryState.Unmapped, - MemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.None)); return KernelResult.Success; @@ -362,13 +363,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong address, KPageList pageList, MemoryState state, - MemoryPermission permission) + KMemoryPermission permission) { ulong pagesCount = pageList.GetPagesCount(); ulong size = pagesCount * PageSize; - if (!ValidateRegionForState(address, size, state)) + if (!CanContain(address, size, state)) { return KernelResult.InvalidMemState; } @@ -437,8 +438,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.Mask, stateExpected, - MemoryPermission.None, - MemoryPermission.None, + KMemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, @@ -467,13 +468,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } } - public KernelResult MapNormalMemory(long address, long size, MemoryPermission permission) + public KernelResult MapNormalMemory(long address, long size, KMemoryPermission permission) { // TODO. return KernelResult.Success; } - public KernelResult MapIoMemory(long address, long size, MemoryPermission permission) + public KernelResult MapIoMemory(long address, long size, KMemoryPermission permission) { // TODO. return KernelResult.Success; @@ -487,7 +488,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong regionStart, ulong regionPagesCount, MemoryState state, - MemoryPermission permission, + KMemoryPermission permission, out ulong address) { address = 0; @@ -496,7 +497,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong regionEndAddr = regionStart + regionSize; - if (!ValidateRegionForState(regionStart, regionSize, state)) + if (!CanContain(regionStart, regionSize, state)) { return KernelResult.InvalidMemState; } @@ -547,11 +548,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong address, ulong pagesCount, MemoryState state, - MemoryPermission permission) + KMemoryPermission permission) { ulong size = pagesCount * PageSize; - if (!ValidateRegionForState(address, size, state)) + if (!CanContain(address, size, state)) { return KernelResult.InvalidMemState; } @@ -596,13 +597,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.Mask, MemoryState.Heap, - MemoryPermission.Mask, - MemoryPermission.ReadAndWrite, + KMemoryPermission.Mask, + KMemoryPermission.ReadAndWrite, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, out MemoryState state, - out MemoryPermission permission, + out KMemoryPermission permission, out _); success &= IsUnmapped(dst, size); @@ -618,14 +619,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory AddVaRangeToPageList(pageList, src, pagesCount); - KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None); + KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None); if (result != KernelResult.Success) { return result; } - result = MapPages(dst, pageList, MemoryPermission.None); + result = MapPages(dst, pageList, KMemoryPermission.None); if (result != KernelResult.Success) { @@ -634,7 +635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return result; } - InsertBlock(src, pagesCount, state, MemoryPermission.None, MemoryAttribute.Borrowed); + InsertBlock(src, pagesCount, state, KMemoryPermission.None, MemoryAttribute.Borrowed); InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic); return KernelResult.Success; @@ -657,8 +658,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.Mask, MemoryState.Heap, - MemoryPermission.None, - MemoryPermission.None, + KMemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.Borrowed, MemoryAttribute.IpcAndDeviceMapped, @@ -671,8 +672,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory PageSize, MemoryState.UnmapProcessCodeMemoryAllowed, MemoryState.UnmapProcessCodeMemoryAllowed, - MemoryPermission.None, - MemoryPermission.None, + KMemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, @@ -685,8 +686,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.Mask, state, - MemoryPermission.None, - MemoryPermission.None, + KMemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.None); @@ -707,7 +708,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } InsertBlock(dst, pagesCount, MemoryState.Unmapped); - InsertBlock(src, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite); + InsertBlock(src, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite); return KernelResult.Success; } @@ -788,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory _currentHeapAddr, pagesCount, pageList, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, MemoryOperation.MapVa); if (result != KernelResult.Success) @@ -798,7 +799,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return result; } - InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite); + InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite); } else { @@ -816,8 +817,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory sizeDelta, MemoryState.Mask, MemoryState.Heap, - MemoryPermission.Mask, - MemoryPermission.ReadAndWrite, + KMemoryPermission.Mask, + KMemoryPermission.ReadAndWrite, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, @@ -886,13 +887,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.AttributeChangeAllowed, MemoryState.AttributeChangeAllowed, - MemoryPermission.None, - MemoryPermission.None, + KMemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.BorrowedAndIpcMapped, MemoryAttribute.None, MemoryAttribute.DeviceMappedAndUncached, out MemoryState state, - out MemoryPermission permission, + out KMemoryPermission permission, out MemoryAttribute attribute)) { if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) @@ -932,9 +933,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory AddrSpaceEnd, ~AddrSpaceEnd + 1, MemoryState.Reserved, - MemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.None, - MemoryPermission.None, + KMemoryPermission.None, 0, 0); } @@ -951,8 +952,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.MapAllowed, MemoryState.MapAllowed, - MemoryPermission.Mask, - MemoryPermission.ReadAndWrite, + KMemoryPermission.Mask, + KMemoryPermission.ReadAndWrite, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, @@ -975,18 +976,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory AddVaRangeToPageList(pageList, src, pagesCount); - KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None); + KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None); if (result != KernelResult.Success) { return result; } - result = MapPages(dst, pageList, MemoryPermission.ReadAndWrite); + result = MapPages(dst, pageList, KMemoryPermission.ReadAndWrite); if (result != KernelResult.Success) { - if (MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite) != KernelResult.Success) + if (MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite) != KernelResult.Success) { throw new InvalidOperationException("Unexpected failure reverting memory permission."); } @@ -994,8 +995,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return result; } - InsertBlock(src, pagesCount, srcState, MemoryPermission.None, MemoryAttribute.Borrowed); - InsertBlock(dst, pagesCount, MemoryState.Stack, MemoryPermission.ReadAndWrite); + InsertBlock(src, pagesCount, srcState, KMemoryPermission.None, MemoryAttribute.Borrowed); + InsertBlock(dst, pagesCount, MemoryState.Stack, KMemoryPermission.ReadAndWrite); return KernelResult.Success; } @@ -1017,8 +1018,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.Mask, stateExpected, - MemoryPermission.None, - MemoryPermission.None, + KMemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, @@ -1058,8 +1059,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.MapAllowed, MemoryState.MapAllowed, - MemoryPermission.Mask, - MemoryPermission.None, + KMemoryPermission.Mask, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.Borrowed, MemoryAttribute.IpcAndDeviceMapped, @@ -1072,13 +1073,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.Mask, MemoryState.Stack, - MemoryPermission.None, - MemoryPermission.None, + KMemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, out _, - out MemoryPermission dstPermission, + out KMemoryPermission dstPermission, out _); if (success) @@ -1108,7 +1109,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return result; } - result = MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite); + result = MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite); if (result != KernelResult.Success) { @@ -1117,7 +1118,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return result; } - InsertBlock(src, pagesCount, srcState, MemoryPermission.ReadAndWrite); + InsertBlock(src, pagesCount, srcState, KMemoryPermission.ReadAndWrite); InsertBlock(dst, pagesCount, MemoryState.Unmapped); return KernelResult.Success; @@ -1129,7 +1130,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } } - public KernelResult SetProcessMemoryPermission(ulong address, ulong size, MemoryPermission permission) + public KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission) { lock (_blocks) { @@ -1138,20 +1139,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.ProcessPermissionChangeAllowed, MemoryState.ProcessPermissionChangeAllowed, - MemoryPermission.None, - MemoryPermission.None, + KMemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, out MemoryState oldState, - out MemoryPermission oldPermission, + out KMemoryPermission oldPermission, out _)) { MemoryState newState = oldState; // If writing into the code region is allowed, then we need // to change it to mutable. - if ((permission & MemoryPermission.Write) != 0) + if ((permission & KMemoryPermission.Write) != 0) { if (oldState == MemoryState.CodeStatic) { @@ -1176,7 +1177,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong pagesCount = size / PageSize; - MemoryOperation operation = (permission & MemoryPermission.Execute) != 0 + MemoryOperation operation = (permission & KMemoryPermission.Execute) != 0 ? MemoryOperation.ChangePermsAndAttributes : MemoryOperation.ChangePermRw; @@ -1270,10 +1271,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory address, pagesCount, MemoryState.Unmapped, - MemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.None, MemoryState.Heap, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, MemoryAttribute.None); } @@ -1410,7 +1411,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory pagesCount, srcPa, true, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, MemoryOperation.MapPa); dstVa += pagesCount * PageSize; @@ -1428,7 +1429,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong src, MemoryState stateMask, MemoryState stateExpected, - MemoryPermission permission, + KMemoryPermission permission, MemoryAttribute attributeMask, MemoryAttribute attributeExpected) { @@ -1450,7 +1451,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong size, MemoryState stateMask, MemoryState stateExpected, - MemoryPermission permission, + KMemoryPermission permission, MemoryAttribute attributeMask, MemoryAttribute attributeExpected, ulong src) @@ -1474,7 +1475,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong serverAddress, MemoryState stateMask, MemoryState stateExpected, - MemoryPermission permission, + KMemoryPermission permission, MemoryAttribute attributeMask, MemoryAttribute attributeExpected, bool toServer) @@ -1529,7 +1530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong size, ulong src, KMemoryManager sourceMemMgr, - MemoryPermission permission, + KMemoryPermission permission, MemoryState state, bool copyData, out ulong dst) @@ -1568,7 +1569,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory private KernelResult GetPagesForMappingIntoAnotherProcess( ulong address, ulong size, - MemoryPermission permission, + KMemoryPermission permission, MemoryState state, bool copyData, bool aslrDisabled, @@ -1600,9 +1601,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory default: return KernelResult.InvalidCombination; } - MemoryPermission permissionMask = permission == MemoryPermission.ReadAndWrite - ? MemoryPermission.None - : MemoryPermission.Read; + KMemoryPermission permissionMask = permission == KMemoryPermission.ReadAndWrite + ? KMemoryPermission.None + : KMemoryPermission.Read; MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached; @@ -1634,7 +1635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrVisited)) { - if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0) + if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0) { ulong blockAddress = GetAddrInRange(info, addressRounded); ulong blockSize = GetSizeInRange(info, addressRounded, endAddrVisited); @@ -1661,7 +1662,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory if (addressRounded < endAddrTruncated) { - foreach (KMemoryInfo info in IterateOverRange(addressTruncated, endAddrRounded)) + foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrTruncated)) { // Check if the block state matches what we expect. if ((info.State & stateMask) != stateMask || @@ -1678,7 +1679,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong blockPagesCount = blockSize / PageSize; - if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0) + if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0) { result = DoMmuOperation( blockAddress, @@ -1784,7 +1785,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory { ulong unusedSizeBefore = address - addressTruncated; - _context.Memory.ZeroFill(dstFirstPagePa, unusedSizeBefore); + _context.Memory.ZeroFill(GetDramAddressFromPa(dstFirstPagePa), unusedSizeBefore); ulong copySize = addressRounded <= endAddr ? addressRounded - address : size; @@ -1803,7 +1804,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory if (unusedSizeAfter != 0) { - _context.Memory.ZeroFill(firstPageFillAddress, unusedSizeAfter); + _context.Memory.ZeroFill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter); } if (pages.AddRange(dstFirstPagePa, 1) != KernelResult.Success) @@ -1865,7 +1866,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory unusedSizeAfter = PageSize; } - _context.Memory.ZeroFill(lastPageFillAddr, unusedSizeAfter); + _context.Memory.ZeroFill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter); if (pages.AddRange(dstLastPagePa, 1) != KernelResult.Success) { @@ -1897,7 +1898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory private KernelResult MapPagesFromAnotherProcess( ulong size, ulong address, - MemoryPermission permission, + KMemoryPermission permission, MemoryState state, KPageList pageList, out ulong dst) @@ -1975,8 +1976,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.Mask, state, - MemoryPermission.Read, - MemoryPermission.Read, + KMemoryPermission.Read, + KMemoryPermission.Read, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, @@ -1996,14 +1997,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong pagesCount = (endAddrRounded - addressTruncated) / PageSize; - KernelResult result = DoMmuOperation( - addressTruncated, - pagesCount, - 0, - false, - MemoryPermission.None, - MemoryOperation.Unmap); - // Free pages we had to create on-demand, if any of the buffer was not page aligned. // Real kernel has page ref counting, so this is done as part of the unmap operation. if (addressTruncated != addressRounded) @@ -2016,6 +2009,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory FreeSinglePage(_memRegion, ConvertVaToPa(endAddrTruncated)); } + KernelResult result = DoMmuOperation( + addressTruncated, + pagesCount, + 0, + false, + KMemoryPermission.None, + MemoryOperation.Unmap); + if (result == KernelResult.Success) { InsertBlock(addressTruncated, pagesCount, MemoryState.Unmapped); @@ -2037,7 +2038,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong addressRounded = BitUtils.AlignUp (address, PageSize); ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize); - ulong pagesCount = (endAddrTruncated - addressRounded) / PageSize; + ulong pagesCount = addressRounded < endAddrTruncated ? (endAddrTruncated - addressRounded) / PageSize : 0; + + if (pagesCount == 0) + { + return KernelResult.Success; + } MemoryState stateMask; @@ -2111,23 +2117,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.IpcBufferAllowed, MemoryState.IpcBufferAllowed, - MemoryPermission.Mask, - MemoryPermission.ReadAndWrite, + KMemoryPermission.Mask, + KMemoryPermission.ReadAndWrite, MemoryAttribute.Mask, MemoryAttribute.None, - MemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.Borrowed); } - public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, MemoryPermission permission) + public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, KMemoryPermission permission) { return SetAttributesAndChangePermission( address, size, MemoryState.TransferMemoryAllowed, MemoryState.TransferMemoryAllowed, - MemoryPermission.Mask, - MemoryPermission.ReadAndWrite, + KMemoryPermission.Mask, + KMemoryPermission.ReadAndWrite, MemoryAttribute.Mask, MemoryAttribute.None, permission, @@ -2140,11 +2146,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong size, MemoryState stateMask, MemoryState stateExpected, - MemoryPermission permissionMask, - MemoryPermission permissionExpected, + KMemoryPermission permissionMask, + KMemoryPermission permissionExpected, MemoryAttribute attributeMask, MemoryAttribute attributeExpected, - MemoryPermission newPermission, + KMemoryPermission newPermission, MemoryAttribute attributeSetMask, KPageList pageList = null) { @@ -2166,7 +2172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory attributeExpected, MemoryAttribute.IpcAndDeviceMapped, out MemoryState oldState, - out MemoryPermission oldPermission, + out KMemoryPermission oldPermission, out MemoryAttribute oldAttribute)) { ulong pagesCount = size / PageSize; @@ -2181,7 +2187,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return KernelResult.OutOfResource; } - if (newPermission == MemoryPermission.None) + if (newPermission == KMemoryPermission.None) { newPermission = oldPermission; } @@ -2222,11 +2228,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.IpcBufferAllowed, MemoryState.IpcBufferAllowed, - MemoryPermission.None, - MemoryPermission.None, + KMemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.Borrowed, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, MemoryAttribute.Borrowed); } @@ -2237,11 +2243,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.TransferMemoryAllowed, MemoryState.TransferMemoryAllowed, - MemoryPermission.None, - MemoryPermission.None, + KMemoryPermission.None, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.Borrowed, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, MemoryAttribute.Borrowed, pageList); } @@ -2251,11 +2257,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong size, MemoryState stateMask, MemoryState stateExpected, - MemoryPermission permissionMask, - MemoryPermission permissionExpected, + KMemoryPermission permissionMask, + KMemoryPermission permissionExpected, MemoryAttribute attributeMask, MemoryAttribute attributeExpected, - MemoryPermission newPermission, + KMemoryPermission newPermission, MemoryAttribute attributeClearMask, KPageList pageList = null) { @@ -2277,7 +2283,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory attributeExpected, MemoryAttribute.IpcAndDeviceMapped, out MemoryState oldState, - out MemoryPermission oldPermission, + out KMemoryPermission oldPermission, out MemoryAttribute oldAttribute)) { ulong pagesCount = size / PageSize; @@ -2299,7 +2305,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return KernelResult.OutOfResource; } - if (newPermission == MemoryPermission.None) + if (newPermission == KMemoryPermission.None) { newPermission = oldPermission; } @@ -2385,8 +2391,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory size, MemoryState.Mask, MemoryState.Unmapped, - MemoryPermission.Mask, - MemoryPermission.None, + KMemoryPermission.Mask, + KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.None, MemoryAttribute.IpcAndDeviceMapped, @@ -2400,13 +2406,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong size, MemoryState stateMask, MemoryState stateExpected, - MemoryPermission permissionMask, - MemoryPermission permissionExpected, + KMemoryPermission permissionMask, + KMemoryPermission permissionExpected, MemoryAttribute attributeMask, MemoryAttribute attributeExpected, MemoryAttribute attributeIgnoreMask, out MemoryState outState, - out MemoryPermission outPermission, + out KMemoryPermission outPermission, out MemoryAttribute outAttribute) { ulong endAddr = address + size; @@ -2416,7 +2422,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory KMemoryInfo info = node.Value.GetInfo(); MemoryState firstState = info.State; - MemoryPermission firstPermission = info.Permission; + KMemoryPermission firstPermission = info.Permission; MemoryAttribute firstAttribute = info.Attribute; do @@ -2432,7 +2438,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory (firstPermission & permissionMask) != permissionExpected) { outState = MemoryState.Unmapped; - outPermission = MemoryPermission.None; + outPermission = KMemoryPermission.None; outAttribute = MemoryAttribute.None; return false; @@ -2452,8 +2458,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong size, MemoryState stateMask, MemoryState stateExpected, - MemoryPermission permissionMask, - MemoryPermission permissionExpected, + KMemoryPermission permissionMask, + KMemoryPermission permissionExpected, MemoryAttribute attributeMask, MemoryAttribute attributeExpected) { @@ -2490,10 +2496,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong baseAddress, ulong pagesCount, MemoryState oldState, - MemoryPermission oldPermission, + KMemoryPermission oldPermission, MemoryAttribute oldAttribute, MemoryState newState, - MemoryPermission newPermission, + KMemoryPermission newPermission, MemoryAttribute newAttribute) { // Insert new block on the list only on areas where the state @@ -2553,13 +2559,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } _blockAllocator.Count += _blocks.Count - oldCount; + + ValidateInternalState(); } private void InsertBlock( ulong baseAddress, ulong pagesCount, MemoryState state, - MemoryPermission permission = MemoryPermission.None, + KMemoryPermission permission = KMemoryPermission.None, MemoryAttribute attribute = MemoryAttribute.None) { // Inserts new block at the list, replacing and splitting @@ -2605,25 +2613,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } _blockAllocator.Count += _blocks.Count - oldCount; + + ValidateInternalState(); } - private static void SetIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission) + private static void SetIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission) { block.SetIpcMappingPermission(permission); } - private static void RestoreIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission) + private static void RestoreIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission) { block.RestoreIpcMappingPermission(); } - private delegate void BlockMutator(KMemoryBlock block, MemoryPermission newPerm); + private delegate void BlockMutator(KMemoryBlock block, KMemoryPermission newPerm); private void InsertBlock( ulong baseAddress, ulong pagesCount, BlockMutator blockMutate, - MemoryPermission permission = MemoryPermission.None) + KMemoryPermission permission = KMemoryPermission.None) { // Inserts new block at the list, replacing and splitting // existing blocks as needed, then calling the callback @@ -2671,6 +2681,31 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } _blockAllocator.Count += _blocks.Count - oldCount; + + ValidateInternalState(); + } + + [Conditional("DEBUG")] + private void ValidateInternalState() + { + ulong expectedAddress = 0; + + LinkedListNode<KMemoryBlock> node = _blocks.First; + + while (node != null) + { + LinkedListNode<KMemoryBlock> newNode = node; + + KMemoryBlock currBlock = node.Value; + + Debug.Assert(currBlock.BaseAddress == expectedAddress); + + expectedAddress = currBlock.BaseAddress + currBlock.PagesCount * PageSize; + + node = newNode.Next; + } + + Debug.Assert(expectedAddress == AddrSpaceEnd); } private LinkedListNode<KMemoryBlock> MergeEqualStateNeighbors(LinkedListNode<KMemoryBlock> node) @@ -2876,13 +2911,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return null; } - private bool ValidateRegionForState(ulong address, ulong size, MemoryState state) + public bool CanContain(ulong address, ulong size, MemoryState state) { ulong endAddr = address + size; - ulong regionBaseAddr = GetBaseAddrForState(state); - - ulong regionEndAddr = regionBaseAddr + GetSizeForState(state); + ulong regionBaseAddr = GetBaseAddress(state); + ulong regionEndAddr = regionBaseAddr + GetSize(state); bool InsideRegion() { @@ -2891,17 +2925,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory endAddr - 1 <= regionEndAddr - 1; } - bool OutsideHeapRegion() - { - return endAddr <= HeapRegionStart || - address >= HeapRegionEnd; - } - - bool OutsideMapRegion() - { - return endAddr <= AliasRegionStart || - address >= AliasRegionEnd; - } + bool OutsideHeapRegion() => endAddr <= HeapRegionStart || address >= HeapRegionEnd; + bool OutsideAliasRegion() => endAddr <= AliasRegionStart || address >= AliasRegionEnd; switch (state) { @@ -2919,10 +2944,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory case MemoryState.ProcessMemory: case MemoryState.CodeReadOnly: case MemoryState.CodeWritable: - return InsideRegion() && OutsideHeapRegion() && OutsideMapRegion(); + return InsideRegion() && OutsideHeapRegion() && OutsideAliasRegion(); case MemoryState.Heap: - return InsideRegion() && OutsideMapRegion(); + return InsideRegion() && OutsideAliasRegion(); case MemoryState.IpcBuffer0: case MemoryState.IpcBuffer1: @@ -2936,7 +2961,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory throw new ArgumentException($"Invalid state value \"{state}\"."); } - private ulong GetBaseAddrForState(MemoryState state) + private ulong GetBaseAddress(MemoryState state) { switch (state) { @@ -2975,7 +3000,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory throw new ArgumentException($"Invalid state value \"{state}\"."); } - private ulong GetSizeForState(MemoryState state) + private ulong GetSize(MemoryState state) { switch (state) { @@ -3050,7 +3075,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } } - private KernelResult MapPages(ulong address, KPageList pageList, MemoryPermission permission) + private KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission) { ulong currAddr = address; @@ -3090,11 +3115,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory pagesCount, 0, false, - MemoryPermission.None, + KMemoryPermission.None, MemoryOperation.Unmap); } - private KernelResult MmuChangePermission(ulong address, ulong pagesCount, MemoryPermission permission) + private KernelResult MmuChangePermission(ulong address, ulong pagesCount, KMemoryPermission permission) { return DoMmuOperation( address, @@ -3110,7 +3135,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong pagesCount, ulong srcPa, bool map, - MemoryPermission permission, + KMemoryPermission permission, MemoryOperation operation) { if (map != (operation == MemoryOperation.MapPa)) @@ -3171,7 +3196,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong address, ulong pagesCount, KPageList pageList, - MemoryPermission permission, + KMemoryPermission permission, MemoryOperation operation) { if (operation != MemoryOperation.MapVa) diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs index 65134f0d..ca0e3421 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs @@ -10,15 +10,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory private readonly long _ownerPid; - private readonly MemoryPermission _ownerPermission; - private readonly MemoryPermission _userPermission; + private readonly KMemoryPermission _ownerPermission; + private readonly KMemoryPermission _userPermission; public KSharedMemory( KernelContext context, KPageList pageList, long ownerPid, - MemoryPermission ownerPermission, - MemoryPermission userPermission) : base(context) + KMemoryPermission ownerPermission, + KMemoryPermission userPermission) : base(context) { _pageList = pageList; _ownerPid = ownerPid; @@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong address, ulong size, KProcess process, - MemoryPermission permission) + KMemoryPermission permission) { ulong pagesCountRounded = BitUtils.DivRoundUp(size, KMemoryManager.PageSize); @@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return KernelResult.InvalidSize; } - MemoryPermission expectedPermission = process.Pid == _ownerPid + KMemoryPermission expectedPermission = process.Pid == _ownerPid ? _ownerPermission : _userPermission; diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs index d3e6208e..96349452 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs @@ -8,12 +8,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory { private KProcess _creator; + // TODO: Remove when we no longer need to read it from the owner directly. + public KProcess Creator => _creator; + private readonly KPageList _pageList; public ulong Address { get; private set; } public ulong Size => _pageList.GetPagesCount() * KMemoryManager.PageSize; - public MemoryPermission Permission { get; private set; } + public KMemoryPermission Permission { get; private set; } private bool _hasBeenInitialized; private bool _isMapped; @@ -23,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory _pageList = new KPageList(); } - public KernelResult Initialize(ulong address, ulong size, MemoryPermission permission) + public KernelResult Initialize(ulong address, ulong size, KMemoryPermission permission) { KProcess creator = KernelContext.Scheduler.GetCurrentProcess(); diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs b/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs index 0ad90abd..8bfd8d94 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs @@ -3,7 +3,7 @@ using System; namespace Ryujinx.HLE.HOS.Kernel.Memory { [Flags] - enum MemoryPermission : byte + enum KMemoryPermission : byte { None = 0, Mask = 0xff, diff --git a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs index 376badfb..5ad33154 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs @@ -1,7 +1,7 @@ -using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Diagnostics.Demangler; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.Loaders.Elf; +using Ryujinx.Memory; using System.Collections.Generic; using System.Linq; using System.Text; @@ -224,7 +224,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process break; } - if (info.State == MemoryState.CodeStatic && info.Permission == MemoryPermission.ReadAndExecute) + if (info.State == MemoryState.CodeStatic && info.Permission == KMemoryPermission.ReadAndExecute) { LoadMod0Symbols(_owner.CpuMemory, info.Address); } @@ -235,7 +235,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process } } - private void LoadMod0Symbols(MemoryManager memory, ulong textOffset) + private void LoadMod0Symbols(IVirtualMemoryManager memory, ulong textOffset) { ulong mod0Offset = textOffset + memory.Read<uint>(textOffset + 4); @@ -319,7 +319,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process } } - private ElfSymbol GetSymbol64(MemoryManager memory, ulong address, ulong strTblAddr) + private ElfSymbol GetSymbol64(IVirtualMemoryManager memory, ulong address, ulong strTblAddr) { ElfSymbol64 sym = memory.Read<ElfSymbol64>(address); @@ -335,7 +335,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size); } - private ElfSymbol GetSymbol32(MemoryManager memory, ulong address, ulong strTblAddr) + private ElfSymbol GetSymbol32(IVirtualMemoryManager memory, ulong address, ulong strTblAddr) { ElfSymbol32 sym = memory.Read<ElfSymbol32>(address); diff --git a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs new file mode 100644 index 00000000..758ac6b1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs @@ -0,0 +1,13 @@ +using ARMeilleure.State; +using Ryujinx.Memory; +using System; + +namespace Ryujinx.HLE.HOS.Kernel.Process +{ + interface IProcessContext : IDisposable + { + IVirtualMemoryManager AddressSpace { get; } + + void Execute(ExecutionContext context, ulong codeAddress); + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs new file mode 100644 index 00000000..c438b570 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs @@ -0,0 +1,10 @@ +using Ryujinx.Cpu; +using Ryujinx.Memory; + +namespace Ryujinx.HLE.HOS.Kernel.Process +{ + interface IProcessContextFactory + { + IProcessContext Create(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler); + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs index d02e25a3..8e914f19 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs @@ -6,6 +6,7 @@ using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Memory; using System; using System.Collections.Generic; using System.Linq; @@ -15,13 +16,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { class KProcess : KSynchronizationObject { - public const int KernelVersionMajor = 10; - public const int KernelVersionMinor = 4; + public const int KernelVersionMajor = 10; + public const int KernelVersionMinor = 4; public const int KernelVersionRevision = 0; public const int KernelVersionPacked = - (KernelVersionMajor << 19) | - (KernelVersionMinor << 15) | + (KernelVersionMajor << 19) | + (KernelVersionMinor << 15) | (KernelVersionRevision << 0); public KMemoryManager MemoryManager { get; private set; } @@ -47,27 +48,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public long[] RandomEntropy { get; private set; } private bool _signaled; - private bool _useSystemMemBlocks; public string Name { get; private set; } private int _threadCount; - public int MmuFlags { get; private set; } + public ProcessCreationFlags Flags { get; private set; } private MemoryRegion _memRegion; public KProcessCapabilities Capabilities { get; private set; } public ulong TitleId { get; private set; } - public long Pid { get; private set; } + public long Pid { get; private set; } - private long _creationTimestamp; + private long _creationTimestamp; private ulong _entrypoint; + private ThreadStart _customThreadStart; private ulong _imageSize; private ulong _mainThreadStackSize; private ulong _memoryUsageCapacity; - private int _version; + private int _version; public KHandleTable HandleTable { get; private set; } @@ -77,14 +78,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public bool IsPaused { get; private set; } - public MemoryManager CpuMemory { get; private set; } - public CpuContext CpuContext { get; private set; } + private IProcessContextFactory _contextFactory; + public IProcessContext Context { get; private set; } + public IVirtualMemoryManager CpuMemory => Context.AddressSpace; public HleProcessDebugger Debugger { get; private set; } public KProcess(KernelContext context) : base(context) { - _processLock = new object(); + _processLock = new object(); _threadingLock = new object(); AddressArbiter = new KAddressArbiter(context); @@ -96,6 +98,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process RandomEntropy = new long[KScheduler.CpuCoresCount]; + // TODO: Remove once we no longer need to initialize it externally. + HandleTable = new KHandleTable(context); + _threads = new LinkedList<KThread>(); Debugger = new HleProcessDebugger(this); @@ -103,25 +108,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public KernelResult InitializeKip( ProcessCreationInfo creationInfo, - int[] caps, - KPageList pageList, - KResourceLimit resourceLimit, - MemoryRegion memRegion) + ReadOnlySpan<int> capabilities, + KPageList pageList, + KResourceLimit resourceLimit, + MemoryRegion memRegion, + IProcessContextFactory contextFactory) { ResourceLimit = resourceLimit; - _memRegion = memRegion; + _memRegion = memRegion; + _contextFactory = contextFactory ?? new ProcessContextFactory(); - AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7); + AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift); - InitializeMemoryManager(addrSpaceType, memRegion); + InitializeMemoryManager(creationInfo.Flags); - bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0; + bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr); ulong codeAddress = creationInfo.CodeAddress; ulong codeSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize; - KMemoryBlockAllocator memoryBlockAllocator = (MmuFlags & 0x40) != 0 + KMemoryBlockAllocator memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication) ? KernelContext.LargeMemoryBlockAllocator : KernelContext.SmallMemoryBlockAllocator; @@ -139,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return result; } - if (!ValidateCodeAddressAndSize(codeAddress, codeSize)) + if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic)) { return KernelResult.InvalidMemRange; } @@ -148,14 +155,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process codeAddress, pageList, MemoryState.CodeStatic, - MemoryPermission.None); + KMemoryPermission.None); if (result != KernelResult.Success) { return result; } - result = Capabilities.InitializeForKernel(caps, MemoryManager); + result = Capabilities.InitializeForKernel(capabilities, MemoryManager); if (result != KernelResult.Success) { @@ -176,14 +183,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public KernelResult Initialize( ProcessCreationInfo creationInfo, - int[] caps, - KResourceLimit resourceLimit, - MemoryRegion memRegion) + ReadOnlySpan<int> capabilities, + KResourceLimit resourceLimit, + MemoryRegion memRegion, + IProcessContextFactory contextFactory, + ThreadStart customThreadStart = null) { ResourceLimit = resourceLimit; - _memRegion = memRegion; + _memRegion = memRegion; + _contextFactory = contextFactory ?? new ProcessContextFactory(); - ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.PersonalMmHeapPagesCount, memRegion); + ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.SystemResourcePagesCount, memRegion); ulong codePagesCount = (ulong)creationInfo.CodePagesCount; @@ -205,7 +215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process } } - PersonalMmHeapPagesCount = (ulong)creationInfo.PersonalMmHeapPagesCount; + PersonalMmHeapPagesCount = (ulong)creationInfo.SystemResourcePagesCount; KMemoryBlockAllocator memoryBlockAllocator; @@ -215,16 +225,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Process } else { - memoryBlockAllocator = (MmuFlags & 0x40) != 0 + memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication) ? KernelContext.LargeMemoryBlockAllocator : KernelContext.SmallMemoryBlockAllocator; } - AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7); + AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift); - InitializeMemoryManager(addrSpaceType, memRegion); + InitializeMemoryManager(creationInfo.Flags); - bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0; + bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr); ulong codeAddress = creationInfo.CodeAddress; @@ -246,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return result; } - if (!ValidateCodeAddressAndSize(codeAddress, codeSize)) + if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic)) { CleanUpForError(); @@ -257,7 +267,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process codeAddress, codePagesCount, MemoryState.CodeStatic, - MemoryPermission.None); + KMemoryPermission.None); if (result != KernelResult.Success) { @@ -266,7 +276,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return result; } - result = Capabilities.InitializeForUser(caps, MemoryManager); + result = Capabilities.InitializeForUser(capabilities, MemoryManager); if (result != KernelResult.Success) { @@ -289,57 +299,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process CleanUpForError(); } - return result; - } - - private bool ValidateCodeAddressAndSize(ulong address, ulong size) - { - ulong codeRegionStart; - ulong codeRegionSize; - - switch (MemoryManager.AddrSpaceWidth) - { - case 32: - codeRegionStart = 0x200000; - codeRegionSize = 0x3fe00000; - break; - - case 36: - codeRegionStart = 0x8000000; - codeRegionSize = 0x78000000; - break; - - case 39: - codeRegionStart = 0x8000000; - codeRegionSize = 0x7ff8000000; - break; - - default: throw new InvalidOperationException("Invalid address space width on memory manager."); - } - - ulong endAddr = address + size; - - ulong codeRegionEnd = codeRegionStart + codeRegionSize; - - if (endAddr <= address || - endAddr - 1 > codeRegionEnd - 1) - { - return false; - } - - if (MemoryManager.InsideHeapRegion (address, size) || - MemoryManager.InsideAliasRegion(address, size)) - { - return false; - } + _customThreadStart = customThreadStart; - return true; + return result; } private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo) { // Ensure that the current kernel version is equal or above to the minimum required. - uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19; + uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19; uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf; if (KernelContext.EnableVersionChecks) @@ -377,31 +345,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process _creationTimestamp = PerformanceCounter.ElapsedMilliseconds; - MmuFlags = creationInfo.MmuFlags; - _version = creationInfo.Version; - TitleId = creationInfo.TitleId; + Flags = creationInfo.Flags; + _version = creationInfo.Version; + TitleId = creationInfo.TitleId; _entrypoint = creationInfo.CodeAddress; - _imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize; - - _useSystemMemBlocks = ((MmuFlags >> 6) & 1) != 0; + _imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize; - switch ((AddressSpaceType)((MmuFlags >> 1) & 7)) + switch (Flags & ProcessCreationFlags.AddressSpaceMask) { - case AddressSpaceType.Addr32Bits: - case AddressSpaceType.Addr36Bits: - case AddressSpaceType.Addr39Bits: + case ProcessCreationFlags.AddressSpace32Bit: + case ProcessCreationFlags.AddressSpace64BitDeprecated: + case ProcessCreationFlags.AddressSpace64Bit: _memoryUsageCapacity = MemoryManager.HeapRegionEnd - MemoryManager.HeapRegionStart; break; - case AddressSpaceType.Addr32BitsNoMap: + case ProcessCreationFlags.AddressSpace32BitWithoutAlias: _memoryUsageCapacity = MemoryManager.HeapRegionEnd - MemoryManager.HeapRegionStart + MemoryManager.AliasRegionEnd - MemoryManager.AliasRegionStart; break; - default: throw new InvalidOperationException($"Invalid MMU flags value 0x{MmuFlags:x2}."); + default: throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}."); } GenerateRandomEntropy(); @@ -469,7 +435,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process } ulong regionStart = MemoryManager.TlsIoRegionStart; - ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart; + ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart; ulong regionPagesCount = regionSize / KMemoryManager.PageSize; @@ -481,7 +447,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process regionStart, regionPagesCount, MemoryState.ThreadLocal, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, out ulong tlsPageVa); if (result != KernelResult.Success) @@ -506,7 +472,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process KernelResult result = KernelResult.Success; - KTlsPageInfo pageInfo = null; + KTlsPageInfo pageInfo; if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo)) { @@ -594,8 +560,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process // Check if the needed size for the code and the stack will fit on the // memory usage capacity of this Process. Also check for possible overflow // on the above addition. - if (neededSize > _memoryUsageCapacity || - neededSize < stackSizeRounded) + if (neededSize > _memoryUsageCapacity || neededSize < stackSizeRounded) { threadResourceLimit?.Release(LimitableResource.Thread, 1); @@ -646,7 +611,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize; ulong regionStart = MemoryManager.StackRegionStart; - ulong regionSize = MemoryManager.StackRegionEnd - regionStart; + ulong regionSize = MemoryManager.StackRegionEnd - regionStart; ulong regionPagesCount = regionSize / KMemoryManager.PageSize; @@ -658,7 +623,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process regionStart, regionPagesCount, MemoryState.Stack, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, out ulong stackBottom); if (result != KernelResult.Success) @@ -703,7 +668,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process stackTop, mainThreadPriority, DefaultCpuCore, - this); + this, + ThreadType.User, + _customThreadStart); if (result != KernelResult.Success) { @@ -730,20 +697,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process SetState(newState); - // TODO: We can't call KThread.Start from a non-guest thread. - // We will need to make some changes to allow the creation of - // dummy threads that will be used to initialize the current - // thread on KCoreContext so that GetCurrentThread doesn't fail. - /* Result = MainThread.Start(); + result = mainThread.Start(); - if (Result != KernelResult.Success) + if (result != KernelResult.Success) { - SetState(OldState); + SetState(oldState); CleanUpForError(); - } */ - - mainThread.Reschedule(ThreadSchedState.Running); + } if (result == KernelResult.Success) { @@ -760,7 +721,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { if (State != newState) { - State = newState; + State = newState; _signaled = true; Signal(); @@ -769,23 +730,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public KernelResult InitializeThread( KThread thread, - ulong entrypoint, - ulong argsPtr, - ulong stackTop, - int priority, - int cpuCore) + ulong entrypoint, + ulong argsPtr, + ulong stackTop, + int priority, + int cpuCore) { lock (_processLock) { - return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this); + return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this, ThreadType.User, null); } } public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context) { - context.Interrupt += InterruptHandler; + context.Interrupt += InterruptHandler; context.SupervisorCall += KernelContext.SyscallHandler.SvcCall; - context.Undefined += UndefinedInstructionHandler; + context.Undefined += UndefinedInstructionHandler; } private void InterruptHandler(object sender, EventArgs e) @@ -910,8 +871,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { if (State >= ProcessState.Started) { - if (State == ProcessState.Started || - State == ProcessState.Crashed || + if (State == ProcessState.Started || + State == ProcessState.Crashed || State == ProcessState.Attached || State == ProcessState.DebugSuspended) { @@ -1072,23 +1033,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return result; } - private void InitializeMemoryManager(AddressSpaceType addrSpaceType, MemoryRegion memRegion) + private void InitializeMemoryManager(ProcessCreationFlags flags) { - int addrSpaceBits = addrSpaceType switch + int addrSpaceBits = (flags & ProcessCreationFlags.AddressSpaceMask) switch { - AddressSpaceType.Addr32Bits => 32, - AddressSpaceType.Addr36Bits => 36, - AddressSpaceType.Addr32BitsNoMap => 32, - AddressSpaceType.Addr39Bits => 39, - _ => throw new ArgumentException(nameof(addrSpaceType)) + ProcessCreationFlags.AddressSpace32Bit => 32, + ProcessCreationFlags.AddressSpace64BitDeprecated => 36, + ProcessCreationFlags.AddressSpace32BitWithoutAlias => 32, + ProcessCreationFlags.AddressSpace64Bit => 39, + _ => 39 }; - CpuMemory = new MemoryManager(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler); - CpuContext = new CpuContext(CpuMemory); + Context = _contextFactory.Create(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler); // TODO: This should eventually be removed. // The GPU shouldn't depend on the CPU memory manager at all. - KernelContext.Device.Gpu.SetVmm(CpuMemory); + if (flags.HasFlag(ProcessCreationFlags.IsApplication)) + { + KernelContext.Device.Gpu.SetVmm((MemoryManager)CpuMemory); + } MemoryManager = new KMemoryManager(KernelContext, CpuMemory); } @@ -1109,9 +1072,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process throw new UndefinedInstructionException(e.Address, e.OpCode); } - protected override void Destroy() - { - CpuMemory.Dispose(); - } + protected override void Destroy() => Context.Dispose(); } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs index 2396aea8..e1cdb30f 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs @@ -2,6 +2,7 @@ using Ryujinx.Common; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Threading; +using System; namespace Ryujinx.HLE.HOS.Kernel.Process { @@ -24,29 +25,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process IrqAccessMask = new byte[0x80]; } - public KernelResult InitializeForKernel(int[] caps, KMemoryManager memoryManager) + public KernelResult InitializeForKernel(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager) { AllowedCpuCoresMask = 0xf; AllowedThreadPriosMask = -1; DebuggingFlags &= ~3; KernelReleaseVersion = KProcess.KernelVersionPacked; - return Parse(caps, memoryManager); + return Parse(capabilities, memoryManager); } - public KernelResult InitializeForUser(int[] caps, KMemoryManager memoryManager) + public KernelResult InitializeForUser(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager) { - return Parse(caps, memoryManager); + return Parse(capabilities, memoryManager); } - private KernelResult Parse(int[] caps, KMemoryManager memoryManager) + private KernelResult Parse(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager) { int mask0 = 0; int mask1 = 0; - for (int index = 0; index < caps.Length; index++) + for (int index = 0; index < capabilities.Length; index++) { - int cap = caps[index]; + int cap = capabilities[index]; if (((cap + 1) & ~cap) != 0x40) { @@ -59,14 +60,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process } else { - if ((uint)index + 1 >= caps.Length) + if ((uint)index + 1 >= capabilities.Length) { return KernelResult.InvalidCombination; } int prevCap = cap; - cap = caps[++index]; + cap = capabilities[++index]; if (((cap + 1) & ~cap) != 0x40) { @@ -91,9 +92,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return KernelResult.InvalidAddress; } - MemoryPermission perm = (prevCap >> 31) != 0 - ? MemoryPermission.Read - : MemoryPermission.ReadAndWrite; + KMemoryPermission perm = (prevCap >> 31) != 0 + ? KMemoryPermission.Read + : KMemoryPermission.ReadAndWrite; KernelResult result; @@ -216,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { long address = ((long)(uint)cap << 4) & 0xffffff000; - memoryManager.MapIoMemory(address, KMemoryManager.PageSize, MemoryPermission.ReadAndWrite); + memoryManager.MapIoMemory(address, KMemoryManager.PageSize, KMemoryPermission.ReadAndWrite); break; } diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs new file mode 100644 index 00000000..54997cb7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs @@ -0,0 +1,25 @@ +using ARMeilleure.State; +using Ryujinx.Memory; +using System; + +namespace Ryujinx.HLE.HOS.Kernel.Process +{ + class ProcessContext : IProcessContext + { + public IVirtualMemoryManager AddressSpace { get; } + + public ProcessContext(IVirtualMemoryManager asManager) + { + AddressSpace = asManager; + } + + public void Execute(ExecutionContext context, ulong codeAddress) + { + throw new NotSupportedException(); + } + + public void Dispose() + { + } + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs new file mode 100644 index 00000000..03db62fa --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs @@ -0,0 +1,13 @@ +using Ryujinx.Cpu; +using Ryujinx.Memory; + +namespace Ryujinx.HLE.HOS.Kernel.Process +{ + class ProcessContextFactory : IProcessContextFactory + { + public IProcessContext Create(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler) + { + return new ProcessContext(new AddressSpaceManager(backingMemory, addressSpaceSize)); + } + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs new file mode 100644 index 00000000..a34481e5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs @@ -0,0 +1,38 @@ +namespace Ryujinx.HLE.HOS.Kernel.Process +{ + enum ProcessCreationFlags + { + Is64Bit = 1 << 0, + + AddressSpaceShift = 1, + AddressSpace32Bit = 0 << AddressSpaceShift, + AddressSpace64BitDeprecated = 1 << AddressSpaceShift, + AddressSpace32BitWithoutAlias = 2 << AddressSpaceShift, + AddressSpace64Bit = 3 << AddressSpaceShift, + AddressSpaceMask = 7 << AddressSpaceShift, + + EnableDebug = 1 << 4, + EnableAslr = 1 << 5, + IsApplication = 1 << 6, + DeprecatedUseSecureMemory = 1 << 7, + + PoolPartitionShift = 7, + PoolPartitionApplication = 0 << PoolPartitionShift, + PoolPartitionApplet = 1 << PoolPartitionShift, + PoolPartitionSystem = 2 << PoolPartitionShift, + PoolPartitionSystemNonSecure = 3 << PoolPartitionShift, + PoolPartitionMask = 0xf << PoolPartitionShift, + + OptimizeMemoryAllocation = 1 << 11, + + All = + Is64Bit | + AddressSpaceMask | + EnableDebug | + EnableAslr | + IsApplication | + DeprecatedUseSecureMemory | + PoolPartitionMask | + OptimizeMemoryAllocation + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs index a5820865..26c23b3b 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs @@ -2,36 +2,36 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { struct ProcessCreationInfo { - public string Name { get; private set; } + public string Name { get; } - public int Version { get; private set; } - public ulong TitleId { get; private set; } + public int Version { get; } + public ulong TitleId { get; } - public ulong CodeAddress { get; private set; } - public int CodePagesCount { get; private set; } + public ulong CodeAddress { get; } + public int CodePagesCount { get; } - public int MmuFlags { get; private set; } - public int ResourceLimitHandle { get; private set; } - public int PersonalMmHeapPagesCount { get; private set; } + public ProcessCreationFlags Flags { get; } + public int ResourceLimitHandle { get; } + public int SystemResourcePagesCount { get; } public ProcessCreationInfo( string name, - int category, - ulong titleId, - ulong codeAddress, - int codePagesCount, - int mmuFlags, - int resourceLimitHandle, - int personalMmHeapPagesCount) + int version, + ulong titleId, + ulong codeAddress, + int codePagesCount, + ProcessCreationFlags flags, + int resourceLimitHandle, + int systemResourcePagesCount) { - Name = name; - Version = category; - TitleId = titleId; - CodeAddress = codeAddress; - CodePagesCount = codePagesCount; - MmuFlags = mmuFlags; - ResourceLimitHandle = resourceLimitHandle; - PersonalMmHeapPagesCount = personalMmHeapPagesCount; + Name = name; + Version = version; + TitleId = titleId; + CodeAddress = codeAddress; + CodePagesCount = codePagesCount; + Flags = flags; + ResourceLimitHandle = resourceLimitHandle; + SystemResourcePagesCount = systemResourcePagesCount; } } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index c1e7026b..5e32ca58 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -7,124 +7,223 @@ using Ryujinx.HLE.HOS.Kernel.Ipc; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Memory; using System; +using System.Threading; namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { class Syscall { - private readonly Switch _device; private readonly KernelContext _context; - public Syscall(Switch device, KernelContext context) + public Syscall(KernelContext context) { - _device = device; _context = context; } - // IPC + // Process - public KernelResult ConnectToNamedPort(ulong namePtr, out int handle) + public KernelResult GetProcessId(int handle, out long pid) + { + KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); + + KProcess process = currentProcess.HandleTable.GetKProcess(handle); + + if (process == null) + { + KThread thread = currentProcess.HandleTable.GetKThread(handle); + + if (thread != null) + { + process = thread.Owner; + } + + // TODO: KDebugEvent. + } + + pid = process?.Pid ?? 0; + + return process != null + ? KernelResult.Success + : KernelResult.InvalidHandle; + } + + public KernelResult CreateProcess( + ProcessCreationInfo info, + ReadOnlySpan<int> capabilities, + out int handle, + IProcessContextFactory contextFactory, + ThreadStart customThreadStart = null) { handle = 0; - if (!KernelTransfer.UserToKernelString(_context, namePtr, 12, out string name)) + if ((info.Flags & ~ProcessCreationFlags.All) != 0) { - return KernelResult.UserCopyFailed; + return KernelResult.InvalidEnumValue; } - if (name.Length > 11) + // TODO: Address space check. + + if ((info.Flags & ProcessCreationFlags.PoolPartitionMask) > ProcessCreationFlags.PoolPartitionSystemNonSecure) { - return KernelResult.MaximumExceeded; + return KernelResult.InvalidEnumValue; } - KAutoObject autoObj = KAutoObject.FindNamedObject(_context, name); + if ((info.CodeAddress & 0x1fffff) != 0) + { + return KernelResult.InvalidAddress; + } - if (!(autoObj is KClientPort clientPort)) + if (info.CodePagesCount < 0 || info.SystemResourcePagesCount < 0) { - return KernelResult.NotFound; + return KernelResult.InvalidSize; } - KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); + if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) && + !info.Flags.HasFlag(ProcessCreationFlags.IsApplication)) + { + return KernelResult.InvalidThread; + } - KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle); + KHandleTable handleTable = _context.Scheduler.GetCurrentProcess().HandleTable; - if (result != KernelResult.Success) + KProcess process = new KProcess(_context); + + using var _ = new OnScopeExit(process.DecrementReferenceCount); + + KResourceLimit resourceLimit; + + if (info.ResourceLimitHandle != 0) { - return result; + resourceLimit = handleTable.GetObject<KResourceLimit>(info.ResourceLimitHandle); + + if (resourceLimit == null) + { + return KernelResult.InvalidHandle; + } + } + else + { + resourceLimit = _context.ResourceLimit; } - result = clientPort.Connect(out KClientSession clientSession); + MemoryRegion memRegion = (info.Flags & ProcessCreationFlags.PoolPartitionMask) switch + { + ProcessCreationFlags.PoolPartitionApplication => MemoryRegion.Application, + ProcessCreationFlags.PoolPartitionApplet => MemoryRegion.Applet, + ProcessCreationFlags.PoolPartitionSystem => MemoryRegion.Service, + ProcessCreationFlags.PoolPartitionSystemNonSecure => MemoryRegion.NvServices, + _ => MemoryRegion.NvServices + }; + + KernelResult result = process.Initialize( + info, + capabilities, + resourceLimit, + memRegion, + contextFactory, + customThreadStart); if (result != KernelResult.Success) { - currentProcess.HandleTable.CancelHandleReservation(handle); - return result; } - currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession); - - clientSession.DecrementReferenceCount(); + _context.Processes.TryAdd(process.Pid, process); - return result; + return handleTable.GenerateHandle(process, out handle); } - public KernelResult SendSyncRequestHLE(int handle) + public KernelResult StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize) { - KProcess process = _context.Scheduler.GetCurrentProcess(); + KProcess process = _context.Scheduler.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle); - KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle); + if (process == null) + { + return KernelResult.InvalidHandle; + } - if (clientSession == null || clientSession.Service == null) + if ((uint)cpuCore >= KScheduler.CpuCoresCount || !process.IsCpuCoreAllowed(cpuCore)) { - return SendSyncRequest(handle); + return KernelResult.InvalidCpuCore; + } + + if ((uint)priority >= KScheduler.PrioritiesCount || !process.IsPriorityAllowed(priority)) + { + return KernelResult.InvalidPriority; + } + + process.DefaultCpuCore = cpuCore; + + KernelResult result = process.Start(priority, mainThreadStackSize); + + if (result != KernelResult.Success) + { + return result; } - return SendSyncRequestWithUserBufferHLE((ulong)_context.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle); + process.IncrementReferenceCount(); + + return KernelResult.Success; } - public KernelResult SendSyncRequestWithUserBufferHLE(ulong messagePtr, ulong messageSize, int handle) + // IPC + + public KernelResult ConnectToNamedPort(ulong namePtr, out int handle) { - KProcess process = _context.Scheduler.GetCurrentProcess(); + handle = 0; - byte[] messageData = new byte[messageSize]; + if (!KernelTransfer.UserToKernelString(_context, namePtr, 12, out string name)) + { + return KernelResult.UserCopyFailed; + } - process.CpuMemory.Read(messagePtr, messageData); + return ConnectToNamedPort(name, out handle); + } - KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle); + public KernelResult ConnectToNamedPort(string name, out int handle) + { + handle = 0; - if (clientSession == null || clientSession.Service == null) + if (name.Length > 11) { - return SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle); + return KernelResult.MaximumExceeded; } - if (clientSession != null) - { - _context.CriticalSection.Enter(); + KAutoObject autoObj = KAutoObject.FindNamedObject(_context, name); - KThread currentThread = _context.Scheduler.GetCurrentThread(); + if (!(autoObj is KClientPort clientPort)) + { + return KernelResult.NotFound; + } - currentThread.SignaledObj = null; - currentThread.ObjSyncResult = KernelResult.Success; + KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); - currentThread.Reschedule(ThreadSchedState.Paused); + KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle); - clientSession.Service.Server.PushMessage(_device, currentThread, clientSession, messagePtr, messageSize); + if (result != KernelResult.Success) + { + return result; + } - _context.CriticalSection.Leave(); + result = clientPort.Connect(out KClientSession clientSession); - return currentThread.ObjSyncResult; - } - else + if (result != KernelResult.Success) { - Logger.Warning?.Print(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!"); + currentProcess.HandleTable.CancelHandleReservation(handle); - return KernelResult.InvalidHandle; + return result; } + + currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession); + + clientSession.DecrementReferenceCount(); + + return result; } - private KernelResult SendSyncRequest(int handle) + public KernelResult SendSyncRequest(int handle) { KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); @@ -407,9 +506,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.UserCopyFailed; } - KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount]; + return ReplyAndReceive(handles, replyTargetHandle, timeout, out handleIndex); + } - for (int index = 0; index < handlesCount; index++) + public KernelResult ReplyAndReceive(ReadOnlySpan<int> handles, int replyTargetHandle, long timeout, out int handleIndex) + { + handleIndex = 0; + + KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); + + KSynchronizationObject[] syncObjs = new KSynchronizationObject[handles.Length]; + + for (int index = 0; index < handles.Length; index++) { KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]); @@ -601,7 +709,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.UserCopyFailed; } - if (maxSessions < 0 || name.Length > 11) + if (name.Length > 11) + { + return KernelResult.MaximumExceeded; + } + + return ManageNamedPort(name, maxSessions, out handle); + } + + public KernelResult ManageNamedPort(string name, int maxSessions, out int handle) + { + handle = 0; + + if (maxSessions < 0) { return KernelResult.MaximumExceeded; } @@ -826,7 +946,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - public KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission) + public KernelResult MapSharedMemory(int handle, ulong address, ulong size, KMemoryPermission permission) { if (!PageAligned(address)) { @@ -843,7 +963,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidMemState; } - if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite) + if ((permission | KMemoryPermission.Write) != KMemoryPermission.ReadAndWrite) { return KernelResult.InvalidPermission; } @@ -912,7 +1032,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall currentProcess); } - public KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle) + public KernelResult CreateTransferMemory(ulong address, ulong size, KMemoryPermission permission, out int handle) { handle = 0; @@ -931,7 +1051,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidMemState; } - if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write) + if (permission > KMemoryPermission.ReadAndWrite || permission == KMemoryPermission.Write) { return KernelResult.InvalidPermission; } @@ -1119,7 +1239,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size); } - public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, MemoryPermission permission) + public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, KMemoryPermission permission) { if (!PageAligned(src)) { @@ -1131,10 +1251,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidSize; } - if (permission != MemoryPermission.None && - permission != MemoryPermission.Read && - permission != MemoryPermission.ReadAndWrite && - permission != MemoryPermission.ReadAndExecute) + if (permission != KMemoryPermission.None && + permission != KMemoryPermission.Read && + permission != KMemoryPermission.ReadAndWrite && + permission != KMemoryPermission.ReadAndExecute) { return KernelResult.InvalidPermission; } @@ -1282,31 +1402,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _context.Scheduler.GetCurrentThread().Context.CntpctEl0; } - public KernelResult GetProcessId(int handle, out long pid) - { - KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); - - KProcess process = currentProcess.HandleTable.GetKProcess(handle); - - if (process == null) - { - KThread thread = currentProcess.HandleTable.GetKThread(handle); - - if (thread != null) - { - process = thread.Owner; - } - - // TODO: KDebugEvent. - } - - pid = process?.Pid ?? 0; - - return process != null - ? KernelResult.Success - : KernelResult.InvalidHandle; - } - public void Break(ulong reason) { KThread currentThread = _context.Scheduler.GetCurrentThread(); @@ -1997,7 +2092,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidThread; } - MemoryManager memory = currentProcess.CpuMemory; + IVirtualMemoryManager memory = currentProcess.CpuMemory; memory.Write(address + 0x0, thread.Context.GetX(0)); memory.Write(address + 0x8, thread.Context.GetX(1)); diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs index 224af6d8..b57175a3 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs @@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall public KernelResult SendSyncRequest32([R(0)] int handle) { - return _syscall.SendSyncRequestHLE(handle); + return _syscall.SendSyncRequest(handle); } public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint messageSize, [R(2)] int handle) { - return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle); + return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle); } public KernelResult CreateSession32( @@ -116,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] MemoryPermission permission) + public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] KMemoryPermission permission) { return _syscall.MapSharedMemory(handle, address, size, permission); } @@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall public KernelResult CreateTransferMemory32( [R(1)] uint address, [R(2)] uint size, - [R(3)] MemoryPermission permission, + [R(3)] KMemoryPermission permission, [R(1)] out int handle) { return _syscall.CreateTransferMemory(address, size, permission, out handle); @@ -169,7 +169,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall [R(2)] uint srcLow, [R(3)] uint srcHigh, [R(4)] uint sizeHigh, - [R(5)] MemoryPermission permission) + [R(5)] KMemoryPermission permission) { ulong src = srcLow | ((ulong)srcHigh << 32); ulong size = sizeLow | ((ulong)sizeHigh << 32); diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs index 47f78a25..07ca4aae 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs @@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall public KernelResult SendSyncRequest64([R(0)] int handle) { - return _syscall.SendSyncRequestHLE(handle); + return _syscall.SendSyncRequest(handle); } public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong messageSize, [R(2)] int handle) { - return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle); + return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle); } public KernelResult SendAsyncRequestWithUserBuffer64( @@ -133,7 +133,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _syscall.QueryMemory(infoPtr, position, out pageInfo); } - public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] MemoryPermission permission) + public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] KMemoryPermission permission) { return _syscall.MapSharedMemory(handle, address, size, permission); } @@ -146,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall public KernelResult CreateTransferMemory64( [R(1)] ulong address, [R(2)] ulong size, - [R(3)] MemoryPermission permission, + [R(3)] KMemoryPermission permission, [R(1)] out int handle) { return _syscall.CreateTransferMemory(address, size, permission, out handle); @@ -172,7 +172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _syscall.UnmapProcessCodeMemory(handle, dst, src, size); } - public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] MemoryPermission permission) + public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] KMemoryPermission permission) { return _syscall.SetProcessMemoryPermission(handle, src, size, permission); } diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs index 84995513..c6da361d 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs @@ -229,6 +229,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading KProcess dummyProcess = new KProcess(_context); + dummyProcess.HandleTable.Initialize(1024); + KThread dummyThread = new KThread(_context); dummyThread.Initialize(0, 0, 0, 44, 0, dummyProcess, ThreadType.Dummy); diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs index 27ff3883..f523cb9c 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs @@ -31,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading public ulong CondVarAddress { get; set; } private ulong _entrypoint; + private ThreadStart _customThreadStart; public ulong MutexAddress { get; set; } @@ -48,12 +49,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; } - public LinkedList<KThread> Withholder { get; set; } + public LinkedList<KThread> Withholder { get; set; } public LinkedListNode<KThread> WithholderNode { get; set; } public LinkedListNode<KThread> ProcessListNode { get; set; } - private LinkedList<KThread> _mutexWaiters; + private LinkedList<KThread> _mutexWaiters; private LinkedListNode<KThread> _mutexWaiterNode; public KThread MutexOwner { get; private set; } @@ -65,24 +66,28 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading public KernelResult ObjSyncResult { get; set; } public int DynamicPriority { get; set; } - public int CurrentCore { get; set; } - public int BasePriority { get; set; } - public int PreferredCore { get; set; } + public int CurrentCore { get; set; } + public int BasePriority { get; set; } + public int PreferredCore { get; set; } private long _affinityMaskOverride; - private int _preferredCoreOverride; + private int _preferredCoreOverride; #pragma warning disable CS0649 - private int _affinityOverrideCount; + private int _affinityOverrideCount; #pragma warning restore CS0649 public ThreadSchedState SchedFlags { get; private set; } private int _shallBeTerminated; - public bool ShallBeTerminated { get => _shallBeTerminated != 0; set => _shallBeTerminated = value ? 1 : 0; } + public bool ShallBeTerminated + { + get => _shallBeTerminated != 0; + set => _shallBeTerminated = value ? 1 : 0; + } public bool SyncCancelled { get; set; } - public bool WaitingSync { get; set; } + public bool WaitingSync { get; set; } private bool _hasExited; private bool _hasBeenInitialized; @@ -98,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading public KThread(KernelContext context) : base(context) { - _scheduler = KernelContext.Scheduler; + _scheduler = KernelContext.Scheduler; _schedulingData = KernelContext.Scheduler.SchedulingData; WaitSyncObjects = new KSynchronizationObject[MaxWaitSyncObjects]; @@ -110,14 +115,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading } public KernelResult Initialize( - ulong entrypoint, - ulong argsPtr, - ulong stackTop, - int priority, - int defaultCpuCore, - KProcess owner, - ThreadType type = ThreadType.User, - ThreadStart customHostThreadStart = null) + ulong entrypoint, + ulong argsPtr, + ulong stackTop, + int priority, + int defaultCpuCore, + KProcess owner, + ThreadType type, + ThreadStart customThreadStart = null) { if ((uint)type > 3) { @@ -135,11 +140,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading CurrentCore = PreferredCore; DynamicPriority = priority; - BasePriority = priority; + BasePriority = priority; ObjSyncResult = KernelResult.ThreadNotStarted; _entrypoint = entrypoint; + _customThreadStart = customThreadStart; if (type == ThreadType.User) { @@ -162,18 +168,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading owner.IncrementReferenceCount(); owner.IncrementThreadCount(); - is64Bits = (owner.MmuFlags & 1) != 0; + is64Bits = owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit); } else { is64Bits = true; } - HostThread = new Thread(customHostThreadStart ?? (() => ThreadStart(entrypoint))); + HostThread = new Thread(ThreadStart); Context = CpuContext.CreateExecutionContext(); - bool isAarch32 = (Owner.MmuFlags & 1) == 0; + bool isAarch32 = !Owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit); Context.IsAarch32 = isAarch32; @@ -189,7 +195,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading } Context.CntfrqEl0 = 19200000; - Context.Tpidr = (long)_tlsAddress; + Context.Tpidr = (long)_tlsAddress; owner.SubscribeThreadEventHandlers(Context); @@ -249,7 +255,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading { KThread currentThread = KernelContext.Scheduler.GetCurrentThread(); - while (SchedFlags != ThreadSchedState.TerminationPending && + while (SchedFlags != ThreadSchedState.TerminationPending && currentThread.SchedFlags != ThreadSchedState.TerminationPending && !currentThread.ShallBeTerminated) { @@ -351,7 +357,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading Context.RequestInterrupt(); } - SignaledObj = null; + SignaledObj = null; ObjSyncResult = KernelResult.ThreadTerminating; ReleaseAndResume(); @@ -524,7 +530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading // If the candidate was scheduled after the current thread, then it's not worth it, // unless the priority is higher than the current one. if (nextThreadOnCurrentQueue.LastScheduledTime >= thread.LastScheduledTime || - nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority) + nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority) { yield return thread; } @@ -701,7 +707,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading } else { - SignaledObj = null; + SignaledObj = null; ObjSyncResult = KernelResult.Cancelled; SetNewSchedFlags(ThreadSchedState.Running); @@ -734,14 +740,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading if (useOverride) { _preferredCoreOverride = newCore; - _affinityMaskOverride = newAffinityMask; + _affinityMaskOverride = newAffinityMask; } else { long oldAffinityMask = AffinityMask; PreferredCore = newCore; - AffinityMask = newAffinityMask; + AffinityMask = newAffinityMask; if (oldAffinityMask != newAffinityMask) { @@ -783,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading private void CombineForcePauseFlags() { - ThreadSchedState oldFlags = SchedFlags; + ThreadSchedState oldFlags = SchedFlags; ThreadSchedState lowNibble = SchedFlags & ThreadSchedState.LowMask; SchedFlags = lowNibble | _forcePauseFlags; @@ -1143,19 +1149,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading } } - private void ThreadStart(ulong entrypoint) + private void ThreadStart() { - Owner.CpuContext.Execute(Context, entrypoint); + KernelStatic.SetKernelContext(KernelContext); - ThreadExit(); - - Context.Dispose(); - } + if (_customThreadStart != null) + { + _customThreadStart(); + } + else + { + Owner.Context.Execute(Context, _entrypoint); + } - private void ThreadExit() - { KernelContext.Scheduler.ExitThread(this); KernelContext.Scheduler.RemoveThread(this); + + Context.Dispose(); } public bool IsCurrentHostThread() @@ -1203,9 +1213,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading // Wake up all threads that may be waiting for a mutex being held by this thread. foreach (KThread thread in _mutexWaiters) { - thread.MutexOwner = null; + thread.MutexOwner = null; thread._preferredCoreOverride = 0; - thread.ObjSyncResult = KernelResult.InvalidState; + thread.ObjSyncResult = KernelResult.InvalidState; thread.ReleaseAndResume(); } |
