Просмотр исходного кода

IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel (#1458)

* IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel

* Fix for applet transfer memory + some nits

* Keep handles if possible to avoid server handle table exhaustion

* Fix IPC ZeroFill bug

* am: Correctly implement CreateManagedDisplayLayer and implement CreateManagedDisplaySeparableLayer

CreateManagedDisplaySeparableLayer is requires since 10.x+ when appletResourceUserId != 0

* Make it exit properly

* Make ServiceNotImplementedException show the full message again

* Allow yielding execution to avoid starving other threads

* Only wait if active

* Merge IVirtualMemoryManager and IAddressSpaceManager

* Fix Ro loading data from the wrong process

Co-authored-by: Thog <me@thog.eu>
gdkchan 5 лет назад
Родитель
Сommit
cf6cd71488
100 измененных файлов с 1638 добавлено и 1015 удалено
  1. 1 1
      ARMeilleure/State/ExecutionContext.cs
  2. 22 5
      Ryujinx.Audio.Renderer/Dsp/Command/AuxiliaryBufferCommand.cs
  3. 3 3
      Ryujinx.Audio.Renderer/Dsp/Command/CommandList.cs
  4. 2 2
      Ryujinx.Audio.Renderer/Dsp/DataSourceHelper.cs
  5. 5 5
      Ryujinx.Audio.Renderer/Dsp/State/AuxiliaryBufferHeader.cs
  6. 1 0
      Ryujinx.Audio.Renderer/Ryujinx.Audio.Renderer.csproj
  7. 10 10
      Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs
  8. 10 2
      Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs
  9. 6 5
      Ryujinx.Cpu/MemoryHelper.cs
  10. 6 1
      Ryujinx.Cpu/MemoryManager.cs
  11. 1 1
      Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
  12. 2 1
      Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
  13. 11 9
      Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs
  14. 24 0
      Ryujinx.HLE/HOS/ArmProcessContext.cs
  15. 14 0
      Ryujinx.HLE/HOS/ArmProcessContextFactory.cs
  16. 14 6
      Ryujinx.HLE/HOS/Horizon.cs
  17. 20 3
      Ryujinx.HLE/HOS/Ipc/IpcMessage.cs
  18. 27 0
      Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs
  19. 6 0
      Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs
  20. 11 0
      Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
  21. 2 2
      Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
  22. 0 9
      Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
  23. 0 9
      Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
  24. 13 21
      Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
  25. 1 14
      Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs
  26. 1 1
      Ryujinx.HLE/HOS/Kernel/KernelContext.cs
  27. 38 0
      Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
  28. 8 8
      Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs
  29. 4 4
      Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs
  30. 176 151
      Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs
  31. 6 6
      Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
  32. 5 2
      Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
  33. 1 1
      Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs
  34. 5 5
      Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
  35. 13 0
      Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
  36. 10 0
      Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs
  37. 97 137
      Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
  38. 14 13
      Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
  39. 25 0
      Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
  40. 13 0
      Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
  41. 38 0
      Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
  42. 23 23
      Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs
  43. 184 89
      Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
  44. 5 5
      Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs
  45. 5 5
      Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs
  46. 2 0
      Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs
  47. 50 40
      Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
  48. 18 12
      Ryujinx.HLE/HOS/ProgramLoader.cs
  49. 24 28
      Ryujinx.HLE/HOS/ServiceCtx.cs
  50. 8 3
      Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs
  51. 25 12
      Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
  52. 18 10
      Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
  53. 7 3
      Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs
  54. 3 1
      Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs
  55. 37 5
      Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
  56. 9 2
      Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IWindowController.cs
  57. 1 1
      Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs
  58. 27 16
      Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
  59. 8 3
      Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs
  60. 1 1
      Ryujinx.HLE/HOS/Services/Am/AppletOE/IApplicationProxyService.cs
  61. 14 8
      Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs
  62. 3 1
      Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs
  63. 4 2
      Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs
  64. 2 1
      Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs
  65. 2 2
      Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs
  66. 3 0
      Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs
  67. 7 3
      Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs
  68. 6 16
      Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
  69. 7 3
      Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs
  70. 12 12
      Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
  71. 24 38
      Ryujinx.HLE/HOS/Services/IpcService.cs
  72. 16 16
      Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs
  73. 15 6
      Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
  74. 8 3
      Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs
  75. 11 6
      Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs
  76. 35 32
      Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs
  77. 3 4
      Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvDeviceFile.cs
  78. 2 1
      Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs
  79. 5 4
      Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs
  80. 3 2
      Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs
  81. 3 3
      Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlDeviceFile.cs
  82. 3 2
      Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs
  83. 12 12
      Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs
  84. 19 18
      Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
  85. 8 3
      Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs
  86. 184 49
      Ryujinx.HLE/HOS/Services/ServerBase.cs
  87. 8 20
      Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
  88. 4 1
      Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs
  89. 10 10
      Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs
  90. 6 6
      Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueue.cs
  91. 39 6
      Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs
  92. 5 0
      Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs
  93. 1 1
      Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
  94. 15 11
      Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
  95. 6 6
      Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/GraphicBuffer.cs
  96. 3 1
      Ryujinx.HLE/HOS/Services/Time/IStaticServiceForGlue.cs
  97. 6 6
      Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs
  98. 1 2
      Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs
  99. 1 1
      Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs
  100. 1 1
      Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs

+ 1 - 1
ARMeilleure/State/ExecutionContext.cs

@@ -66,7 +66,7 @@ namespace ARMeilleure.State
             }
         }
 
-        internal bool Running { get; private set; }
+        public bool Running { get; private set; }
 
         public event EventHandler<EventArgs>              Interrupt;
         public event EventHandler<InstExceptionEventArgs> Break;

+ 22 - 5
Ryujinx.Audio.Renderer/Dsp/Command/AuxiliaryBufferCommand.cs

@@ -16,7 +16,7 @@
 //
 
 using Ryujinx.Audio.Renderer.Common;
-using Ryujinx.Cpu;
+using Ryujinx.Memory;
 using System;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
@@ -65,7 +65,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
             IsEffectEnabled = isEnabled;
         }
 
-        private uint Read(MemoryManager memoryManager, ulong bufferAddress, uint countMax, Span<int> outBuffer, uint count, uint readOffset, uint updateCount)
+        private uint Read(IVirtualMemoryManager memoryManager, ulong bufferAddress, uint countMax, Span<int> outBuffer, uint count, uint readOffset, uint updateCount)
         {
             if (countMax == 0 || bufferAddress == 0)
             {
@@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
             return count;
         }
 
-        private uint Write(MemoryManager memoryManager, ulong outBufferAddress, uint countMax, ReadOnlySpan<int> buffer, uint count, uint writeOffset, uint updateCount)
+        private uint Write(IVirtualMemoryManager memoryManager, ulong outBufferAddress, uint countMax, ReadOnlySpan<int> buffer, uint count, uint writeOffset, uint updateCount)
         {
             if (countMax == 0 || outBufferAddress == 0)
             {
@@ -175,8 +175,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
             }
             else
             {
-                MemoryHelper.FillWithZeros(context.MemoryManager, (long)BufferInfo.SendBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
-                MemoryHelper.FillWithZeros(context.MemoryManager, (long)BufferInfo.ReturnBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
+                ZeroFill(context.MemoryManager, BufferInfo.SendBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
+                ZeroFill(context.MemoryManager, BufferInfo.ReturnBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
 
                 if (InputBufferIndex != OutputBufferIndex)
                 {
@@ -184,5 +184,22 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
                 }
             }
         }
+
+        private static void ZeroFill(IVirtualMemoryManager memoryManager, ulong address, int size)
+        {
+            ulong endAddress = address + (ulong)size;
+
+            while (address + 7UL < endAddress)
+            {
+                memoryManager.Write(address, 0UL);
+                address += 8;
+            }
+
+            while (address < endAddress)
+            {
+                memoryManager.Write(address, (byte)0);
+                address++;
+            }
+        }
     }
 }

+ 3 - 3
Ryujinx.Audio.Renderer/Dsp/Command/CommandList.cs

@@ -19,7 +19,7 @@ using Ryujinx.Audio.Renderer.Integration;
 using Ryujinx.Audio.Renderer.Server;
 using Ryujinx.Common;
 using Ryujinx.Common.Logging;
-using Ryujinx.Cpu;
+using Ryujinx.Memory;
 using System;
 using System.Collections.Generic;
 
@@ -37,7 +37,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
 
         public List<ICommand> Commands { get; }
 
-        public MemoryManager MemoryManager { get; }
+        public IVirtualMemoryManager MemoryManager { get; }
 
         public HardwareDevice OutputDevice { get; private set; }
 
@@ -50,7 +50,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
         {
         }
 
-        public CommandList(MemoryManager memoryManager, Memory<float> mixBuffer, uint sampleCount, uint sampleRate, uint mixBufferCount, uint voiceChannelCountMax)
+        public CommandList(IVirtualMemoryManager memoryManager, Memory<float> mixBuffer, uint sampleCount, uint sampleRate, uint mixBufferCount, uint voiceChannelCountMax)
         {
             SampleCount = sampleCount;
             SampleRate = sampleRate;

+ 2 - 2
Ryujinx.Audio.Renderer/Dsp/DataSourceHelper.cs

@@ -18,7 +18,7 @@
 using Ryujinx.Audio.Renderer.Common;
 using Ryujinx.Audio.Renderer.Dsp.State;
 using Ryujinx.Common.Logging;
-using Ryujinx.Cpu;
+using Ryujinx.Memory;
 using System;
 using System.Buffers;
 using System.Diagnostics;
@@ -63,7 +63,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
             }
         }
 
-        public static void ProcessWaveBuffers(MemoryManager memoryManager, Span<float> outputBuffer, WaveBufferInformation info, uint targetSampleRate, int sampleCount)
+        public static void ProcessWaveBuffers(IVirtualMemoryManager memoryManager, Span<float> outputBuffer, WaveBufferInformation info, uint targetSampleRate, int sampleCount)
         {
             const int tempBufferSize = 0x3F00;
 

+ 5 - 5
Ryujinx.Audio.Renderer/Dsp/State/AuxiliaryBufferHeader.cs

@@ -15,7 +15,7 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 //
 
-using Ryujinx.Cpu;
+using Ryujinx.Memory;
 using System.Runtime.InteropServices;
 
 namespace Ryujinx.Audio.Renderer.Dsp.State
@@ -33,22 +33,22 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
             public uint WriteOffset;
             private uint _reserved;
 
-            public static uint GetReadOffset(MemoryManager manager, ulong bufferAddress)
+            public static uint GetReadOffset(IVirtualMemoryManager manager, ulong bufferAddress)
             {
                 return manager.Read<uint>(bufferAddress + ReadOffsetPosition);
             }
 
-            public static uint GetWriteOffset(MemoryManager manager, ulong bufferAddress)
+            public static uint GetWriteOffset(IVirtualMemoryManager manager, ulong bufferAddress)
             {
                 return manager.Read<uint>(bufferAddress + WriteOffsetPosition);
             }
 
-            public static void SetReadOffset(MemoryManager manager, ulong bufferAddress, uint value)
+            public static void SetReadOffset(IVirtualMemoryManager manager, ulong bufferAddress, uint value)
             {
                 manager.Write(bufferAddress + ReadOffsetPosition, value);
             }
 
-            public static void SetWriteOffset(MemoryManager manager, ulong bufferAddress, uint value)
+            public static void SetWriteOffset(IVirtualMemoryManager manager, ulong bufferAddress, uint value)
             {
                 manager.Write(bufferAddress + WriteOffsetPosition, value);
             }

+ 1 - 0
Ryujinx.Audio.Renderer/Ryujinx.Audio.Renderer.csproj

@@ -8,6 +8,7 @@
   <ItemGroup>
     <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
     <ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" />
+    <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
   </ItemGroup>
 
 </Project>

+ 10 - 10
Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs

@@ -31,7 +31,7 @@ using Ryujinx.Audio.Renderer.Server.Voice;
 using Ryujinx.Audio.Renderer.Utils;
 using Ryujinx.Common;
 using Ryujinx.Common.Logging;
-using Ryujinx.Cpu;
+using Ryujinx.Memory;
 using System;
 using System.Buffers;
 using System.Diagnostics;
@@ -87,7 +87,7 @@ namespace Ryujinx.Audio.Renderer.Server
 
         private Memory<byte> _performanceBuffer;
 
-        public MemoryManager MemoryManager { get; private set; }
+        public IVirtualMemoryManager MemoryManager { get; private set; }
 
         private ulong _elapsedFrameCount;
         private ulong _renderingStartTick;
@@ -96,14 +96,14 @@ namespace Ryujinx.Audio.Renderer.Server
 
         public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent)
         {
-            _manager           = manager;
-            _terminationEvent  = new ManualResetEvent(false);
+            _manager            = manager;
+            _terminationEvent   = new ManualResetEvent(false);
             _dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
-            _voiceContext      = new VoiceContext();
-            _mixContext        = new MixContext();
-            _sinkContext       = new SinkContext();
-            _splitterContext   = new SplitterContext();
-            _effectContext     = new EffectContext();
+            _voiceContext       = new VoiceContext();
+            _mixContext         = new MixContext();
+            _sinkContext        = new SinkContext();
+            _splitterContext    = new SplitterContext();
+            _effectContext      = new EffectContext();
 
             _commandProcessingTimeEstimator = null;
             _systemEvent = systemEvent;
@@ -113,7 +113,7 @@ namespace Ryujinx.Audio.Renderer.Server
             _sessionId                 = 0;
         }
 
-        public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, MemoryManager memoryManager)
+        public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager)
         {
             if (!BehaviourContext.CheckValidRevision(parameter.Revision))
             {

+ 10 - 2
Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs

@@ -19,7 +19,7 @@ using Ryujinx.Audio.Renderer.Dsp;
 using Ryujinx.Audio.Renderer.Integration;
 using Ryujinx.Audio.Renderer.Parameter;
 using Ryujinx.Common.Logging;
-using Ryujinx.Cpu;
+using Ryujinx.Memory;
 using System;
 using System.Diagnostics;
 using System.Threading;
@@ -288,7 +288,7 @@ namespace Ryujinx.Audio.Renderer.Server
         /// <param name="workBufferSize">The guest work buffer size.</param>
         /// <param name="processHandle">The process handle of the application.</param>
         /// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
-        public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, MemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle)
+        public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, IVirtualMemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle)
         {
             int sessionId = AcquireSessionId();
 
@@ -321,6 +321,14 @@ namespace Ryujinx.Audio.Renderer.Server
         {
             if (disposing)
             {
+                lock (_audioProcessorLock)
+                {
+                    if (_isRunning)
+                    {
+                        StopLocked();
+                    }
+                }
+
                 Processor.Dispose();
 
                 foreach (HardwareDevice device in OutputDevices)

+ 6 - 5
Ryujinx.Cpu/MemoryHelper.cs

@@ -1,4 +1,5 @@
-using System;
+using Ryujinx.Memory;
+using System;
 using System.IO;
 using System.Runtime.InteropServices;
 using System.Text;
@@ -7,7 +8,7 @@ namespace Ryujinx.Cpu
 {
     public static class MemoryHelper
     {
-        public static void FillWithZeros(MemoryManager memory, long position, int size)
+        public static void FillWithZeros(IVirtualMemoryManager memory, long position, int size)
         {
             int size8 = size & ~(8 - 1);
 
@@ -22,7 +23,7 @@ namespace Ryujinx.Cpu
             }
         }
 
-        public unsafe static T Read<T>(MemoryManager memory, long position) where T : struct
+        public unsafe static T Read<T>(IVirtualMemoryManager memory, long position) where T : struct
         {
             long size = Marshal.SizeOf<T>();
 
@@ -36,7 +37,7 @@ namespace Ryujinx.Cpu
             }
         }
 
-        public unsafe static void Write<T>(MemoryManager memory, long position, T value) where T : struct
+        public unsafe static void Write<T>(IVirtualMemoryManager memory, long position, T value) where T : struct
         {
             long size = Marshal.SizeOf<T>();
 
@@ -50,7 +51,7 @@ namespace Ryujinx.Cpu
             memory.Write((ulong)position, data);
         }
 
-        public static string ReadAsciiString(MemoryManager memory, long position, long maxSize = -1)
+        public static string ReadAsciiString(IVirtualMemoryManager memory, long position, long maxSize = -1)
         {
             using (MemoryStream ms = new MemoryStream())
             {

+ 6 - 1
Ryujinx.Cpu/MemoryManager.cs

@@ -13,7 +13,7 @@ namespace Ryujinx.Cpu
     /// <summary>
     /// Represents a CPU memory manager.
     /// </summary>
-    public sealed class MemoryManager : IMemoryManager, IDisposable, IVirtualMemoryManager
+    public sealed class MemoryManager : IMemoryManager, IVirtualMemoryManager, IDisposable
     {
         public const int PageBits = 12;
         public const int PageSize = 1 << PageBits;
@@ -468,6 +468,11 @@ namespace Ryujinx.Cpu
         /// <returns>True if the entire range is mapped, false otherwise</returns>
         public bool IsRangeMapped(ulong va, ulong size)
         {
+            if (size == 0UL)
+            {
+                return true;
+            }
+
             ulong endVa = (va + size + PageMask) & ~(ulong)PageMask;
 
             va &= ~(ulong)PageMask;

+ 1 - 1
Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs

@@ -1,4 +1,4 @@
-using Ryujinx.Cpu;
+using Ryujinx.Memory;
 using System;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;

+ 2 - 1
Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs

@@ -1,5 +1,6 @@
 using Ryujinx.Cpu;
 using Ryujinx.Cpu.Tracking;
+using Ryujinx.Memory;
 using System;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
@@ -12,7 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
     /// </summary>
     class PhysicalMemory
     {
-        public const int PageSize = Cpu.MemoryManager.PageSize;
+        public const int PageSize = 0x1000;
 
         private readonly Cpu.MemoryManager _cpuMemory;
 

+ 11 - 9
Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs

@@ -14,28 +14,31 @@ namespace Ryujinx.HLE.Exceptions
     [Serializable]
     internal class ServiceNotImplementedException : Exception
     {
+        public IIpcService Service { get; }
         public ServiceCtx Context { get; }
         public IpcMessage Request { get; }
 
-        public ServiceNotImplementedException(ServiceCtx context)
-            : this(context, "The service call is not implemented.")
+        public ServiceNotImplementedException(IIpcService service, ServiceCtx context)
+            : this(service, context, "The service call is not implemented.")
         { }
 
-        public ServiceNotImplementedException(ServiceCtx context, string message)
+        public ServiceNotImplementedException(IIpcService service, ServiceCtx context, string message)
             : base(message)
         {
+            Service = service;
             Context = context;
             Request = context.Request;
         }
 
-        public ServiceNotImplementedException(ServiceCtx context, string message, Exception inner)
+        public ServiceNotImplementedException(IIpcService service, ServiceCtx context, string message, Exception inner)
             : base(message, inner)
         {
+            Service = service;
             Context = context;
             Request = context.Request;
         }
 
-        protected ServiceNotImplementedException(SerializationInfo info, StreamingContext context) 
+        protected ServiceNotImplementedException(SerializationInfo info, StreamingContext context)
             : base(info, context)
         { }
 
@@ -59,17 +62,16 @@ namespace Ryujinx.HLE.Exceptions
 
             if (callingType != null && callingMethod != null)
             {
-                var ipcService  = Context.Session.Service;
-                var ipcCommands = ipcService.Commands;
+                var ipcCommands = Service.Commands;
 
                 // Find the handler for the method called
-                var ipcHandler   = ipcCommands.FirstOrDefault(x => x.Value as MethodBase == callingMethod);
+                var ipcHandler   = ipcCommands.FirstOrDefault(x => x.Value == callingMethod);
                 var ipcCommandId = ipcHandler.Key;
                 var ipcMethod    = ipcHandler.Value;
 
                 if (ipcMethod != null)
                 {
-                    sb.AppendLine($"Service Command: {ipcService.GetType().FullName}: {ipcCommandId} ({ipcMethod.Name})");
+                    sb.AppendLine($"Service Command: {Service.GetType().FullName}: {ipcCommandId} ({ipcMethod.Name})");
                     sb.AppendLine();
                 }
             }

+ 24 - 0
Ryujinx.HLE/HOS/ArmProcessContext.cs

@@ -0,0 +1,24 @@
+using ARMeilleure.State;
+using Ryujinx.Cpu;
+using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Memory;
+
+namespace Ryujinx.HLE.HOS
+{
+    class ArmProcessContext : IProcessContext
+    {
+        private readonly MemoryManager _memoryManager;
+        private readonly CpuContext _cpuContext;
+
+        public IVirtualMemoryManager AddressSpace => _memoryManager;
+
+        public ArmProcessContext(MemoryManager memoryManager)
+        {
+            _memoryManager = memoryManager;
+            _cpuContext = new CpuContext(memoryManager);
+        }
+
+        public void Execute(ExecutionContext context, ulong codeAddress) => _cpuContext.Execute(context, codeAddress);
+        public void Dispose() => _memoryManager.Dispose();
+    }
+}

+ 14 - 0
Ryujinx.HLE/HOS/ArmProcessContextFactory.cs

@@ -0,0 +1,14 @@
+using Ryujinx.Cpu;
+using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Memory;
+
+namespace Ryujinx.HLE.HOS
+{
+    class ArmProcessContextFactory : IProcessContextFactory
+    {
+        public IProcessContext Create(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler)
+        {
+            return new ArmProcessContext(new MemoryManager(backingMemory, addressSpaceSize, invalidAccessHandler));
+        }
+    }
+}

+ 14 - 6
Ryujinx.HLE/HOS/Horizon.cs

@@ -120,11 +120,11 @@ namespace Ryujinx.HLE.HOS
             iirsPageList.AddRange(iirsPa, IirsSize / KMemoryManager.PageSize);
             timePageList.AddRange(timePa, TimeSize / KMemoryManager.PageSize);
 
-            HidSharedMem  = new KSharedMemory(KernelContext, hidPageList,  0, 0, MemoryPermission.Read);
-            FontSharedMem = new KSharedMemory(KernelContext, fontPageList, 0, 0, MemoryPermission.Read);
-            IirsSharedMem = new KSharedMemory(KernelContext, iirsPageList, 0, 0, MemoryPermission.Read);
+            HidSharedMem  = new KSharedMemory(KernelContext, hidPageList,  0, 0, KMemoryPermission.Read);
+            FontSharedMem = new KSharedMemory(KernelContext, fontPageList, 0, 0, KMemoryPermission.Read);
+            IirsSharedMem = new KSharedMemory(KernelContext, iirsPageList, 0, 0, KMemoryPermission.Read);
 
-            KSharedMemory timeSharedMemory = new KSharedMemory(KernelContext, timePageList, 0, 0, MemoryPermission.Read);
+            KSharedMemory timeSharedMemory = new KSharedMemory(KernelContext, timePageList, 0, 0, KMemoryPermission.Read);
 
             TimeServiceManager.Instance.Initialize(device, this, timeSharedMemory, timePa - DramMemoryMap.DramBase, TimeSize);
 
@@ -134,8 +134,6 @@ namespace Ryujinx.HLE.HOS
 
             Font = new SharedFontManager(device, fontPa - DramMemoryMap.DramBase);
 
-            IUserInterface.InitializePort(this);
-
             VsyncEvent = new KEvent(KernelContext);
 
             DisplayResolutionChangeEvent = new KEvent(KernelContext);
@@ -224,6 +222,16 @@ namespace Ryujinx.HLE.HOS
             AudioRendererManager.Initialize(writableEvents, devices);
         }
 
+        public void InitializeServices()
+        {
+            IUserInterface sm = new IUserInterface(KernelContext);
+
+            // Wait until SM server thread is done with initialization,
+            // only then doing connections to SM is safe.
+            sm.Server.InitDone.WaitOne();
+            sm.Server.InitDone.Dispose();
+        }
+
         public void LoadKip(string kipPath)
         {
             using IStorage kipFile = new LocalStorage(kipPath, FileAccess.Read);

+ 20 - 3
Ryujinx.HLE/HOS/Ipc/IpcMessage.cs

@@ -84,6 +84,11 @@ namespace Ryujinx.HLE.HOS.Ipc
 
             long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr);
 
+            if (rawDataSize != 0)
+            {
+                rawDataSize -= (int)pad0;
+            }
+
             reader.BaseStream.Seek(pad0, SeekOrigin.Current);
 
             int recvListCount = recvListFlags - 2;
@@ -107,7 +112,7 @@ namespace Ryujinx.HLE.HOS.Ipc
             }
         }
 
-        public byte[] GetBytes(long cmdPtr)
+        public byte[] GetBytes(long cmdPtr, ulong recvListAddr)
         {
             using (MemoryStream ms = new MemoryStream())
             {
@@ -131,7 +136,11 @@ namespace Ryujinx.HLE.HOS.Ipc
 
                 int dataLength = RawData?.Length ?? 0;
 
-                int pad0 = (int)GetPadSize16(cmdPtr + 8 + handleData.Length);
+                dataLength = (dataLength + 3) & ~3;
+
+                int rawLength = dataLength;
+
+                int pad0 = (int)GetPadSize16(cmdPtr + 8 + handleData.Length + PtrBuff.Count * 8);
 
                 // Apparently, padding after Raw Data is 16 bytes, however when there is
                 // padding before Raw Data too, we need to subtract the size of this padding.
@@ -140,7 +149,7 @@ namespace Ryujinx.HLE.HOS.Ipc
 
                 dataLength = (dataLength + pad0 + pad1) / 4;
 
-                word1 = dataLength & 0x3ff;
+                word1 = (dataLength & 0x3ff) | (2 << 10);
 
                 if (HandleDesc != null)
                 {
@@ -151,14 +160,22 @@ namespace Ryujinx.HLE.HOS.Ipc
                 writer.Write(word1);
                 writer.Write(handleData);
 
+                for (int index = 0; index < PtrBuff.Count; index++)
+                {
+                    writer.Write(PtrBuff[index].GetWord0());
+                    writer.Write(PtrBuff[index].GetWord1());
+                }
+
                 ms.Seek(pad0, SeekOrigin.Current);
 
                 if (RawData != null)
                 {
                     writer.Write(RawData);
+                    ms.Seek(rawLength - RawData.Length, SeekOrigin.Current);
                 }
 
                 writer.Write(new byte[pad1]);
+                writer.Write(recvListAddr);
 
                 return ms.ToArray();
             }

+ 27 - 0
Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs

@@ -8,6 +8,13 @@ namespace Ryujinx.HLE.HOS.Ipc
         public int   Index    { get; private set; }
         public long  Size     { get; private set; }
 
+        public IpcPtrBuffDesc(long position, int index, long size)
+        {
+            Position = position;
+            Index = index;
+            Size = size;
+        }
+
         public IpcPtrBuffDesc(BinaryReader reader)
         {
             long word0 = reader.ReadUInt32();
@@ -22,5 +29,25 @@ namespace Ryujinx.HLE.HOS.Ipc
 
             Size = (ushort)(word0 >> 16);
         }
+
+        public uint GetWord0()
+        {
+            uint word0;
+
+            word0  = (uint)((Position & 0x0f00000000) >> 20);
+            word0 |= (uint)((Position & 0x7000000000) >> 30);
+
+            word0 |= (uint)(Index & 0x03f) << 0;
+            word0 |= (uint)(Index & 0x1c0) << 3;
+
+            word0 |= (uint)Size << 16;
+
+            return word0;
+        }
+
+        public uint GetWord1()
+        {
+            return (uint)Position;
+        }
     }
 }

+ 6 - 0
Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs

@@ -7,6 +7,12 @@ namespace Ryujinx.HLE.HOS.Ipc
         public long Position { get; private set; }
         public long Size     { get; private set; }
 
+        public IpcRecvListBuffDesc(long position, long size)
+        {
+            Position = position;
+            Size = size;
+        }
+
         public IpcRecvListBuffDesc(BinaryReader reader)
         {
             long value = reader.ReadInt64();

+ 11 - 0
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();
+    }
+}

+ 2 - 2
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);

+ 0 - 9
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)

+ 0 - 9
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();
-            }
         }
     }
 }

+ 13 - 21
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;
 

+ 1 - 14
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)

+ 1 - 1
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);
 

+ 38 - 0
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;
+        }
+    }
+}

+ 8 - 8
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;
             }

+ 4 - 4
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)
         {

+ 176 - 151
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)

+ 6 - 6
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;
 

+ 5 - 2
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();
 

+ 1 - 1
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,

+ 5 - 5
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);
 

+ 13 - 0
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);
+    }
+}

+ 10 - 0
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);
+    }
+}

+ 97 - 137
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();
     }
 }

+ 14 - 13
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;
                 }

+ 25 - 0
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()
+        {
+        }
+    }
+}

+ 13 - 0
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));
+        }
+    }
+}

+ 38 - 0
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
+    }
+}

+ 23 - 23
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;
         }
     }
 }

+ 184 - 89
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));

+ 5 - 5
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);

+ 5 - 5
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);
         }

+ 2 - 0
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);

+ 50 - 40
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();
             }

+ 18 - 12
Ryujinx.HLE/HOS/ProgramLoader.cs

@@ -36,23 +36,23 @@ namespace Ryujinx.HLE.HOS
 
             ulong codeAddress = codeBaseAddress + (ulong)kip.TextOffset;
 
-            int mmuFlags = 0;
+            ProcessCreationFlags flags = 0;
 
             if (AslrEnabled)
             {
                 // TODO: Randomization.
 
-                mmuFlags |= 0x20;
+                flags |= ProcessCreationFlags.EnableAslr;
             }
 
             if (kip.Is64BitAddressSpace)
             {
-                mmuFlags |= (int)AddressSpaceType.Addr39Bits << 1;
+                flags |= ProcessCreationFlags.AddressSpace64Bit;
             }
 
             if (kip.Is64Bit)
             {
-                mmuFlags |= 1;
+                flags |= ProcessCreationFlags.Is64Bit;
             }
 
             ProcessCreationInfo creationInfo = new ProcessCreationInfo(
@@ -61,7 +61,7 @@ namespace Ryujinx.HLE.HOS
                 kip.ProgramId,
                 codeAddress,
                 codePagesCount,
-                mmuFlags,
+                flags,
                 0,
                 0);
 
@@ -82,12 +82,15 @@ namespace Ryujinx.HLE.HOS
 
             KProcess process = new KProcess(context);
 
+            var processContextFactory = new ArmProcessContextFactory();
+
             result = process.InitializeKip(
                 creationInfo,
                 kip.Capabilities,
                 pageList,
                 context.ResourceLimit,
-                memoryRegion);
+                memoryRegion,
+                processContextFactory);
 
             if (result != KernelResult.Success)
             {
@@ -183,7 +186,7 @@ namespace Ryujinx.HLE.HOS
                 metaData.Aci0.TitleId,
                 codeStart,
                 codePagesCount,
-                metaData.MmuFlags,
+                (ProcessCreationFlags)metaData.ProcessFlags | ProcessCreationFlags.IsApplication,
                 0,
                 personalMmHeapPagesCount);
 
@@ -217,11 +220,14 @@ namespace Ryujinx.HLE.HOS
                 return false;
             }
 
+            var processContextFactory = new ArmProcessContextFactory();
+
             result = process.Initialize(
                 creationInfo,
                 metaData.Aci0.KernelAccessControl.Capabilities,
                 resourceLimit,
-                memoryRegion);
+                memoryRegion,
+                processContextFactory);
 
             if (result != KernelResult.Success)
             {
@@ -280,7 +286,7 @@ namespace Ryujinx.HLE.HOS
 
             MemoryHelper.FillWithZeros(process.CpuMemory, (long)bssStart, image.BssSize);
 
-            KernelResult SetProcessMemoryPermission(ulong address, ulong size, MemoryPermission permission)
+            KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
             {
                 if (size == 0)
                 {
@@ -292,21 +298,21 @@ namespace Ryujinx.HLE.HOS
                 return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
             }
 
-            KernelResult result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, MemoryPermission.ReadAndExecute);
+            KernelResult result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, KMemoryPermission.ReadAndExecute);
 
             if (result != KernelResult.Success)
             {
                 return result;
             }
 
-            result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, MemoryPermission.Read);
+            result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, KMemoryPermission.Read);
 
             if (result != KernelResult.Success)
             {
                 return result;
             }
 
-            return SetProcessMemoryPermission(dataStart, end - dataStart, MemoryPermission.ReadAndWrite);
+            return SetProcessMemoryPermission(dataStart, end - dataStart, KMemoryPermission.ReadAndWrite);
         }
     }
 }

+ 24 - 28
Ryujinx.HLE/HOS/ServiceCtx.cs

@@ -1,43 +1,39 @@
-using Ryujinx.Cpu;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Memory;
 using System.IO;
 
 namespace Ryujinx.HLE.HOS
 {
     class ServiceCtx
     {
-        public Switch         Device       { get; }
-        public KProcess       Process      { get; }
-        public MemoryManager  Memory       { get; }
-        public KThread        Thread       { get; }
-        public KClientSession Session      { get; }
-        public IpcMessage     Request      { get; }
-        public IpcMessage     Response     { get; }
-        public BinaryReader   RequestData  { get; }
-        public BinaryWriter   ResponseData { get; }
+        public Switch Device { get; }
+        public KProcess Process { get; }
+        public IVirtualMemoryManager Memory { get; }
+        public KThread Thread { get; }
+        public IpcMessage Request { get; }
+        public IpcMessage Response { get; }
+        public BinaryReader RequestData { get; }
+        public BinaryWriter ResponseData { get; }
 
         public ServiceCtx(
-            Switch         device,
-            KProcess       process,
-            MemoryManager  memory,
-            KThread        thread,
-            KClientSession session,
-            IpcMessage     request,
-            IpcMessage     response,
-            BinaryReader   requestData,
-            BinaryWriter   responseData)
+            Switch device,
+            KProcess process,
+            IVirtualMemoryManager memory,
+            KThread thread,
+            IpcMessage request,
+            IpcMessage response,
+            BinaryReader requestData,
+            BinaryWriter responseData)
         {
-            Device       = device;
-            Process      = process;
-            Memory       = memory;
-            Thread       = thread;
-            Session      = session;
-            Request      = request;
-            Response     = response;
-            RequestData  = requestData;
+            Device = device;
+            Process = process;
+            Memory = memory;
+            Thread = thread;
+            Request = request;
+            Response = response;
+            RequestData = requestData;
             ResponseData = responseData;
         }
     }

+ 8 - 3
Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs

@@ -4,7 +4,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
 {
     class ISystemAppletProxy : IpcService
     {
-        public ISystemAppletProxy() { }
+        private readonly long _pid;
+
+        public ISystemAppletProxy(long pid)
+        {
+            _pid = pid;
+        }
 
         [Command(0)]
         // GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
@@ -19,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
         // GetSelfController() -> object<nn::am::service::ISelfController>
         public ResultCode GetSelfController(ServiceCtx context)
         {
-            MakeObject(context, new ISelfController(context.Device.System));
+            MakeObject(context, new ISelfController(context.Device.System, _pid));
 
             return ResultCode.Success;
         }
@@ -28,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
         // GetWindowController() -> object<nn::am::service::IWindowController>
         public ResultCode GetWindowController(ServiceCtx context)
         {
-            MakeObject(context, new IWindowController());
+            MakeObject(context, new IWindowController(_pid));
 
             return ResultCode.Success;
         }

+ 25 - 12
Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs

@@ -18,6 +18,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
         private KEvent _normalOutDataEvent;
         private KEvent _interactiveOutDataEvent;
 
+        private int _stateChangedEventHandle;
+        private int _normalOutDataEventHandle;
+        private int _interactiveOutDataEventHandle;
+
         public ILibraryAppletAccessor(AppletId appletId, Horizon system)
         {
             _stateChangedEvent       = new KEvent(system.KernelContext);
@@ -32,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
             _applet.AppletStateChanged        += OnAppletStateChanged;
             _normalSession.DataAvailable      += OnNormalOutData;
             _interactiveSession.DataAvailable += OnInteractiveOutData;
-            
+
             Logger.Info?.Print(LogClass.ServiceAm, $"Applet '{appletId}' created.");
         }
 
@@ -55,12 +59,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
         // GetAppletStateChangedEvent() -> handle<copy>
         public ResultCode GetAppletStateChangedEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_stateChangedEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out _stateChangedEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangedEventHandle);
 
             return ResultCode.Success;
         }
@@ -69,8 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
         // Start()
         public ResultCode Start(ServiceCtx context)
         {
-            return (ResultCode)_applet.Start(_normalSession.GetConsumer(),
-                                             _interactiveSession.GetConsumer());
+            return (ResultCode)_applet.Start(_normalSession.GetConsumer(), _interactiveSession.GetConsumer());
         }
 
         [Command(30)]
@@ -138,12 +144,16 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
         // GetPopOutDataEvent() -> handle<copy>
         public ResultCode GetPopOutDataEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_normalOutDataEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out _normalOutDataEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_normalOutDataEventHandle);
 
             return ResultCode.Success;
         }
@@ -152,12 +162,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
         // GetPopInteractiveOutDataEvent() -> handle<copy>
         public ResultCode GetPopInteractiveOutDataEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_interactiveOutDataEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out _interactiveOutDataEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_interactiveOutDataEventHandle);
 
             return ResultCode.Success;
         }

+ 18 - 10
Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs

@@ -12,7 +12,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
         private Apm.SystemManagerServer _apmSystemManagerServer;
         private Lbl.LblControllerServer _lblControllerServer;
 
-        private bool _vrModeEnabled = false;
+        private bool _vrModeEnabled;
+        private int _messageEventHandle;
+        private int _displayResolutionChangedEventHandle;
 
         public ICommonStateGetter(ServiceCtx context)
         {
@@ -25,14 +27,17 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
         // GetEventHandle() -> handle<copy>
         public ResultCode GetEventHandle(ServiceCtx context)
         {
-            KEvent Event = context.Device.System.AppletState.MessageEvent;
+            KEvent messageEvent = context.Device.System.AppletState.MessageEvent;
 
-            if (context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_messageEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(messageEvent.ReadableEvent, out _messageEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_messageEventHandle);
 
             return ResultCode.Success;
         }
@@ -147,7 +152,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
                 _lblControllerServer.DisableVrMode();
             }
 
-            // TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used. 
+            // TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
         }
 
         [Command(60)] // 3.0.0+
@@ -164,12 +169,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
         // GetDefaultDisplayResolutionChangeEvent() -> handle<copy>
         public ResultCode GetDefaultDisplayResolutionChangeEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_displayResolutionChangedEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out _displayResolutionChangedEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_displayResolutionChangedEventHandle);
 
             Logger.Stub?.PrintStub(LogClass.ServiceAm);
 
@@ -189,7 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
 
             _apmSystemManagerServer.SetCpuBoostMode((Apm.CpuBoostMode)cpuBoostMode);
 
-            // TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used. 
+            // TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
 
             return ResultCode.Success;
         }

+ 7 - 3
Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs

@@ -9,6 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
     class IHomeMenuFunctions : IpcService
     {
         private KEvent _channelEvent;
+        private int    _channelEventHandle;
 
         public IHomeMenuFunctions(Horizon system)
         {
@@ -29,12 +30,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
         // GetPopFromGeneralChannelEvent() -> handle<copy>
         public ResultCode GetPopFromGeneralChannelEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_channelEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out _channelEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_channelEventHandle);
 
             Logger.Stub?.PrintStub(LogClass.ServiceAm);
 

+ 3 - 1
Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs

@@ -49,7 +49,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
             }
 
             var data = new byte[transferMem.Size];
-            context.Memory.Read(transferMem.Address, data);
+            transferMem.Creator.CpuMemory.Read(transferMem.Address, data);
+
+            context.Device.System.KernelContext.Syscall.CloseHandle(handle);
 
             MakeObject(context, new IStorage(data));
 

+ 37 - 5
Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs

@@ -8,10 +8,13 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
 {
     class ISelfController : IpcService
     {
+        private readonly long _pid;
+
         private KEvent _libraryAppletLaunchableEvent;
+        private int    _libraryAppletLaunchableEventHandle;
 
         private KEvent _accumulatedSuspendedTickChangedEvent;
-        private int    _accumulatedSuspendedTickChangedEventHandle = 0;
+        private int    _accumulatedSuspendedTickChangedEventHandle;
 
         private object _fatalSectionLock = new object();
         private int    _fatalSectionCount;
@@ -32,9 +35,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
         private uint _screenShotImageOrientation = 0;
         private uint _idleTimeDetectionExtension = 0;
 
-        public ISelfController(Horizon system)
+        public ISelfController(Horizon system, long pid)
         {
             _libraryAppletLaunchableEvent = new KEvent(system.KernelContext);
+            _pid = pid;
         }
 
         [Command(0)]
@@ -103,12 +107,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
         {
             _libraryAppletLaunchableEvent.ReadableEvent.Signal();
 
-            if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_libraryAppletLaunchableEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out _libraryAppletLaunchableEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_libraryAppletLaunchableEventHandle);
 
             Logger.Stub?.PrintStub(LogClass.ServiceAm);
 
@@ -206,6 +213,31 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
             return ResultCode.Success;
         }
 
+        [Command(40)]
+        // CreateManagedDisplayLayer() -> u64
+        public ResultCode CreateManagedDisplayLayer(ServiceCtx context)
+        {
+            context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long layerId);
+
+            context.ResponseData.Write(layerId);
+
+            return ResultCode.Success;
+        }
+
+        [Command(44)] // 10.0.0+
+        // CreateManagedDisplaySeparableLayer() -> (u64, u64)
+        public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context)
+        {
+            // NOTE: first create the recoding layer and then the display one because right now Surface Flinger only use the last id.
+            context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long recordingLayerId);
+            context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long displayLayerId);
+
+            context.ResponseData.Write(displayLayerId);
+            context.ResponseData.Write(recordingLayerId);
+
+            return ResultCode.Success;
+        }
+
         [Command(50)]
         // SetHandlesRequestToDisplay(b8)
         public ResultCode SetHandlesRequestToDisplay(ServiceCtx context)

+ 9 - 2
Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IWindowController.cs

@@ -4,7 +4,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
 {
     class IWindowController : IpcService
     {
-        public IWindowController() { }
+        private readonly long _pid;
+
+        public IWindowController(long pid)
+        {
+            _pid = pid;
+        }
 
         [Command(1)]
         // GetAppletResourceUserId() -> nn::applet::AppletResourceUserId
@@ -12,7 +17,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
         {
             Logger.Stub?.PrintStub(LogClass.ServiceAm);
 
-            context.ResponseData.Write(0L);
+            long appletResourceUserId = context.Device.System.AppletState.AppletResourceUserIds.Add(_pid);
+
+            context.ResponseData.Write(appletResourceUserId);
 
             return ResultCode.Success;
         }

+ 1 - 1
Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs

@@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
         // OpenSystemAppletProxy(u64, pid, handle<copy>) -> object<nn::am::service::ISystemAppletProxy>
         public ResultCode OpenSystemAppletProxy(ServiceCtx context)
         {
-            MakeObject(context, new ISystemAppletProxy());
+            MakeObject(context, new ISystemAppletProxy(context.Request.HandleDesc.PId));
 
             return ResultCode.Success;
         }

+ 27 - 16
Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs

@@ -28,6 +28,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         private KEvent _friendInvitationStorageChannelEvent;
         private KEvent _notificationStorageChannelEvent;
 
+        private int _gpuErrorDetectedSystemEventHandle;
+        private int _friendInvitationStorageChannelEventHandle;
+        private int _notificationStorageChannelEventHandle;
+
         public IApplicationFunctions(Horizon system)
         {
             _gpuErrorDetectedSystemEvent         = new KEvent(system.KernelContext);
@@ -122,7 +126,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
                 return ResultCode.Success;
             }
 
-            // If desired language is not supported by application, use first supported language from TitleLanguage. 
+            // If desired language is not supported by application, use first supported language from TitleLanguage.
             // TODO: In the future, a GUI could enable user-specified search priority
             if (((1 << (int)context.Device.System.State.DesiredTitleLanguage) & supportedLanguages) == 0)
             {
@@ -293,12 +297,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
                 resultCode = InitializeApplicationCopyrightFrameBufferImpl(transferMemoryAddress, transferMemorySize, width, height);
             }
 
-            /*
-            if (transferMemoryHandle)
+            if (transferMemoryHandle != 0)
             {
-                svcCloseHandle(transferMemoryHandle);
+                context.Device.System.KernelContext.Syscall.CloseHandle(transferMemoryHandle);
             }
-            */
 
             return resultCode;
         }
@@ -455,15 +457,18 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         // GetGpuErrorDetectedSystemEvent() -> handle<copy>
         public ResultCode GetGpuErrorDetectedSystemEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out int gpuErrorDetectedSystemEventHandle) != KernelResult.Success)
+            if (_gpuErrorDetectedSystemEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out _gpuErrorDetectedSystemEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(gpuErrorDetectedSystemEventHandle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_gpuErrorDetectedSystemEventHandle);
 
-            // NOTE: This is used by "sdk" NSO during applet-application initialization. 
-            //       A seperate thread is setup where event-waiting is handled. 
+            // NOTE: This is used by "sdk" NSO during applet-application initialization.
+            //       A seperate thread is setup where event-waiting is handled.
             //       When the Event is signaled, official sw will assert.
 
             return ResultCode.Success;
@@ -473,12 +478,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         // GetFriendInvitationStorageChannelEvent() -> handle<copy>
         public ResultCode GetFriendInvitationStorageChannelEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out int friendInvitationStorageChannelEventHandle) != KernelResult.Success)
+            if (_friendInvitationStorageChannelEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out _friendInvitationStorageChannelEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(friendInvitationStorageChannelEventHandle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_friendInvitationStorageChannelEventHandle);
 
             return ResultCode.Success;
         }
@@ -501,12 +509,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         // GetNotificationStorageChannelEvent() -> handle<copy>
         public ResultCode GetNotificationStorageChannelEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out int notificationStorageChannelEventHandle) != KernelResult.Success)
+            if (_notificationStorageChannelEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out _notificationStorageChannelEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(notificationStorageChannelEventHandle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationStorageChannelEventHandle);
 
             return ResultCode.Success;
         }

+ 8 - 3
Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs

@@ -5,7 +5,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
 {
     class IApplicationProxy : IpcService
     {
-        public IApplicationProxy() { }
+        private readonly long _pid;
+
+        public IApplicationProxy(long pid)
+        {
+            _pid = pid;
+        }
 
         [Command(0)]
         // GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
@@ -20,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
         // GetSelfController() -> object<nn::am::service::ISelfController>
         public ResultCode GetSelfController(ServiceCtx context)
         {
-            MakeObject(context, new ISelfController(context.Device.System));
+            MakeObject(context, new ISelfController(context.Device.System, _pid));
 
             return ResultCode.Success;
         }
@@ -29,7 +34,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
         // GetWindowController() -> object<nn::am::service::IWindowController>
         public ResultCode GetWindowController(ServiceCtx context)
         {
-            MakeObject(context, new IWindowController());
+            MakeObject(context, new IWindowController(_pid));
 
             return ResultCode.Success;
         }

+ 1 - 1
Ryujinx.HLE/HOS/Services/Am/AppletOE/IApplicationProxyService.cs

@@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
         // OpenApplicationProxy(u64, pid, handle<copy>) -> object<nn::am::service::IApplicationProxy>
         public ResultCode OpenApplicationProxy(ServiceCtx context)
         {
-            MakeObject(context, new IApplicationProxy());
+            MakeObject(context, new IApplicationProxy(context.Request.HandleDesc.PId));
 
             return ResultCode.Success;
         }

+ 14 - 8
Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs

@@ -10,15 +10,18 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
 {
     class IAudioOut : IpcService, IDisposable
     {
-        private IAalOutput _audioOut;
-        private KEvent     _releaseEvent;
-        private int        _track;
+        private readonly IAalOutput _audioOut;
+        private readonly KEvent     _releaseEvent;
+        private          int        _releaseEventHandle;
+        private readonly int        _track;
+        private readonly int        _clientHandle;
 
-        public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track)
+        public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track, int clientHandle)
         {
             _audioOut     = audioOut;
             _releaseEvent = releaseEvent;
             _track        = track;
+            _clientHandle = clientHandle;
         }
 
         [Command(0)]
@@ -59,12 +62,15 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
         // RegisterBufferEvent() -> handle<copy>
         public ResultCode RegisterBufferEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_releaseEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out _releaseEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_releaseEventHandle);
 
             return ResultCode.Success;
         }
@@ -108,7 +114,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
             // NOTE: Assume PCM16 all the time, change if new format are found.
             short[] buffer = new short[data.SampleBufferSize / sizeof(short)];
 
-            context.Memory.Read((ulong)data.SampleBufferPtr, MemoryMarshal.Cast<short, byte>(buffer));
+            context.Process.HandleTable.GetKProcess(_clientHandle).CpuMemory.Read((ulong)data.SampleBufferPtr, MemoryMarshal.Cast<short, byte>(buffer));
 
             _audioOut.AppendBuffer(_track, tag, buffer);
 

+ 3 - 1
Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs

@@ -33,7 +33,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
 
         public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle)
         {
-            ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, context.Memory, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle);
+            var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory;
+
+            ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, memoryManager, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle);
 
             if (result == ResultCode.Success)
             {

+ 4 - 2
Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs

@@ -14,9 +14,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
 
         private IAudioRendererManager _impl;
 
-        public AudioRendererManagerServer(ServiceCtx context) : this(new AudioRendererManager(context.Device.System.AudioRendererManager, context.Device.System.AudioDeviceSessionRegistry)) { }
+        public AudioRendererManagerServer(ServiceCtx context) : this(context, new AudioRendererManager(context.Device.System.AudioRendererManager, context.Device.System.AudioDeviceSessionRegistry)) { }
 
-        public AudioRendererManagerServer(IAudioRendererManager impl) : base(new ServerBase("AudioRendererServer"))
+        public AudioRendererManagerServer(ServiceCtx context, IAudioRendererManager impl) : base(new ServerBase(context.Device.System.KernelContext, "AudioRendererServer"))
         {
             _impl = impl;
         }
@@ -40,6 +40,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio
                 MakeObject(context, new AudioRendererServer(renderer));
             }
 
+            context.Device.System.KernelContext.Syscall.CloseHandle((int)processHandle);
+
             return result;
         }
 

+ 2 - 1
Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs

@@ -1,4 +1,5 @@
 using Ryujinx.Cpu;
+using Ryujinx.Memory;
 using System;
 using System.Text;
 
@@ -57,7 +58,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
             return ResultCode.Success;
         }
 
-        private uint ListAudioInsImpl(MemoryManager memory, long bufferPosition, long bufferSize, bool filtered = false)
+        private uint ListAudioInsImpl(IVirtualMemoryManager memory, long bufferPosition, long bufferSize, bool filtered = false)
         {
             uint count = 0;
 

+ 2 - 2
Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs

@@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
         private const int    DefaultSampleRate    = 48000;
         private const int    DefaultChannelsCount = 2;
 
-        public IAudioOutManager(ServiceCtx context) : base(new ServerBase("AudioOutServer")) { }
+        public IAudioOutManager(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "AudioOutServer")) { }
 
         [Command(0)]
         // ListAudioOuts() -> (u32 count, buffer<bytes, 6>)
@@ -134,7 +134,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
 
             int track = audioOut.OpenTrack(sampleRate, channels, callback);
 
-            MakeObject(context, new IAudioOut(audioOut, releaseEvent, track));
+            MakeObject(context, new IAudioOut(audioOut, releaseEvent, track, context.Request.HandleDesc.ToCopy[0]));
 
             context.ResponseData.Write(sampleRate);
             context.ResponseData.Write(channels);

+ 3 - 0
Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs

@@ -16,6 +16,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
 
             MakeObject(context, new IHardwareOpusDecoder(sampleRate, channelsCount));
 
+            // Close transfer memory immediately as we don't use it.
+            context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
+
             return ResultCode.Success;
         }
 

+ 7 - 3
Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs

@@ -12,6 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
     class IDeliveryCacheProgressService : IpcService
     {
         private KEvent _event;
+        private int    _eventHandle;
 
         public IDeliveryCacheProgressService(ServiceCtx context)
         {
@@ -22,12 +23,15 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
         // GetEvent() -> handle<copy>
         public ResultCode GetEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_eventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_eventHandle);
 
             Logger.Stub?.PrintStub(LogClass.ServiceBcat);
 

+ 6 - 16
Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs

@@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
         }
 
         [Command(8)]
-        // OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path) 
+        // OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path)
         // -> object<nn::fssrv::sf::IFileSystem> contentFs
         public ResultCode OpenFileSystemWithId(ServiceCtx context)
         {
@@ -138,12 +138,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
             // Workaround that by setting the application ID and owner ID if they're not already set
             if (attribute.ProgramId == ProgramId.InvalidId)
             {
-                attribute.ProgramId = new ProgramId(context.Process.TitleId);
-            }
-
-            if (creationInfo.OwnerId == 0)
-            {
-                creationInfo.OwnerId = 0;
+                attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
             }
 
             Logger.Info?.Print(LogClass.ServiceFs, $"Creating save with title ID {attribute.ProgramId.Value:x16}");
@@ -215,12 +210,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
             // Workaround that by setting the application ID and owner ID if they're not already set
             if (attribute.ProgramId == ProgramId.InvalidId)
             {
-                attribute.ProgramId = new ProgramId(context.Process.TitleId);
-            }
-
-            if (creationInfo.OwnerId == 0)
-            {
-                creationInfo.OwnerId = 0;
+                attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
             }
 
             Result result = _baseFileSystemProxy.CreateSaveDataFileSystemWithHashSalt(ref attribute, ref creationInfo, ref metaCreateInfo, ref hashSalt);
@@ -239,7 +229,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
             // Workaround that by setting the application ID if it's not already set
             if (attribute.ProgramId == ProgramId.InvalidId)
             {
-                attribute.ProgramId = new ProgramId(context.Process.TitleId);
+                attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
             }
 
             Result result = _baseFileSystemProxy.OpenSaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute);
@@ -280,7 +270,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
             // Workaround that by setting the application ID if it's not already set
             if (attribute.ProgramId == ProgramId.InvalidId)
             {
-                attribute.ProgramId = new ProgramId(context.Process.TitleId);
+                attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
             }
 
             Result result = _baseFileSystemProxy.OpenReadOnlySaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute);
@@ -328,7 +318,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
             filter.SetSaveDataType(SaveDataType.Cache);
             filter.SetProgramId(new ProgramId(context.Process.TitleId));
 
-            // FS would query the User and SdCache space IDs to find where the existing cache is (if any). 
+            // FS would query the User and SdCache space IDs to find where the existing cache is (if any).
             // We always have the SD card inserted, so we can always use SdCache for now.
             Result result = _baseFileSystemProxy.OpenSaveDataInfoReaderBySaveDataSpaceId(
                 out ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> infoReader, SaveDataSpaceId.SdCache);

+ 7 - 3
Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs

@@ -8,6 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
     class IAppletResource : IpcService
     {
         private KSharedMemory _hidSharedMem;
+        private int           _hidSharedMemHandle;
 
         public IAppletResource(KSharedMemory hidSharedMem)
         {
@@ -18,12 +19,15 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
         // GetSharedMemoryHandle() -> handle<copy>
         public ResultCode GetSharedMemoryHandle(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out int handle) != KernelResult.Success)
+            if (_hidSharedMemHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out _hidSharedMemHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_hidSharedMemHandle);
 
             return ResultCode.Success;
         }

+ 12 - 12
Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs

@@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         private HidAccelerometerParameters _accelerometerParams;
         private HidVibrationValue          _vibrationValue;
 
-        public IHidServer(ServiceCtx context) : base(new ServerBase("HidServer"))
+        public IHidServer(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "HidServer"))
         {
             _xpadIdEvent                 = new KEvent(context.Device.System.KernelContext);
             _palmaOperationCompleteEvent = new KEvent(context.Device.System.KernelContext);
@@ -559,9 +559,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             ControllerType type = (ControllerType)context.RequestData.ReadInt32();
             long appletResourceUserId = context.RequestData.ReadInt64();
 
-            Logger.Stub?.PrintStub(LogClass.ServiceHid, new { 
-                    appletResourceUserId, 
-                    type 
+            Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
+                    appletResourceUserId,
+                    type
                 });
 
             context.Device.Hid.Npads.SupportedStyleSets = type;
@@ -577,9 +577,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
 
             context.ResponseData.Write((int)context.Device.Hid.Npads.SupportedStyleSets);
 
-            Logger.Stub?.PrintStub(LogClass.ServiceHid, new { 
+            Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
                     appletResourceUserId,
-                    context.Device.Hid.Npads.SupportedStyleSets 
+                    context.Device.Hid.Npads.SupportedStyleSets
                 });
 
             return ResultCode.Success;
@@ -704,9 +704,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             long appletResourceUserId = context.RequestData.ReadInt64();
             context.Device.Hid.Npads.JoyHold = (NpadJoyHoldType)context.RequestData.ReadInt64();
 
-            Logger.Stub?.PrintStub(LogClass.ServiceHid, new { 
-                    appletResourceUserId, 
-                    context.Device.Hid.Npads.JoyHold 
+            Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
+                    appletResourceUserId,
+                    context.Device.Hid.Npads.JoyHold
                 });
 
             return ResultCode.Success;
@@ -720,9 +720,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
 
             context.ResponseData.Write((long)context.Device.Hid.Npads.JoyHold);
 
-            Logger.Stub?.PrintStub(LogClass.ServiceHid, new { 
-                    appletResourceUserId, 
-                    context.Device.Hid.Npads.JoyHold 
+            Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
+                    appletResourceUserId,
+                    context.Device.Hid.Npads.JoyHold
                 });
 
             return ResultCode.Success;

+ 24 - 38
Ryujinx.HLE/HOS/Services/IpcService.cs

@@ -1,8 +1,6 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
-using Ryujinx.HLE.HOS.Kernel.Ipc;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -17,6 +15,7 @@ namespace Ryujinx.HLE.HOS.Services
 
         public ServerBase Server { get; private set; }
 
+        private IpcService _parent;
         private IdDictionary _domainObjects;
         private int _selfId;
         private bool _isDomain;
@@ -32,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Services
 
             Server = server;
 
+            _parent = this;
             _domainObjects = new IdDictionary();
             _selfId = -1;
         }
@@ -62,8 +62,8 @@ namespace Ryujinx.HLE.HOS.Services
                 int domainWord0 = context.RequestData.ReadInt32();
                 int domainObjId = context.RequestData.ReadInt32();
 
-                int domainCmd       = (domainWord0 >> 0)  & 0xff;
-                int inputObjCount   = (domainWord0 >> 8)  & 0xff;
+                int domainCmd = (domainWord0 >> 0) & 0xff;
+                int inputObjCount = (domainWord0 >> 8) & 0xff;
                 int dataPayloadSize = (domainWord0 >> 16) & 0xffff;
 
                 context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin);
@@ -96,8 +96,8 @@ namespace Ryujinx.HLE.HOS.Services
                 }
             }
 
-            long sfciMagic =      context.RequestData.ReadInt64();
-            int  commandId = (int)context.RequestData.ReadInt64();
+            long sfciMagic = context.RequestData.ReadInt64();
+            int commandId = (int)context.RequestData.ReadInt64();
 
             bool serviceExists = service.Commands.TryGetValue(commandId, out MethodInfo processRequest);
 
@@ -145,56 +145,37 @@ namespace Ryujinx.HLE.HOS.Services
             {
                 string dbgMessage = $"{service.GetType().FullName}: {commandId}";
 
-                throw new ServiceNotImplementedException(context, dbgMessage);
+                throw new ServiceNotImplementedException(service, context, dbgMessage);
             }
         }
 
-        protected static void MakeObject(ServiceCtx context, IpcService obj)
+        protected void MakeObject(ServiceCtx context, IpcService obj)
         {
-            IpcService service = context.Session.Service;
+            obj.TrySetServer(_parent.Server);
 
-            obj.TrySetServer(service.Server);
-
-            if (service._isDomain)
+            if (_parent._isDomain)
             {
-                context.Response.ObjectIds.Add(service.Add(obj));
+                obj._parent = _parent;
+
+                context.Response.ObjectIds.Add(_parent.Add(obj));
             }
             else
             {
-                KSession session = new KSession(context.Device.System.KernelContext);
-
-                session.ClientSession.Service = obj;
-
-                if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != KernelResult.Success)
-                {
-                    throw new InvalidOperationException("Out of handles!");
-                }
+                context.Device.System.KernelContext.Syscall.CreateSession(false, 0, out int serverSessionHandle, out int clientSessionHandle);
 
-                session.ServerSession.DecrementReferenceCount();
-                session.ClientSession.DecrementReferenceCount();
+                obj.Server.AddSessionObj(serverSessionHandle, obj);
 
-                context.Response.HandleDesc = IpcHandleDesc.MakeMove(handle);
+                context.Response.HandleDesc = IpcHandleDesc.MakeMove(clientSessionHandle);
             }
         }
 
-        protected static T GetObject<T>(ServiceCtx context, int index) where T : IpcService
+        protected T GetObject<T>(ServiceCtx context, int index) where T : IpcService
         {
-            IpcService service = context.Session.Service;
-
-            if (!service._isDomain)
-            {
-                int handle = context.Request.HandleDesc.ToMove[index];
-
-                KClientSession session = context.Process.HandleTable.GetObject<KClientSession>(handle);
-
-                return session?.Service is T ? (T)session.Service : null;
-            }
-
             int objId = context.Request.ObjectIds[index];
 
-            IIpcService obj = service.GetObject(objId);
+            IIpcService obj = _parent.GetObject(objId);
 
-            return obj is T ? (T)obj : null;
+            return obj is T t ? t : null;
         }
 
         public bool TrySetServer(ServerBase newServer)
@@ -230,5 +211,10 @@ namespace Ryujinx.HLE.HOS.Services
         {
             return _domainObjects.GetData<IIpcService>(id);
         }
+
+        public void SetParent(IpcService parent)
+        {
+            _parent = parent._parent;
+        }
     }
 }

+ 16 - 16
Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs

@@ -103,98 +103,98 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
         // StartDetection(bytes<8, 4>)
         public ResultCode StartDetection(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(4)]
         // StopDetection(bytes<8, 4>)
         public ResultCode StopDetection(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(5)]
         // Mount(bytes<8, 4>, u32, u32)
         public ResultCode Mount(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(6)]
         // Unmount(bytes<8, 4>)
         public ResultCode Unmount(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(7)]
         // OpenApplicationArea(bytes<8, 4>, u32)
         public ResultCode OpenApplicationArea(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(8)]
         // GetApplicationArea(bytes<8, 4>) -> (u32, buffer<unknown, 6>)
         public ResultCode GetApplicationArea(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(9)]
         // SetApplicationArea(bytes<8, 4>, buffer<unknown, 5>)
         public ResultCode SetApplicationArea(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(10)]
         // Flush(bytes<8, 4>)
         public ResultCode Flush(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(11)]
         // Restore(bytes<8, 4>)
         public ResultCode Restore(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(12)]
         // CreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
         public ResultCode CreateApplicationArea(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(13)]
         // GetTagInfo(bytes<8, 4>) -> buffer<unknown<0x58>, 0x1a>
         public ResultCode GetTagInfo(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(14)]
         // GetRegisterInfo(bytes<8, 4>) -> buffer<unknown<0x100>, 0x1a>
         public ResultCode GetRegisterInfo(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(15)]
         // GetCommonInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
         public ResultCode GetCommonInfo(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(16)]
         // GetModelInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
         public ResultCode GetModelInfo(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(17)]
@@ -308,7 +308,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
         // GetApplicationAreaSize(bytes<8, 4>) -> u32
         public ResultCode GetApplicationAreaSize(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(23)] // 3.0.0+
@@ -334,7 +334,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
         // RecreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
         public ResultCode RecreateApplicationArea(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
     }
 }

+ 15 - 6
Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs

@@ -11,6 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
         private KEvent _event0;
         private KEvent _event1;
 
+        private int _event0Handle;
+        private int _event1Handle;
+
         private uint _version;
 
         public IRequest(Horizon system, uint version)
@@ -50,17 +53,23 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
         // GetSystemEventReadableHandles() -> (handle<copy>, handle<copy>)
         public ResultCode GetSystemEventReadableHandles(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out int handle0) != KernelResult.Success)
+            if (_event0Handle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out _event0Handle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out int handle1) != KernelResult.Success)
+            if (_event1Handle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out _event1Handle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle0, handle1);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_event0Handle, _event1Handle);
 
             return ResultCode.Success;
         }
@@ -107,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
                 return ResultCode.Unknown180;
             }
 
-            // Returns appletId, libraryAppletMode, outSize and a buffer. 
+            // Returns appletId, libraryAppletMode, outSize and a buffer.
             // Returned applet ids- (0x19, 0xf, 0xe)
             // libraryAppletMode seems to be 0 for all applets supported.
 

+ 8 - 3
Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs

@@ -11,6 +11,8 @@ namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServ
     {
         private readonly KEvent _event;
 
+        private int _eventHandle;
+
         public IShopServiceAccessor(Horizon system)
         {
             _event = new KEvent(system.KernelContext);
@@ -22,12 +24,15 @@ namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServ
         {
             MakeObject(context, new IShopServiceAsync());
 
-            if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_eventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_eventHandle);
 
             Logger.Stub?.PrintStub(LogClass.ServiceNim);
 

+ 11 - 6
Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs

@@ -9,7 +9,9 @@ namespace Ryujinx.HLE.HOS.Services.Ns
     [Service("aoc:u")]
     class IAddOnContentManager : IpcService
     {
-        KEvent _addOnContentListChangedEvent;
+        private readonly KEvent _addOnContentListChangedEvent;
+
+        private int _addOnContentListChangedEventHandle;
 
         public IAddOnContentManager(ServiceCtx context)
         {
@@ -22,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns
         {
             long pid = context.Process.Pid;
 
-            // Official code checks ApplicationControlProperty.RuntimeAddOnContentInstall 
+            // Official code checks ApplicationControlProperty.RuntimeAddOnContentInstall
             // if true calls ns:am ListAvailableAddOnContent again to get updated count
 
             byte runtimeAddOnContentInstall = context.Device.Application.ControlData.Value.RuntimeAddOnContentInstall;
@@ -135,12 +137,15 @@ namespace Ryujinx.HLE.HOS.Services.Ns
         {
             // Official code seems to make an internal call to ns:am Cmd 84 GetDynamicCommitEvent()
 
-            if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (_addOnContentListChangedEventHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out _addOnContentListChangedEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_addOnContentListChangedEventHandle);
 
             Logger.Stub?.PrintStub(LogClass.ServiceNs);
 
@@ -148,7 +153,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns
         }
 
 
-        [Command(9)] // [10.0.0+] 
+        [Command(9)] // [10.0.0+]
         // GetAddOnContentLostErrorCode() -> u64
         public ResultCode GetAddOnContentLostErrorCode(ServiceCtx context)
         {

+ 35 - 32
Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs

@@ -4,7 +4,6 @@ using Ryujinx.Cpu;
 using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Memory;
-using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel;
@@ -12,6 +11,7 @@ using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
 using Ryujinx.HLE.HOS.Services.Nv.Types;
+using Ryujinx.Memory;
 using System;
 using System.Collections.Generic;
 using System.Reflection;
@@ -27,47 +27,45 @@ namespace Ryujinx.HLE.HOS.Services.Nv
         private static Dictionary<string, Type> _deviceFileRegistry =
                    new Dictionary<string, Type>()
         {
-                       { "/dev/nvmap",           typeof(NvMapDeviceFile)         },
-                       { "/dev/nvhost-ctrl",     typeof(NvHostCtrlDeviceFile)    },
-                       { "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuDeviceFile) },
-                       { "/dev/nvhost-as-gpu",   typeof(NvHostAsGpuDeviceFile)   },
-                       { "/dev/nvhost-gpu",      typeof(NvHostGpuDeviceFile)     },
-                     //{ "/dev/nvhost-msenc",    typeof(NvHostChannelDeviceFile) },
-                       { "/dev/nvhost-nvdec",    typeof(NvHostChannelDeviceFile) },
-                     //{ "/dev/nvhost-nvjpg",    typeof(NvHostChannelDeviceFile) },
-                       { "/dev/nvhost-vic",      typeof(NvHostChannelDeviceFile) },
-                     //{ "/dev/nvhost-display",  typeof(NvHostChannelDeviceFile) },
+            { "/dev/nvmap",           typeof(NvMapDeviceFile)         },
+            { "/dev/nvhost-ctrl",     typeof(NvHostCtrlDeviceFile)    },
+            { "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuDeviceFile) },
+            { "/dev/nvhost-as-gpu",   typeof(NvHostAsGpuDeviceFile)   },
+            { "/dev/nvhost-gpu",      typeof(NvHostGpuDeviceFile)     },
+            //{ "/dev/nvhost-msenc",    typeof(NvHostChannelDeviceFile) },
+            { "/dev/nvhost-nvdec",    typeof(NvHostChannelDeviceFile) },
+            //{ "/dev/nvhost-nvjpg",    typeof(NvHostChannelDeviceFile) },
+            { "/dev/nvhost-vic",      typeof(NvHostChannelDeviceFile) },
+            //{ "/dev/nvhost-display",  typeof(NvHostChannelDeviceFile) },
         };
 
         private static IdDictionary _deviceFileIdRegistry = new IdDictionary();
 
-        private KProcess _owner;
+        private IVirtualMemoryManager _clientMemory;
+        private long _owner;
 
         private bool _transferMemInitialized = false;
 
-        public INvDrvServices(ServiceCtx context) : base(new ServerBase("NvservicesServer"))
+        public INvDrvServices(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "NvservicesServer"))
         {
-            _owner = null;
+            _owner = 0;
         }
 
         private int Open(ServiceCtx context, string path)
         {
-            if (context.Process == _owner)
+            if (_deviceFileRegistry.TryGetValue(path, out Type deviceFileClass))
             {
-                if (_deviceFileRegistry.TryGetValue(path, out Type deviceFileClass))
-                {
-                    ConstructorInfo constructor = deviceFileClass.GetConstructor(new Type[] { typeof(ServiceCtx) });
+                ConstructorInfo constructor = deviceFileClass.GetConstructor(new Type[] { typeof(ServiceCtx), typeof(IVirtualMemoryManager), typeof(long) });
 
-                    NvDeviceFile deviceFile = (NvDeviceFile)constructor.Invoke(new object[] { context });
+                NvDeviceFile deviceFile = (NvDeviceFile)constructor.Invoke(new object[] { context, _clientMemory, _owner });
 
-                    deviceFile.Path = path;
+                deviceFile.Path = path;
 
-                    return _deviceFileIdRegistry.Add(deviceFile);
-                }
-                else
-                {
-                    Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
-                }
+                return _deviceFileIdRegistry.Add(deviceFile);
+            }
+            else
+            {
+                Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
             }
 
             return -1;
@@ -150,7 +148,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
                 return NvResult.NotImplemented;
             }
 
-            if (deviceFile.Owner.Pid != _owner.Pid)
+            if (deviceFile.Owner != _owner)
             {
                 return NvResult.AccessDenied;
             }
@@ -160,7 +158,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
 
         private NvResult EnsureInitialized()
         {
-            if (_owner == null)
+            if (_owner == 0)
             {
                 Logger.Warning?.Print(LogClass.ServiceNv, "INvDrvServices is not initialized!");
 
@@ -229,8 +227,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             if (errorCode == NvResult.Success)
             {
                 long pathPtr = context.Request.SendBuff[0].Position;
+                long pathSize = context.Request.SendBuff[0].Size;
 
-                string path = MemoryHelper.ReadAsciiString(context.Memory, pathPtr);
+                string path = MemoryHelper.ReadAsciiString(context.Memory, pathPtr, pathSize);
 
                 fd = Open(context, path);
 
@@ -322,7 +321,11 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             // TODO: When transfer memory will be implemented, this could be removed.
             _transferMemInitialized = true;
 
-            _owner = context.Process;
+            int clientHandle = context.Request.HandleDesc.ToCopy[0];
+
+            _clientMemory = context.Process.HandleTable.GetKProcess(clientHandle).CpuMemory;
+
+            context.Device.System.KernelContext.Syscall.GetProcessId(clientHandle, out _owner);
 
             context.ResponseData.Write((uint)NvResult.Success);
 
@@ -425,7 +428,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
         // ForceSetClientPid(u64) -> u32 error_code
         public ResultCode ForceSetClientPid(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(8)]
@@ -452,7 +455,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
         // InitializeDevtools(u32, handle<copy>) -> u32 error_code;
         public ResultCode InitializeDevtools(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(11)] // 3.0.0+

+ 3 - 4
Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvDeviceFile.cs

@@ -1,6 +1,5 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Kernel.Memory;
-using Ryujinx.HLE.HOS.Kernel.Process;
 using System;
 using System.Diagnostics;
 using System.Reflection;
@@ -12,14 +11,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices
     abstract class NvDeviceFile
     {
         public readonly ServiceCtx Context;
-        public readonly KProcess   Owner;
+        public readonly long       Owner;
 
         public string Path;
 
-        public NvDeviceFile(ServiceCtx context)
+        public NvDeviceFile(ServiceCtx context, long owner)
         {
             Context = context;
-            Owner   = context.Process;
+            Owner   = owner;
         }
 
         public virtual NvInternalResult QueryEvent(out int eventHandle, uint eventId)

+ 2 - 1
Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs

@@ -3,6 +3,7 @@ using Ryujinx.Graphics.Gpu.Memory;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
+using Ryujinx.Memory;
 using System;
 using System.Collections.Concurrent;
 
@@ -12,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
     {
         private static ConcurrentDictionary<KProcess, AddressSpaceContext> _addressSpaceContextRegistry = new ConcurrentDictionary<KProcess, AddressSpaceContext>();
 
-        public NvHostAsGpuDeviceFile(ServiceCtx context) : base(context) { }
+        public NvHostAsGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner) { }
 
         public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
         {

+ 5 - 4
Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs

@@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
 using Ryujinx.HLE.HOS.Services.Nv.Types;
+using Ryujinx.Memory;
 using System;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
@@ -19,9 +20,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
         private uint _submitTimeout;
         private uint _timeslice;
 
-        private Switch _device;
+        private readonly Switch _device;
 
-        private Cpu.MemoryManager _memory;
+        private readonly IVirtualMemoryManager _memory;
 
         public enum ResourcePolicy
         {
@@ -37,10 +38,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
 
         private NvFence _channelSyncpoint;
 
-        public NvHostChannelDeviceFile(ServiceCtx context) : base(context)
+        public NvHostChannelDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
         {
             _device        = context.Device;
-            _memory        = context.Memory;
+            _memory        = memory;
             _timeout       = 3000;
             _submitTimeout = 0;
             _timeslice     = 0;

+ 3 - 2
Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs

@@ -1,6 +1,7 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
+using Ryujinx.Memory;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
@@ -11,7 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
         private KEvent _smExceptionBptPauseReportEvent;
         private KEvent _errorNotifierEvent;
 
-        public NvHostGpuDeviceFile(ServiceCtx context) : base(context)
+        public NvHostGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, memory, owner)
         {
             _smExceptionBptIntReportEvent   = new KEvent(context.Device.System.KernelContext);
             _smExceptionBptPauseReportEvent = new KEvent(context.Device.System.KernelContext);
@@ -55,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
 
             if (targetEvent != null)
             {
-                if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
+                if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }

+ 3 - 3
Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlDeviceFile.cs

@@ -5,7 +5,7 @@ using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl.Types;
 using Ryujinx.HLE.HOS.Services.Nv.Types;
 using Ryujinx.HLE.HOS.Services.Settings;
-
+using Ryujinx.Memory;
 using System;
 using System.Text;
 using System.Threading;
@@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
         private Switch        _device;
         private NvHostEvent[] _events;
 
-        public NvHostCtrlDeviceFile(ServiceCtx context) : base(context)
+        public NvHostCtrlDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
         {
             if (NxSettings.Settings.TryGetValue("nv!rmos_set_production_mode", out object productionModeSetting))
             {
@@ -126,7 +126,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
 
             if (targetEvent != null)
             {
-                if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
+                if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }

+ 3 - 2
Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs

@@ -2,6 +2,7 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types;
+using Ryujinx.Memory;
 using System;
 using System.Diagnostics;
 
@@ -15,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu
         private KEvent _errorEvent;
         private KEvent _unknownEvent;
 
-        public NvHostCtrlGpuDeviceFile(ServiceCtx context) : base(context)
+        public NvHostCtrlGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
         {
             _errorEvent   = new KEvent(context.Device.System.KernelContext);
             _unknownEvent = new KEvent(context.Device.System.KernelContext);
@@ -98,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu
 
             if (targetEvent != null)
             {
-                if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
+                if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }

+ 12 - 12
Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs

@@ -1,7 +1,7 @@
 using Ryujinx.Common;
 using Ryujinx.Common.Logging;
 using Ryujinx.Graphics.Gpu.Memory;
-using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Memory;
 using System;
 using System.Collections.Concurrent;
 
@@ -11,9 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
     {
         private const int FlagNotFreedYet = 1;
 
-        private static ConcurrentDictionary<KProcess, IdDictionary> _maps = new ConcurrentDictionary<KProcess, IdDictionary>();
+        private static ConcurrentDictionary<long, IdDictionary> _maps = new ConcurrentDictionary<long, IdDictionary>();
 
-        public NvMapDeviceFile(ServiceCtx context) : base(context)
+        public NvMapDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
         {
             IdDictionary dict = _maps.GetOrAdd(Owner, (key) => new IdDictionary());
 
@@ -244,9 +244,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
             return dict.Add(map);
         }
 
-        private static bool DeleteMapWithHandle(KProcess process, int handle)
+        private static bool DeleteMapWithHandle(long pid, int handle)
         {
-            if (_maps.TryGetValue(process, out IdDictionary dict))
+            if (_maps.TryGetValue(pid, out IdDictionary dict))
             {
                 return dict.Delete(handle) != null;
             }
@@ -254,14 +254,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
             return false;
         }
 
-        public static void IncrementMapRefCount(KProcess process, int handle, bool allowHandleZero = false)
+        public static void IncrementMapRefCount(long pid, int handle, bool allowHandleZero = false)
         {
-            GetMapFromHandle(process, handle, allowHandleZero)?.IncrementRefCount();
+            GetMapFromHandle(pid, handle, allowHandleZero)?.IncrementRefCount();
         }
 
-        public static bool DecrementMapRefCount(KProcess process, int handle)
+        public static bool DecrementMapRefCount(long pid, int handle)
         {
-            NvMapHandle map = GetMapFromHandle(process, handle, false);
+            NvMapHandle map = GetMapFromHandle(pid, handle, false);
 
             if (map == null)
             {
@@ -270,7 +270,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
 
             if (map.DecrementRefCount() <= 0)
             {
-                DeleteMapWithHandle(process, handle);
+                DeleteMapWithHandle(pid, handle);
 
                 Logger.Info?.Print(LogClass.ServiceNv, $"Deleted map {handle}!");
 
@@ -282,9 +282,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
             }
         }
 
-        public static NvMapHandle GetMapFromHandle(KProcess process, int handle, bool allowHandleZero = false)
+        public static NvMapHandle GetMapFromHandle(long pid, int handle, bool allowHandleZero = false)
         {
-            if ((allowHandleZero || handle != 0) && _maps.TryGetValue(process, out IdDictionary dict))
+            if ((allowHandleZero || handle != 0) && _maps.TryGetValue(pid, out IdDictionary dict))
             {
                 return dict.GetData<NvMapHandle>(handle);
             }

+ 19 - 18
Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs

@@ -53,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
                 return ResultCode.InvalidAddress;
             }
 
-            StructReader reader = new StructReader(context.Memory, nrrAddress);
+            StructReader reader = new StructReader(_owner.CpuMemory, nrrAddress);
             NrrHeader    header = reader.Read<NrrHeader>();
 
             if (header.Magic != NrrMagic)
@@ -71,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
             {
                 byte[] temp = new byte[0x20];
 
-                context.Memory.Read((ulong)(nrrAddress + header.HashOffset + (i * 0x20)), temp);
+                _owner.CpuMemory.Read((ulong)(nrrAddress + header.HashOffset + (i * 0x20)), temp);
 
                 hashes.Add(temp);
             }
@@ -131,8 +131,8 @@ namespace Ryujinx.HLE.HOS.Services.Ro
                 return ResultCode.InvalidAddress;
             }
 
-            uint magic       = context.Memory.Read<uint>(nroAddress + 0x10);
-            uint nroFileSize = context.Memory.Read<uint>(nroAddress + 0x18);
+            uint magic       = _owner.CpuMemory.Read<uint>(nroAddress + 0x10);
+            uint nroFileSize = _owner.CpuMemory.Read<uint>(nroAddress + 0x18);
 
             if (magic != NroMagic || nroSize != nroFileSize)
             {
@@ -141,7 +141,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
 
             byte[] nroData = new byte[nroSize];
 
-            context.Memory.Read(nroAddress, nroData);
+            _owner.CpuMemory.Read(nroAddress, nroData);
 
             byte[] nroHash = null;
 
@@ -176,7 +176,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
             // Check if everything is contiguous.
             if (nro.RoOffset   != nro.TextOffset + nro.Text.Length ||
                 nro.DataOffset != nro.RoOffset   + nro.Ro.Length   ||
-                nroFileSize           != nro.DataOffset + nro.Data.Length)
+                nroFileSize    != nro.DataOffset + nro.Data.Length)
             {
                 return ResultCode.InvalidNro;
             }
@@ -337,21 +337,21 @@ namespace Ryujinx.HLE.HOS.Services.Ro
 
             KernelResult result;
 
-            result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, MemoryPermission.ReadAndExecute);
+            result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, KMemoryPermission.ReadAndExecute);
 
             if (result != KernelResult.Success)
             {
                 return result;
             }
 
-            result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, MemoryPermission.Read);
+            result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, KMemoryPermission.Read);
 
             if (result != KernelResult.Success)
             {
                 return result;
             }
 
-            return process.MemoryManager.SetProcessMemoryPermission(dataStart, bssEnd - dataStart, MemoryPermission.ReadAndWrite);
+            return process.MemoryManager.SetProcessMemoryPermission(dataStart, bssEnd - dataStart, KMemoryPermission.ReadAndWrite);
         }
 
         private ResultCode RemoveNrrInfo(long nrrAddress)
@@ -420,9 +420,9 @@ namespace Ryujinx.HLE.HOS.Services.Ro
             return (ResultCode)result;
         }
 
-        private ResultCode IsInitialized(KProcess process)
+        private ResultCode IsInitialized(long pid)
         {
-            if (_owner != null && _owner.Pid == process.Pid)
+            if (_owner != null && _owner.Pid == pid)
             {
                 return ResultCode.Success;
             }
@@ -434,7 +434,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
         // LoadNro(u64, u64, u64, u64, u64, pid) -> u64
         public ResultCode LoadNro(ServiceCtx context)
         {
-            ResultCode result = IsInitialized(context.Process);
+            ResultCode result = IsInitialized(_owner.Pid);
 
             // Zero
             context.RequestData.ReadUInt64();
@@ -454,11 +454,11 @@ namespace Ryujinx.HLE.HOS.Services.Ro
 
                 if (result == ResultCode.Success)
                 {
-                    result = MapNro(context.Process, info, out nroMappedAddress);
+                    result = MapNro(_owner, info, out nroMappedAddress);
 
                     if (result == ResultCode.Success)
                     {
-                        result = (ResultCode)SetNroMemoryPermissions(context.Process, info.Executable, nroMappedAddress);
+                        result = (ResultCode)SetNroMemoryPermissions(_owner, info.Executable, nroMappedAddress);
 
                         if (result == ResultCode.Success)
                         {
@@ -479,7 +479,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
         // UnloadNro(u64, u64, pid)
         public ResultCode UnloadNro(ServiceCtx context)
         {
-            ResultCode result = IsInitialized(context.Process);
+            ResultCode result = IsInitialized(_owner.Pid);
 
             // Zero
             context.RequestData.ReadUInt64();
@@ -503,7 +503,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
         // LoadNrr(u64, u64, u64, pid)
         public ResultCode LoadNrr(ServiceCtx context)
         {
-            ResultCode result = IsInitialized(context.Process);
+            ResultCode result = IsInitialized(_owner.Pid);
 
             // pid placeholder, zero
             context.RequestData.ReadUInt64();
@@ -536,7 +536,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
         // UnloadNrr(u64, u64, pid)
         public ResultCode UnloadNrr(ServiceCtx context)
         {
-            ResultCode result = IsInitialized(context.Process);
+            ResultCode result = IsInitialized(_owner.Pid);
 
             // pid placeholder, zero
             context.RequestData.ReadUInt64();
@@ -565,7 +565,8 @@ namespace Ryujinx.HLE.HOS.Services.Ro
                 return ResultCode.InvalidSession;
             }
 
-            _owner = context.Process;
+            _owner = context.Process.HandleTable.GetKProcess(context.Request.HandleDesc.ToCopy[0]);
+            context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
 
             return ResultCode.Success;
         }

+ 8 - 3
Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs

@@ -9,6 +9,8 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
     [Service("pl:s")] // 9.0.0+
     class ISharedFontManager : IpcService
     {
+        private int _fontSharedMemHandle;
+
         public ISharedFontManager(ServiceCtx context) { }
 
         [Command(0)]
@@ -63,12 +65,15 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
         {
             context.Device.System.Font.EnsureInitialized(context.Device.System.ContentManager);
 
-            if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out int handle) != KernelResult.Success)
+            if (_fontSharedMemHandle == 0)
             {
-                throw new InvalidOperationException("Out of handles!");
+                if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out _fontSharedMemHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
             }
 
-            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_fontSharedMemHandle);
 
             return ResultCode.Success;
         }

+ 184 - 49
Ryujinx.HLE/HOS/Services/ServerBase.cs

@@ -1,62 +1,193 @@
-using Ryujinx.Common;
 using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using System;
+using System.Buffers.Binary;
+using System.Collections.Generic;
 using System.IO;
+using System.Threading;
 
 namespace Ryujinx.HLE.HOS.Services
 {
     class ServerBase
     {
-        private struct IpcRequest
+        // Must be the maximum value used by services (highest one know is the one used by nvservices = 0x8000).
+        // Having a size that is too low will cause failures as data copy will fail if the receiving buffer is
+        // not large enough.
+        private const int PointerBufferSize = 0x8000;
+
+        private readonly static int[] DefaultCapabilities = new int[]
         {
-            public Switch Device { get; }
-            public KProcess Process => Thread?.Owner;
-            public KThread Thread { get; }
-            public KClientSession Session { get; }
-            public ulong MessagePtr { get; }
-            public ulong MessageSize { get; }
-
-            public IpcRequest(Switch device, KThread thread, KClientSession session, ulong messagePtr, ulong messageSize)
-            {
-                Device = device;
-                Thread = thread;
-                Session = session;
-                MessagePtr = messagePtr;
-                MessageSize = messageSize;
-            }
+            0x030363F7,
+            0x1FFFFFCF,
+            0x207FFFEF,
+            0x47E0060F,
+            0x0048BFFF,
+            0x01007FFF
+        };
+
+        private readonly KernelContext _context;
+        private readonly KProcess _selfProcess;
+
+        private readonly List<int> _sessionHandles = new List<int>();
+        private readonly List<int> _portHandles = new List<int>();
+        private readonly Dictionary<int, IpcService> _sessions = new Dictionary<int, IpcService>();
+        private readonly Dictionary<int, IpcService> _ports = new Dictionary<int, IpcService>();
+
+        public ManualResetEvent InitDone { get; }
+        public IpcService SmObject { get; set; }
+        public string Name { get; }
+
+        public ServerBase(KernelContext context, string name)
+        {
+            InitDone = new ManualResetEvent(false);
+            Name = name;
+            _context = context;
 
-            public void SignalDone(KernelResult result)
-            {
-                Thread.ObjSyncResult = result;
-                Thread.Reschedule(ThreadSchedState.Running);
-            }
+            const ProcessCreationFlags flags =
+                ProcessCreationFlags.EnableAslr |
+                ProcessCreationFlags.AddressSpace64Bit |
+                ProcessCreationFlags.Is64Bit |
+                ProcessCreationFlags.PoolPartitionSystem;
+
+            ProcessCreationInfo creationInfo = new ProcessCreationInfo("Service", 1, 0, 0x8000000, 1, flags, 0, 0);
+
+            context.Syscall.CreateProcess(creationInfo, DefaultCapabilities, out int handle, null, ServerLoop);
+
+            _selfProcess = context.Scheduler.GetCurrentProcess().HandleTable.GetKProcess(handle);
+
+            context.Syscall.StartProcess(handle, 44, 3, 0x1000);
         }
 
-        private readonly AsyncWorkQueue<IpcRequest> _ipcProcessor;
+        private void AddPort(int serverPortHandle, IpcService obj)
+        {
+            _portHandles.Add(serverPortHandle);
+            _ports.Add(serverPortHandle, obj);
+        }
 
-        public ServerBase(string name)
+        public void AddSessionObj(KServerSession serverSession, IpcService obj)
         {
-            _ipcProcessor = new AsyncWorkQueue<IpcRequest>(Process, name);
+            _selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle);
+            AddSessionObj(serverSessionHandle, obj);
         }
 
-        public void PushMessage(Switch device, KThread thread, KClientSession session, ulong messagePtr, ulong messageSize)
+        public void AddSessionObj(int serverSessionHandle, IpcService obj)
         {
-            _ipcProcessor.Add(new IpcRequest(device, thread, session, messagePtr, messageSize));
+            _sessionHandles.Add(serverSessionHandle);
+            _sessions.Add(serverSessionHandle, obj);
         }
 
-        private void Process(IpcRequest message)
+        private void ServerLoop()
         {
-            byte[] reqData = new byte[message.MessageSize];
+            if (SmObject != null)
+            {
+                _context.Syscall.ManageNamedPort("sm:", 50, out int serverPortHandle);
+
+                AddPort(serverPortHandle, SmObject);
+
+                InitDone.Set();
+            }
+            else
+            {
+                InitDone.Dispose();
+            }
+
+            KThread thread = _context.Scheduler.GetCurrentThread();
+            ulong messagePtr = thread.TlsAddress;
+            _context.Syscall.SetHeapSize(0x200000, out ulong heapAddr);
+
+            _selfProcess.CpuMemory.Write(messagePtr + 0x0, 0);
+            _selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10);
+            _selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48));
+
+            int replyTargetHandle = 0;
+
+            while (true)
+            {
+                int[] handles = _portHandles.ToArray();
+
+                for (int i = 0; i < handles.Length; i++)
+                {
+                    if (_context.Syscall.AcceptSession(handles[i], out int serverSessionHandle) == KernelResult.Success)
+                    {
+                        AddSessionObj(serverSessionHandle, _ports[handles[i]]);
+                    }
+                }
+
+                handles = _sessionHandles.ToArray();
+
+                var rc = _context.Syscall.ReplyAndReceive(handles, replyTargetHandle, 1000000L, out int signaledIndex);
+
+                thread.HandlePostSyscall();
+
+                if (!thread.Context.Running)
+                {
+                    break;
+                }
 
-            message.Process.CpuMemory.Read(message.MessagePtr, reqData);
+                replyTargetHandle = 0;
 
-            IpcMessage request = new IpcMessage(reqData, (long)message.MessagePtr);
+                if (rc == KernelResult.Success && signaledIndex != -1)
+                {
+                    int signaledHandle = handles[signaledIndex];
+
+                    if (Process(signaledHandle, heapAddr))
+                    {
+                        replyTargetHandle = signaledHandle;
+                    }
+                }
+                else
+                {
+                    _selfProcess.CpuMemory.Write(messagePtr + 0x0, 0);
+                    _selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10);
+                    _selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48));
+                }
+            }
+        }
+
+        private bool Process(int serverSessionHandle, ulong recvListAddr)
+        {
+            KProcess process = _context.Scheduler.GetCurrentProcess();
+            KThread thread = _context.Scheduler.GetCurrentThread();
+            ulong messagePtr = thread.TlsAddress;
+            ulong messageSize = 0x100;
+
+            byte[] reqData = new byte[messageSize];
+
+            process.CpuMemory.Read(messagePtr, reqData);
+
+            IpcMessage request = new IpcMessage(reqData, (long)messagePtr);
             IpcMessage response = new IpcMessage();
 
+            ulong tempAddr = recvListAddr;
+            int sizesOffset = request.RawData.Length - ((request.RecvListBuff.Count * 2 + 3) & ~3);
+
+            bool noReceive = true;
+
+            for (int i = 0; i < request.ReceiveBuff.Count; i++)
+            {
+                noReceive &= (request.ReceiveBuff[i].Position == 0);
+            }
+
+            if (noReceive)
+            {
+                for (int i = 0; i < request.RecvListBuff.Count; i++)
+                {
+                    int size = BinaryPrimitives.ReadInt16LittleEndian(request.RawData.AsSpan().Slice(sizesOffset + i * 2, 2));
+
+                    response.PtrBuff.Add(new IpcPtrBuffDesc((long)tempAddr, i, size));
+
+                    request.RecvListBuff[i] = new IpcRecvListBuffDesc((long)tempAddr, size);
+
+                    tempAddr += (ulong)size;
+                }
+            }
+
+            bool shouldReply = true;
+
             using (MemoryStream raw = new MemoryStream(request.RawData))
             {
                 BinaryReader reqReader = new BinaryReader(raw);
@@ -71,17 +202,16 @@ namespace Ryujinx.HLE.HOS.Services
                         BinaryWriter resWriter = new BinaryWriter(resMs);
 
                         ServiceCtx context = new ServiceCtx(
-                            message.Device,
-                            message.Process,
-                            message.Process.CpuMemory,
-                            message.Thread,
-                            message.Session,
+                            _context.Device,
+                            process,
+                            process.CpuMemory,
+                            thread,
                             request,
                             response,
                             reqReader,
                             resWriter);
 
-                        message.Session.Service.CallMethod(context);
+                        _sessions[serverSessionHandle].CallMethod(context);
 
                         response.RawData = resMs.ToArray();
                     }
@@ -95,11 +225,11 @@ namespace Ryujinx.HLE.HOS.Services
                     switch (cmdId)
                     {
                         case 0:
-                            request = FillResponse(response, 0, message.Session.Service.ConvertToDomain());
+                            request = FillResponse(response, 0, _sessions[serverSessionHandle].ConvertToDomain());
                             break;
 
                         case 3:
-                            request = FillResponse(response, 0, 0x1000);
+                            request = FillResponse(response, 0, PointerBufferSize);
                             break;
 
                         // TODO: Whats the difference between IpcDuplicateSession/Ex?
@@ -107,12 +237,11 @@ namespace Ryujinx.HLE.HOS.Services
                         case 4:
                             int unknown = reqReader.ReadInt32();
 
-                            if (message.Process.HandleTable.GenerateHandle(message.Session, out int handle) != KernelResult.Success)
-                            {
-                                throw new InvalidOperationException("Out of handles!");
-                            }
+                            _context.Syscall.CreateSession(false, 0, out int dupServerSessionHandle, out int dupClientSessionHandle);
 
-                            response.HandleDesc = IpcHandleDesc.MakeMove(handle);
+                            AddSessionObj(dupServerSessionHandle, _sessions[serverSessionHandle]);
+
+                            response.HandleDesc = IpcHandleDesc.MakeMove(dupClientSessionHandle);
 
                             request = FillResponse(response, 0);
 
@@ -123,18 +252,24 @@ namespace Ryujinx.HLE.HOS.Services
                 }
                 else if (request.Type == IpcMessageType.CloseSession)
                 {
-                    message.SignalDone(KernelResult.PortRemoteClosed);
-                    return;
+                    _context.Syscall.CloseHandle(serverSessionHandle);
+                    _sessionHandles.Remove(serverSessionHandle);
+                    IpcService service = _sessions[serverSessionHandle];
+                    if (service is IDisposable disposableObj)
+                    {
+                        disposableObj.Dispose();
+                    }
+                    _sessions.Remove(serverSessionHandle);
+                    shouldReply = false;
                 }
                 else
                 {
                     throw new NotImplementedException(request.Type.ToString());
                 }
 
-                message.Process.CpuMemory.Write(message.MessagePtr, response.GetBytes((long)message.MessagePtr));
+                process.CpuMemory.Write(messagePtr, response.GetBytes((long)messagePtr, recvListAddr | ((ulong)PointerBufferSize << 48)));
+                return shouldReply;
             }
-
-            message.SignalDone(KernelResult.Success);
         }
 
         private static IpcMessage FillResponse(IpcMessage response, long result, params int[] values)

+ 8 - 20
Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs

@@ -1,5 +1,6 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Ipc;
 using System;
@@ -11,18 +12,17 @@ using System.Reflection;
 
 namespace Ryujinx.HLE.HOS.Services.Sm
 {
-    [Service("sm:")]
     class IUserInterface : IpcService
     {
         private Dictionary<string, Type> _services;
 
-        private ConcurrentDictionary<string, KPort> _registeredServices;
+        private readonly ConcurrentDictionary<string, KPort> _registeredServices;
 
         private readonly ServerBase _commonServer;
 
         private bool _isInitialized;
 
-        public IUserInterface(ServiceCtx context = null) : base(new ServerBase("SmServer"))
+        public IUserInterface(KernelContext context)
         {
             _registeredServices = new ConcurrentDictionary<string, KPort>();
 
@@ -31,18 +31,9 @@ namespace Ryujinx.HLE.HOS.Services.Sm
                 .Select(service => (((ServiceAttribute)service).Name, type)))
                 .ToDictionary(service => service.Name, service => service.type);
 
-            _commonServer = new ServerBase("CommonServer");
-        }
-
-        public static void InitializePort(Horizon system)
-        {
-            KPort port = new KPort(system.KernelContext, 256, false, 0);
-
-            port.ClientPort.SetName("sm:");
-
-            IUserInterface smService = new IUserInterface();
+            TrySetServer(new ServerBase(context, "SmServer") { SmObject = this });
 
-            port.ClientPort.Service = smService;
+            _commonServer = new ServerBase(context, "CommonServer");
         }
 
         [Command(0)]
@@ -92,16 +83,13 @@ namespace Ryujinx.HLE.HOS.Services.Sm
                         : (IpcService)Activator.CreateInstance(type, context);
 
                     service.TrySetServer(_commonServer);
-
-                    session.ClientSession.Service = service;
+                    service.Server.AddSessionObj(session.ServerSession, service);
                 }
                 else
                 {
                     if (ServiceConfiguration.IgnoreMissingServices)
                     {
                         Logger.Warning?.Print(LogClass.Service, $"Missing service {name} ignored");
-
-                        session.ClientSession.Service = new DummyService(name);
                     }
                     else
                     {
@@ -142,7 +130,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
 
             int maxSessions = context.RequestData.ReadInt32();
 
-            if (name == string.Empty)
+            if (string.IsNullOrEmpty(name))
             {
                 return ResultCode.InvalidName;
             }
@@ -185,7 +173,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
 
             int maxSessions = context.RequestData.ReadInt32();
 
-            if (name == string.Empty)
+            if (string.IsNullOrEmpty(name))
             {
                 return ResultCode.InvalidName;
             }

+ 4 - 1
Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs

@@ -102,7 +102,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
 
         private List<BsdSocket> _sockets = new List<BsdSocket>();
 
-        public IClient(ServiceCtx context, bool isPrivileged)  : base(new ServerBase("BsdServer"))
+        public IClient(ServiceCtx context, bool isPrivileged) : base(new ServerBase(context.Device.System.KernelContext, "BsdServer"))
         {
             _isPrivileged = isPrivileged;
         }
@@ -247,6 +247,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
 
             Logger.Stub?.PrintStub(LogClass.ServiceBsd);
 
+            // Close transfer memory immediately as we don't use it.
+            context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
+
             return ResultCode.Success;
         }
 

+ 10 - 10
Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs

@@ -118,14 +118,14 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
         // ImportSettings(u32, buffer<unknown, 5>) -> buffer<unknown, 6>
         public ResultCode ImportSettings(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(15)]
         // Unknown(bytes<1>)
         public ResultCode Unknown(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(20)]
@@ -164,49 +164,49 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
         // GetNasServiceSetting(buffer<unknown<0x10>, 0x15>) -> buffer<unknown<0x108>, 0x16>
         public ResultCode GetNasServiceSetting(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(31)]
         // GetNasServiceSettingEx(buffer<unknown<0x10>, 0x15>) -> (u32, buffer<unknown<0x108>, 0x16>)
         public ResultCode GetNasServiceSettingEx(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(40)]
         // GetNasRequestFqdn() -> buffer<unknown<0x100>, 0x16>
         public ResultCode GetNasRequestFqdn(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(41)]
         // GetNasRequestFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
         public ResultCode GetNasRequestFqdnEx(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(42)]
         // GetNasApiFqdn() -> buffer<unknown<0x100>, 0x16>
         public ResultCode GetNasApiFqdn(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(43)]
         // GetNasApiFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
         public ResultCode GetNasApiFqdnEx(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(50)]
         // GetCurrentSetting() -> buffer<unknown<0x12bf0>, 0x16>
         public ResultCode GetCurrentSetting(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(60)]
@@ -262,7 +262,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
         // IsChangeEnvironmentIdentifierDisabled() -> bytes<1>
         public ResultCode IsChangeEnvironmentIdentifierDisabled(ServiceCtx context)
         {
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
     }
 }

+ 6 - 6
Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueue.cs

@@ -1,15 +1,15 @@
-using Ryujinx.HLE.HOS.Kernel.Process;
-
-namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
+namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
 {
-    class BufferQueue
+    static class BufferQueue
     {
-        public static void CreateBufferQueue(Switch device, KProcess process, out BufferQueueProducer producer, out BufferQueueConsumer consumer)
+        public static BufferQueueCore CreateBufferQueue(Switch device, long pid, out BufferQueueProducer producer, out BufferQueueConsumer consumer)
         {
-            BufferQueueCore core = new BufferQueueCore(device, process);
+            BufferQueueCore core = new BufferQueueCore(device, pid);
 
             producer = new BufferQueueProducer(core);
             consumer = new BufferQueueConsumer(core);
+
+            return core;
         }
     }
 }

+ 39 - 6
Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs

@@ -1,5 +1,5 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
 using System;
@@ -40,11 +40,13 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
         private KEvent _waitBufferFreeEvent;
         private KEvent _frameAvailableEvent;
 
-        public KProcess Owner { get; }
+        public long Owner { get; }
+
+        public bool Active { get; private set; }
 
         public const int BufferHistoryArraySize = 8;
 
-        public BufferQueueCore(Switch device, KProcess process)
+        public BufferQueueCore(Switch device, long pid)
         {
             Slots                    = new BufferSlotArray();
             IsAbandoned              = false;
@@ -70,7 +72,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
             _waitBufferFreeEvent  = new KEvent(device.System.KernelContext);
             _frameAvailableEvent = new KEvent(device.System.KernelContext);
 
-            Owner = process;
+            Owner = pid;
+
+            Active = true;
 
             BufferHistory        = new BufferInfo[BufferHistoryArraySize];
             EnableExternalEvent  = true;
@@ -162,6 +166,16 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
             }
         }
 
+        public void PrepareForExit()
+        {
+            lock (Lock)
+            {
+                Active = false;
+
+                Monitor.PulseAll(Lock);
+            }
+        }
+
         // TODO: Find an accurate way to handle a regular condvar here as this will wake up unwanted threads in some edge cases.
         public void SignalDequeueEvent()
         {
@@ -170,7 +184,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
 
         public void WaitDequeueEvent()
         {
-            Monitor.Wait(Lock);
+            Monitor.Exit(Lock);
+
+            KernelStatic.YieldUntilCompletion(WaitForLock);
+
+            Monitor.Enter(Lock);
         }
 
         public void SignalIsAllocatingEvent()
@@ -180,7 +198,22 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
 
         public void WaitIsAllocatingEvent()
         {
-            Monitor.Wait(Lock);
+            Monitor.Exit(Lock);
+
+            KernelStatic.YieldUntilCompletion(WaitForLock);
+
+            Monitor.Enter(Lock);
+        }
+
+        private void WaitForLock()
+        {
+            lock (Lock)
+            {
+                if (Active)
+                {
+                    Monitor.Wait(Lock);
+                }
+            }
         }
 
         public void FreeBufferLocked(int slot)

+ 5 - 0
Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs

@@ -816,6 +816,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
                     }
 
                     Core.WaitDequeueEvent();
+
+                    if (!Core.Active)
+                    {
+                        break;
+                    }
                 }
             }
 

+ 1 - 1
Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs

@@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
 {
     abstract class IHOSBinderDriver : IpcService
     {
-        public IHOSBinderDriver() {}
+        public IHOSBinderDriver() { }
 
         [Command(0)]
         // TransactParcel(s32, u32, u32, buffer<unknown, 5, 0>) -> buffer<unknown, 6, 0>

+ 15 - 11
Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs

@@ -1,10 +1,7 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.Graphics.GAL;
 using Ryujinx.Graphics.Gpu;
-using Ryujinx.HLE.HOS.Kernel.Process;
-using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
-using Ryujinx.HLE.HOS.Services.Nv.Types;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -40,7 +37,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
             public int                    ProducerBinderId;
             public IGraphicBufferProducer Producer;
             public BufferItemConsumer     Consumer;
-            public KProcess               Owner;
+            public BufferQueueCore        Core;
+            public long                   Owner;
         }
 
         private class TextureCallbackInformation
@@ -84,7 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
             }
         }
 
-        public IGraphicBufferProducer OpenLayer(KProcess process, long layerId)
+        public IGraphicBufferProducer OpenLayer(long pid, long layerId)
         {
             bool needCreate;
 
@@ -95,13 +93,13 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
 
             if (needCreate)
             {
-                CreateLayerFromId(process, layerId);
+                CreateLayerFromId(pid, layerId);
             }
 
             return GetProducerByLayerId(layerId);
         }
 
-        public IGraphicBufferProducer CreateLayer(KProcess process, out long layerId)
+        public IGraphicBufferProducer CreateLayer(long pid, out long layerId)
         {
             layerId = 1;
 
@@ -116,25 +114,26 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
                 }
             }
 
-            CreateLayerFromId(process, layerId);
+            CreateLayerFromId(pid, layerId);
 
             return GetProducerByLayerId(layerId);
         }
 
-        private void CreateLayerFromId(KProcess process, long layerId)
+        private void CreateLayerFromId(long pid, long layerId)
         {
             lock (Lock)
             {
                 Logger.Info?.Print(LogClass.SurfaceFlinger, $"Creating layer {layerId}");
 
-                BufferQueue.CreateBufferQueue(_device, process, out BufferQueueProducer producer, out BufferQueueConsumer consumer);
+                BufferQueueCore core = BufferQueue.CreateBufferQueue(_device, pid, out BufferQueueProducer producer, out BufferQueueConsumer consumer);
 
                 _layers.Add(layerId, new Layer
                 {
                     ProducerBinderId = HOSBinderDriverServer.RegisterBinderObject(producer),
                     Producer         = producer,
                     Consumer         = new BufferItemConsumer(_device, consumer, 0, -1, false, this),
-                    Owner            = process
+                    Core             = core,
+                    Owner            = pid
                 });
 
                 LastId = layerId;
@@ -345,6 +344,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
         public void Dispose()
         {
             _isRunning = false;
+
+            foreach (Layer layer in _layers.Values)
+            {
+                layer.Core.PrepareForExit();
+            }
         }
 
         public void OnFrameAvailable(ref BufferItem item)

+ 6 - 6
Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/GraphicBuffer.cs

@@ -42,23 +42,23 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
             Buffer = parcel.ReadUnmanagedType<NvGraphicBuffer>();
         }
 
-        public void IncrementNvMapHandleRefCount(KProcess process)
+        public void IncrementNvMapHandleRefCount(long pid)
         {
-            NvMapDeviceFile.IncrementMapRefCount(process, Buffer.NvMapId);
+            NvMapDeviceFile.IncrementMapRefCount(pid, Buffer.NvMapId);
 
             for (int i = 0; i < Buffer.Surfaces.Length; i++)
             {
-                NvMapDeviceFile.IncrementMapRefCount(process, Buffer.Surfaces[i].NvMapHandle);
+                NvMapDeviceFile.IncrementMapRefCount(pid, Buffer.Surfaces[i].NvMapHandle);
             }
         }
 
-        public void DecrementNvMapHandleRefCount(KProcess process)
+        public void DecrementNvMapHandleRefCount(long pid)
         {
-            NvMapDeviceFile.DecrementMapRefCount(process, Buffer.NvMapId);
+            NvMapDeviceFile.DecrementMapRefCount(pid, Buffer.NvMapId);
 
             for (int i = 0; i < Buffer.Surfaces.Length; i++)
             {
-                NvMapDeviceFile.DecrementMapRefCount(process, Buffer.Surfaces[i].NvMapHandle);
+                NvMapDeviceFile.DecrementMapRefCount(pid, Buffer.Surfaces[i].NvMapHandle);
             }
         }
 

+ 3 - 1
Ryujinx.HLE/HOS/Services/Time/IStaticServiceForGlue.cs

@@ -15,10 +15,12 @@ namespace Ryujinx.HLE.HOS.Services.Time
         private IStaticServiceForPsc _inner;
         private TimePermissions      _permissions;
 
-        public IStaticServiceForGlue(ServiceCtx context, TimePermissions permissions) : base(new ServerBase("TimeServer"))
+        public IStaticServiceForGlue(ServiceCtx context, TimePermissions permissions) : base(new ServerBase(context.Device.System.KernelContext, "TimeServer"))
         {
             _permissions = permissions;
             _inner       = new IStaticServiceForPsc(context, permissions);
+            _inner.TrySetServer(Server);
+            _inner.SetParent(this);
         }
 
         [Command(0)]

+ 6 - 6
Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs

@@ -149,7 +149,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         public ResultCode Unknown50(ServiceCtx context)
         {
             // TODO: figure out the usage of this event
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(51)]
@@ -157,7 +157,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         public ResultCode Unknown51(ServiceCtx context)
         {
             // TODO: figure out the usage of this event
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(52)]
@@ -165,7 +165,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         public ResultCode Unknown52(ServiceCtx context)
         {
             // TODO: figure out the usage of this event
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(60)]
@@ -201,7 +201,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         public ResultCode GetAlarmRegistrationEvent(ServiceCtx context)
         {
             // TODO
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(201)]
@@ -209,7 +209,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         public ResultCode UpdateSteadyAlarms(ServiceCtx context)
         {
             // TODO
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
 
         [Command(202)]
@@ -217,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         public ResultCode TryGetNextSteadyClockAlarmSnapshot(ServiceCtx context)
         {
             // TODO
-            throw new ServiceNotImplementedException(context);
+            throw new ServiceNotImplementedException(this, context);
         }
     }
 }

+ 1 - 2
Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs

@@ -5,8 +5,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
     [Service("vi:u")]
     class IApplicationRootService : IpcService
     {
-        // vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
-        public IApplicationRootService(ServiceCtx context) : base(new ServerBase("ViServerU")) { }
+        public IApplicationRootService(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "ViServerU")) { }
 
         [Command(0)]
         // GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>

+ 1 - 1
Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs

@@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
     class IManagerRootService : IpcService
     {
         // vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
-        public IManagerRootService(ServiceCtx context) : base(new ServerBase("ViServerM")) { }
+        public IManagerRootService(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "ViServerM")) { }
 
         [Command(2)]
         // GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>

+ 1 - 1
Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs

@@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
     class ISystemRootService : IpcService
     {
         // vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
-        public ISystemRootService(ServiceCtx context) : base(new ServerBase("ViServerS")) { }
+        public ISystemRootService(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "ViServerS")) { }
 
         [Command(1)]
         // GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>

Некоторые файлы не были показаны из-за большого количества измененных файлов