aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ARMeilleure/State/ExecutionContext.cs2
-rw-r--r--Ryujinx.Audio.Renderer/Dsp/Command/AuxiliaryBufferCommand.cs27
-rw-r--r--Ryujinx.Audio.Renderer/Dsp/Command/CommandList.cs6
-rw-r--r--Ryujinx.Audio.Renderer/Dsp/DataSourceHelper.cs4
-rw-r--r--Ryujinx.Audio.Renderer/Dsp/State/AuxiliaryBufferHeader.cs10
-rw-r--r--Ryujinx.Audio.Renderer/Ryujinx.Audio.Renderer.csproj1
-rw-r--r--Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs20
-rw-r--r--Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs12
-rw-r--r--Ryujinx.Cpu/MemoryHelper.cs11
-rw-r--r--Ryujinx.Cpu/MemoryManager.cs7
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs3
-rw-r--r--Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs20
-rw-r--r--Ryujinx.HLE/HOS/ArmProcessContext.cs24
-rw-r--r--Ryujinx.HLE/HOS/ArmProcessContextFactory.cs14
-rw-r--r--Ryujinx.HLE/HOS/Horizon.cs20
-rw-r--r--Ryujinx.HLE/HOS/Ipc/IpcMessage.cs23
-rw-r--r--Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs27
-rw-r--r--Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs6
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs11
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs4
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs9
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs9
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs34
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs15
-rw-r--r--Ryujinx.HLE/HOS/Kernel/KernelContext.cs2
-rw-r--r--Ryujinx.HLE/HOS/Kernel/KernelStatic.cs38
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs16
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs8
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs327
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs12
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs7
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs2
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs10
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs13
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs10
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs234
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs27
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs25
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs13
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs38
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs46
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs273
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs10
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs10
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs2
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs90
-rw-r--r--Ryujinx.HLE/HOS/ProgramLoader.cs30
-rw-r--r--Ryujinx.HLE/HOS/ServiceCtx.cs52
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs37
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs28
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs42
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IWindowController.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs43
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletOE/IApplicationProxyService.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs22
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs3
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs3
-rw-r--r--Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs22
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs24
-rw-r--r--Ryujinx.HLE/HOS/Services/IpcService.cs62
-rw-r--r--Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs32
-rw-r--r--Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs21
-rw-r--r--Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs17
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs67
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvDeviceFile.cs7
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs3
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs5
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlDeviceFile.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs5
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs24
-rw-r--r--Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs37
-rw-r--r--Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/ServerBase.cs233
-rw-r--r--Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs28
-rw-r--r--Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs5
-rw-r--r--Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs20
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueue.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs45
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs5
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs26
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/GraphicBuffer.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/IStaticServiceForGlue.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs3
-rw-r--r--Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs21
-rw-r--r--Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs6
-rw-r--r--Ryujinx.HLE/Loaders/Npdm/Npdm.cs6
-rw-r--r--Ryujinx.HLE/Switch.cs1
-rw-r--r--Ryujinx.HLE/Utilities/StructReader.cs5
-rw-r--r--Ryujinx.HLE/Utilities/StructWriter.cs5
-rw-r--r--Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs58
-rw-r--r--Ryujinx.Memory/AddressSpaceManager.cs549
-rw-r--r--Ryujinx.Memory/IVirtualMemoryManager.cs28
-rw-r--r--Ryujinx.Memory/MemoryNotContiguousException.cs (renamed from Ryujinx.Cpu/MemoryNotContiguousException.cs)4
-rw-r--r--Ryujinx.Memory/Tracking/IVirtualMemoryManager.cs10
-rw-r--r--Ryujinx.Memory/WritableRegion.cs (renamed from Ryujinx.Cpu/WritableRegion.cs)6
-rw-r--r--Ryujinx/Ui/GLRenderer.cs60
115 files changed, 2347 insertions, 1079 deletions
diff --git a/ARMeilleure/State/ExecutionContext.cs b/ARMeilleure/State/ExecutionContext.cs
index 9f89bff4..a964f6ba 100644
--- a/ARMeilleure/State/ExecutionContext.cs
+++ b/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;
diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/AuxiliaryBufferCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/AuxiliaryBufferCommand.cs
index f63722c1..46aff27e 100644
--- a/Ryujinx.Audio.Renderer/Dsp/Command/AuxiliaryBufferCommand.cs
+++ b/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++;
+ }
+ }
}
}
diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/CommandList.cs b/Ryujinx.Audio.Renderer/Dsp/Command/CommandList.cs
index d65f6ced..4b80c93b 100644
--- a/Ryujinx.Audio.Renderer/Dsp/Command/CommandList.cs
+++ b/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;
diff --git a/Ryujinx.Audio.Renderer/Dsp/DataSourceHelper.cs b/Ryujinx.Audio.Renderer/Dsp/DataSourceHelper.cs
index ccc97b92..6e270df4 100644
--- a/Ryujinx.Audio.Renderer/Dsp/DataSourceHelper.cs
+++ b/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;
diff --git a/Ryujinx.Audio.Renderer/Dsp/State/AuxiliaryBufferHeader.cs b/Ryujinx.Audio.Renderer/Dsp/State/AuxiliaryBufferHeader.cs
index eebbac53..3923a490 100644
--- a/Ryujinx.Audio.Renderer/Dsp/State/AuxiliaryBufferHeader.cs
+++ b/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);
}
diff --git a/Ryujinx.Audio.Renderer/Ryujinx.Audio.Renderer.csproj b/Ryujinx.Audio.Renderer/Ryujinx.Audio.Renderer.csproj
index eac49fb3..ccdeae3e 100644
--- a/Ryujinx.Audio.Renderer/Ryujinx.Audio.Renderer.csproj
+++ b/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>
diff --git a/Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs b/Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs
index 30f326a6..a5925284 100644
--- a/Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs
+++ b/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))
{
diff --git a/Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs b/Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs
index 023dd477..3df0ab31 100644
--- a/Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs
+++ b/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)
diff --git a/Ryujinx.Cpu/MemoryHelper.cs b/Ryujinx.Cpu/MemoryHelper.cs
index 5ba5ef38..8ef4bc66 100644
--- a/Ryujinx.Cpu/MemoryHelper.cs
+++ b/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())
{
diff --git a/Ryujinx.Cpu/MemoryManager.cs b/Ryujinx.Cpu/MemoryManager.cs
index 3fa08fe7..36ae9b32 100644
--- a/Ryujinx.Cpu/MemoryManager.cs
+++ b/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;
diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
index 517dacef..91575e20 100644
--- a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
+++ b/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;
diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
index 3ebf2fd7..de41fb9a 100644
--- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
+++ b/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;
diff --git a/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs b/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs
index 1be7609b..58c15fdd 100644
--- a/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs
+++ b/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();
}
}
diff --git a/Ryujinx.HLE/HOS/ArmProcessContext.cs b/Ryujinx.HLE/HOS/ArmProcessContext.cs
new file mode 100644
index 00000000..fb7703b7
--- /dev/null
+++ b/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();
+ }
+}
diff --git a/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs b/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs
new file mode 100644
index 00000000..050d3690
--- /dev/null
+++ b/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));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index b7e76a72..d4b49f45 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/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);
diff --git a/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs b/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs
index 012c3167..135a0a1f 100644
--- a/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs
+++ b/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();
}
diff --git a/Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs b/Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs
index cdc43f17..c17f248f 100644
--- a/Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs
+++ b/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;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs b/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs
index 3fd92f02..78732550 100644
--- a/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs
+++ b/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();
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs b/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
new file mode 100644
index 00000000..098d83d1
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Ryujinx.HLE.HOS.Kernel.Common
+{
+ struct OnScopeExit : IDisposable
+ {
+ private readonly Action _action;
+ public OnScopeExit(Action action) => _action = action;
+ public void Dispose() => _action();
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
index 0986adf7..fbd32845 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
@@ -99,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
copySize,
stateMask,
stateMask,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.ReadAndWrite,
attributeMask,
MemoryAttribute.None,
desc.ServerAddress);
@@ -125,7 +125,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
clientEndAddr - clientEndAddrTruncated,
stateMask,
stateMask,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.ReadAndWrite,
attributeMask,
MemoryAttribute.None,
serverEndAddrTruncated);
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
index 8d6669cf..c3b7d1dd 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
@@ -14,10 +14,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
public bool IsLight => _parent.IsLight;
- // TODO: Remove that, we need it for now to allow HLE
- // SM implementation to work with the new IPC system.
- public IpcService Service { get; set; }
-
public KClientPort(KernelContext context, KPort parent, int maxSessions) : base(context)
{
_maxSessions = maxSessions;
@@ -45,11 +41,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
KSession session = new KSession(KernelContext, this);
- if (Service != null)
- {
- session.ClientSession.Service = Service;
- }
-
KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession);
if (result != KernelResult.Success)
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
index 2c2d9644..d535bf82 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
@@ -16,10 +16,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
public KClientPort ParentPort { get; }
- // TODO: Remove that, we need it for now to allow HLE
- // services implementation to work with the new IPC system.
- public IpcService Service { get; set; }
-
public KClientSession(KernelContext context, KSession parent, KClientPort parentPort) : base(context)
{
_parent = parent;
@@ -84,11 +80,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
_parent.DisconnectClient();
_parent.DecrementReferenceCount();
-
- if (Service is IDisposable disposableObj)
- {
- disposableObj.Dispose();
- }
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
index 48669832..e9c6127f 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
@@ -430,7 +430,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
descriptor.BufferAddress,
MemoryState.IsPoolAllocated,
MemoryState.IsPoolAllocated,
- MemoryPermission.Read,
+ KMemoryPermission.Read,
MemoryAttribute.Uncached,
MemoryAttribute.None);
@@ -473,9 +473,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
bool notReceiveDesc = isSendDesc || isExchangeDesc;
bool isReceiveDesc = !notReceiveDesc;
- MemoryPermission permission = index >= clientHeader.SendBuffersCount
- ? MemoryPermission.ReadAndWrite
- : MemoryPermission.Read;
+ KMemoryPermission permission = index >= clientHeader.SendBuffersCount
+ ? KMemoryPermission.ReadAndWrite
+ : KMemoryPermission.Read;
uint sizeHigh4 = (descWord2 >> 24) & 0xf;
@@ -559,9 +559,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
if (serverMsg.IsCustom || clientMsg.IsCustom)
{
- MemoryPermission permission = clientMsg.IsCustom
- ? MemoryPermission.None
- : MemoryPermission.Read;
+ KMemoryPermission permission = clientMsg.IsCustom
+ ? KMemoryPermission.None
+ : KMemoryPermission.Read;
clientResult = clientProcess.MemoryManager.CopyDataToCurrentProcess(
copyDst,
@@ -795,7 +795,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
descriptor.BufferSize,
MemoryState.IsPoolAllocated,
MemoryState.IsPoolAllocated,
- MemoryPermission.Read,
+ KMemoryPermission.Read,
MemoryAttribute.Uncached,
MemoryAttribute.None,
descriptor.BufferAddress);
@@ -849,9 +849,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
if (serverMsg.IsCustom || clientMsg.IsCustom)
{
- MemoryPermission permission = clientMsg.IsCustom
- ? MemoryPermission.None
- : MemoryPermission.Read;
+ KMemoryPermission permission = clientMsg.IsCustom
+ ? KMemoryPermission.None
+ : KMemoryPermission.Read;
clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess(
copyDst,
@@ -898,11 +898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return new MessageHeader(word0, word1, word2);
}
- private KernelResult GetCopyObjectHandle(
- KThread srcThread,
- KProcess dstProcess,
- int srcHandle,
- out int dstHandle)
+ private KernelResult GetCopyObjectHandle(KThread srcThread, KProcess dstProcess, int srcHandle, out int dstHandle)
{
dstHandle = 0;
@@ -933,11 +929,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
}
}
- private KernelResult GetMoveObjectHandle(
- KProcess srcProcess,
- KProcess dstProcess,
- int srcHandle,
- out int dstHandle)
+ private KernelResult GetMoveObjectHandle(KProcess srcProcess, KProcess dstProcess, int srcHandle, out int dstHandle)
{
dstHandle = 0;
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs
index 4b5886a9..d614857c 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs
@@ -4,7 +4,7 @@ using System;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
- class KSession : KAutoObject, IDisposable
+ class KSession : KAutoObject
{
public KServerSession ServerSession { get; }
public KClientSession ClientSession { get; }
@@ -37,19 +37,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
}
}
- public void Dispose()
- {
- Dispose(true);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing && ClientSession.Service is IDisposable disposableService)
- {
- disposableService.Dispose();
- }
- }
-
protected override void Destroy()
{
if (_hasBeenInitialized)
diff --git a/Ryujinx.HLE/HOS/Kernel/KernelContext.cs b/Ryujinx.HLE/HOS/Kernel/KernelContext.cs
index a2d8bc47..d19c43ee 100644
--- a/Ryujinx.HLE/HOS/Kernel/KernelContext.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KernelContext.cs
@@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel
Device = device;
Memory = memory;
- Syscall = new Syscall(device, this);
+ Syscall = new Syscall(this);
SyscallHandler = new SyscallHandler(this);
diff --git a/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
new file mode 100644
index 00000000..c7deadae
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
@@ -0,0 +1,38 @@
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using System;
+using System.Threading.Tasks;
+
+namespace Ryujinx.HLE.HOS.Kernel
+{
+ static class KernelStatic
+ {
+ [ThreadStatic]
+ private static KernelContext Context;
+
+ public static void YieldUntilCompletion(Action action)
+ {
+ YieldUntilCompletion(Task.Factory.StartNew(action));
+ }
+
+ public static void YieldUntilCompletion(Task task)
+ {
+ KThread currentThread = Context.Scheduler.GetCurrentThread();
+
+ Context.CriticalSection.Enter();
+
+ currentThread.Reschedule(ThreadSchedState.Paused);
+
+ task.ContinueWith((antecedent) =>
+ {
+ currentThread.Reschedule(ThreadSchedState.Running);
+ });
+
+ Context.CriticalSection.Leave();
+ }
+
+ internal static void SetKernelContext(KernelContext context)
+ {
+ Context = context;
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs
index 04e14e1b..b93b68d9 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs
@@ -8,9 +8,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public ulong PagesCount { get; private set; }
public MemoryState State { get; private set; }
- public MemoryPermission Permission { get; private set; }
+ public KMemoryPermission Permission { get; private set; }
public MemoryAttribute Attribute { get; private set; }
- public MemoryPermission SourcePermission { get; private set; }
+ public KMemoryPermission SourcePermission { get; private set; }
public int IpcRefCount { get; private set; }
public int DeviceRefCount { get; private set; }
@@ -19,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong baseAddress,
ulong pagesCount,
MemoryState state,
- MemoryPermission permission,
+ KMemoryPermission permission,
MemoryAttribute attribute,
int ipcRefCount = 0,
int deviceRefCount = 0)
@@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
DeviceRefCount = deviceRefCount;
}
- public void SetState(MemoryPermission permission, MemoryState state, MemoryAttribute attribute)
+ public void SetState(KMemoryPermission permission, MemoryState state, MemoryAttribute attribute)
{
Permission = permission;
State = state;
@@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
Attribute |= attribute;
}
- public void SetIpcMappingPermission(MemoryPermission newPermission)
+ public void SetIpcMappingPermission(KMemoryPermission newPermission)
{
int oldIpcRefCount = IpcRefCount++;
@@ -54,8 +54,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
SourcePermission = Permission;
- Permission &= ~MemoryPermission.ReadAndWrite;
- Permission |= MemoryPermission.ReadAndWrite & newPermission;
+ Permission &= ~KMemoryPermission.ReadAndWrite;
+ Permission |= KMemoryPermission.ReadAndWrite & newPermission;
}
Attribute |= MemoryAttribute.IpcMapped;
@@ -74,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
Permission = SourcePermission;
- SourcePermission = MemoryPermission.None;
+ SourcePermission = KMemoryPermission.None;
Attribute &= ~MemoryAttribute.IpcMapped;
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs
index 21e9e494..af070ac2 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs
@@ -6,9 +6,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public ulong Size { get; }
public MemoryState State { get; }
- public MemoryPermission Permission { get; }
+ public KMemoryPermission Permission { get; }
public MemoryAttribute Attribute { get; }
- public MemoryPermission SourcePermission { get; }
+ public KMemoryPermission SourcePermission { get; }
public int IpcRefCount { get; }
public int DeviceRefCount { get; }
@@ -17,9 +17,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address,
ulong size,
MemoryState state,
- MemoryPermission permission,
+ KMemoryPermission permission,
MemoryAttribute attribute,
- MemoryPermission sourcePermission,
+ KMemoryPermission sourcePermission,
int ipcRefCount,
int deviceRefCount)
{
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs
index 43e7ad69..63ac8583 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs
@@ -1,9 +1,10 @@
using Ryujinx.Common;
-using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Memory;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
namespace Ryujinx.HLE.HOS.Kernel.Memory
{
@@ -27,11 +28,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
// needs to be split in 2, plus one block that will be the new one inserted.
private const int MaxBlocksNeededForInsertion = 2;
- private LinkedList<KMemoryBlock> _blocks;
+ private readonly LinkedList<KMemoryBlock> _blocks;
- private MemoryManager _cpuMemory;
+ private readonly IVirtualMemoryManager _cpuMemory;
- private KernelContext _context;
+ private readonly KernelContext _context;
public ulong AddrSpaceStart { get; private set; }
public ulong AddrSpaceEnd { get; private set; }
@@ -73,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private MersenneTwister _randomNumberGenerator;
- public KMemoryManager(KernelContext context, MemoryManager cpuMemory)
+ public KMemoryManager(KernelContext context, IVirtualMemoryManager cpuMemory)
{
_context = context;
_cpuMemory = cpuMemory;
@@ -352,7 +353,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
addrSpaceStart,
addrSpacePagesCount,
MemoryState.Unmapped,
- MemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.None));
return KernelResult.Success;
@@ -362,13 +363,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address,
KPageList pageList,
MemoryState state,
- MemoryPermission permission)
+ KMemoryPermission permission)
{
ulong pagesCount = pageList.GetPagesCount();
ulong size = pagesCount * PageSize;
- if (!ValidateRegionForState(address, size, state))
+ if (!CanContain(address, size, state))
{
return KernelResult.InvalidMemState;
}
@@ -437,8 +438,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
stateExpected,
- MemoryPermission.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@@ -467,13 +468,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult MapNormalMemory(long address, long size, MemoryPermission permission)
+ public KernelResult MapNormalMemory(long address, long size, KMemoryPermission permission)
{
// TODO.
return KernelResult.Success;
}
- public KernelResult MapIoMemory(long address, long size, MemoryPermission permission)
+ public KernelResult MapIoMemory(long address, long size, KMemoryPermission permission)
{
// TODO.
return KernelResult.Success;
@@ -487,7 +488,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong regionStart,
ulong regionPagesCount,
MemoryState state,
- MemoryPermission permission,
+ KMemoryPermission permission,
out ulong address)
{
address = 0;
@@ -496,7 +497,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong regionEndAddr = regionStart + regionSize;
- if (!ValidateRegionForState(regionStart, regionSize, state))
+ if (!CanContain(regionStart, regionSize, state))
{
return KernelResult.InvalidMemState;
}
@@ -547,11 +548,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address,
ulong pagesCount,
MemoryState state,
- MemoryPermission permission)
+ KMemoryPermission permission)
{
ulong size = pagesCount * PageSize;
- if (!ValidateRegionForState(address, size, state))
+ if (!CanContain(address, size, state))
{
return KernelResult.InvalidMemState;
}
@@ -596,13 +597,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
MemoryState.Heap,
- MemoryPermission.Mask,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.Mask,
+ KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
out MemoryState state,
- out MemoryPermission permission,
+ out KMemoryPermission permission,
out _);
success &= IsUnmapped(dst, size);
@@ -618,14 +619,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
AddVaRangeToPageList(pageList, src, pagesCount);
- KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None);
+ KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None);
if (result != KernelResult.Success)
{
return result;
}
- result = MapPages(dst, pageList, MemoryPermission.None);
+ result = MapPages(dst, pageList, KMemoryPermission.None);
if (result != KernelResult.Success)
{
@@ -634,7 +635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
- InsertBlock(src, pagesCount, state, MemoryPermission.None, MemoryAttribute.Borrowed);
+ InsertBlock(src, pagesCount, state, KMemoryPermission.None, MemoryAttribute.Borrowed);
InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic);
return KernelResult.Success;
@@ -657,8 +658,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
MemoryState.Heap,
- MemoryPermission.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.Borrowed,
MemoryAttribute.IpcAndDeviceMapped,
@@ -671,8 +672,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
PageSize,
MemoryState.UnmapProcessCodeMemoryAllowed,
MemoryState.UnmapProcessCodeMemoryAllowed,
- MemoryPermission.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@@ -685,8 +686,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
state,
- MemoryPermission.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None);
@@ -707,7 +708,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
InsertBlock(dst, pagesCount, MemoryState.Unmapped);
- InsertBlock(src, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
+ InsertBlock(src, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
return KernelResult.Success;
}
@@ -788,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_currentHeapAddr,
pagesCount,
pageList,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.ReadAndWrite,
MemoryOperation.MapVa);
if (result != KernelResult.Success)
@@ -798,7 +799,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
- InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
+ InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
}
else
{
@@ -816,8 +817,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
sizeDelta,
MemoryState.Mask,
MemoryState.Heap,
- MemoryPermission.Mask,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.Mask,
+ KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@@ -886,13 +887,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.AttributeChangeAllowed,
MemoryState.AttributeChangeAllowed,
- MemoryPermission.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.BorrowedAndIpcMapped,
MemoryAttribute.None,
MemoryAttribute.DeviceMappedAndUncached,
out MemoryState state,
- out MemoryPermission permission,
+ out KMemoryPermission permission,
out MemoryAttribute attribute))
{
if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
@@ -932,9 +933,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
AddrSpaceEnd,
~AddrSpaceEnd + 1,
MemoryState.Reserved,
- MemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
0,
0);
}
@@ -951,8 +952,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.MapAllowed,
MemoryState.MapAllowed,
- MemoryPermission.Mask,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.Mask,
+ KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@@ -975,18 +976,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
AddVaRangeToPageList(pageList, src, pagesCount);
- KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None);
+ KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None);
if (result != KernelResult.Success)
{
return result;
}
- result = MapPages(dst, pageList, MemoryPermission.ReadAndWrite);
+ result = MapPages(dst, pageList, KMemoryPermission.ReadAndWrite);
if (result != KernelResult.Success)
{
- if (MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite) != KernelResult.Success)
+ if (MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite) != KernelResult.Success)
{
throw new InvalidOperationException("Unexpected failure reverting memory permission.");
}
@@ -994,8 +995,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
- InsertBlock(src, pagesCount, srcState, MemoryPermission.None, MemoryAttribute.Borrowed);
- InsertBlock(dst, pagesCount, MemoryState.Stack, MemoryPermission.ReadAndWrite);
+ InsertBlock(src, pagesCount, srcState, KMemoryPermission.None, MemoryAttribute.Borrowed);
+ InsertBlock(dst, pagesCount, MemoryState.Stack, KMemoryPermission.ReadAndWrite);
return KernelResult.Success;
}
@@ -1017,8 +1018,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
stateExpected,
- MemoryPermission.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@@ -1058,8 +1059,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.MapAllowed,
MemoryState.MapAllowed,
- MemoryPermission.Mask,
- MemoryPermission.None,
+ KMemoryPermission.Mask,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.Borrowed,
MemoryAttribute.IpcAndDeviceMapped,
@@ -1072,13 +1073,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
MemoryState.Stack,
- MemoryPermission.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
out _,
- out MemoryPermission dstPermission,
+ out KMemoryPermission dstPermission,
out _);
if (success)
@@ -1108,7 +1109,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
- result = MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite);
+ result = MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite);
if (result != KernelResult.Success)
{
@@ -1117,7 +1118,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
- InsertBlock(src, pagesCount, srcState, MemoryPermission.ReadAndWrite);
+ InsertBlock(src, pagesCount, srcState, KMemoryPermission.ReadAndWrite);
InsertBlock(dst, pagesCount, MemoryState.Unmapped);
return KernelResult.Success;
@@ -1129,7 +1130,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult SetProcessMemoryPermission(ulong address, ulong size, MemoryPermission permission)
+ public KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
{
lock (_blocks)
{
@@ -1138,20 +1139,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.ProcessPermissionChangeAllowed,
MemoryState.ProcessPermissionChangeAllowed,
- MemoryPermission.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
out MemoryState oldState,
- out MemoryPermission oldPermission,
+ out KMemoryPermission oldPermission,
out _))
{
MemoryState newState = oldState;
// If writing into the code region is allowed, then we need
// to change it to mutable.
- if ((permission & MemoryPermission.Write) != 0)
+ if ((permission & KMemoryPermission.Write) != 0)
{
if (oldState == MemoryState.CodeStatic)
{
@@ -1176,7 +1177,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = size / PageSize;
- MemoryOperation operation = (permission & MemoryPermission.Execute) != 0
+ MemoryOperation operation = (permission & KMemoryPermission.Execute) != 0
? MemoryOperation.ChangePermsAndAttributes
: MemoryOperation.ChangePermRw;
@@ -1270,10 +1271,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
address,
pagesCount,
MemoryState.Unmapped,
- MemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.None,
MemoryState.Heap,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.ReadAndWrite,
MemoryAttribute.None);
}
@@ -1410,7 +1411,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pagesCount,
srcPa,
true,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.ReadAndWrite,
MemoryOperation.MapPa);
dstVa += pagesCount * PageSize;
@@ -1428,7 +1429,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong src,
MemoryState stateMask,
MemoryState stateExpected,
- MemoryPermission permission,
+ KMemoryPermission permission,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected)
{
@@ -1450,7 +1451,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
MemoryState stateMask,
MemoryState stateExpected,
- MemoryPermission permission,
+ KMemoryPermission permission,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected,
ulong src)
@@ -1474,7 +1475,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong serverAddress,
MemoryState stateMask,
MemoryState stateExpected,
- MemoryPermission permission,
+ KMemoryPermission permission,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected,
bool toServer)
@@ -1529,7 +1530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
ulong src,
KMemoryManager sourceMemMgr,
- MemoryPermission permission,
+ KMemoryPermission permission,
MemoryState state,
bool copyData,
out ulong dst)
@@ -1568,7 +1569,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private KernelResult GetPagesForMappingIntoAnotherProcess(
ulong address,
ulong size,
- MemoryPermission permission,
+ KMemoryPermission permission,
MemoryState state,
bool copyData,
bool aslrDisabled,
@@ -1600,9 +1601,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
default: return KernelResult.InvalidCombination;
}
- MemoryPermission permissionMask = permission == MemoryPermission.ReadAndWrite
- ? MemoryPermission.None
- : MemoryPermission.Read;
+ KMemoryPermission permissionMask = permission == KMemoryPermission.ReadAndWrite
+ ? KMemoryPermission.None
+ : KMemoryPermission.Read;
MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached;
@@ -1634,7 +1635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrVisited))
{
- if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
+ if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
{
ulong blockAddress = GetAddrInRange(info, addressRounded);
ulong blockSize = GetSizeInRange(info, addressRounded, endAddrVisited);
@@ -1661,7 +1662,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (addressRounded < endAddrTruncated)
{
- foreach (KMemoryInfo info in IterateOverRange(addressTruncated, endAddrRounded))
+ foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrTruncated))
{
// Check if the block state matches what we expect.
if ((info.State & stateMask) != stateMask ||
@@ -1678,7 +1679,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong blockPagesCount = blockSize / PageSize;
- if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
+ if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
{
result = DoMmuOperation(
blockAddress,
@@ -1784,7 +1785,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
ulong unusedSizeBefore = address - addressTruncated;
- _context.Memory.ZeroFill(dstFirstPagePa, unusedSizeBefore);
+ _context.Memory.ZeroFill(GetDramAddressFromPa(dstFirstPagePa), unusedSizeBefore);
ulong copySize = addressRounded <= endAddr ? addressRounded - address : size;
@@ -1803,7 +1804,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (unusedSizeAfter != 0)
{
- _context.Memory.ZeroFill(firstPageFillAddress, unusedSizeAfter);
+ _context.Memory.ZeroFill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter);
}
if (pages.AddRange(dstFirstPagePa, 1) != KernelResult.Success)
@@ -1865,7 +1866,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
unusedSizeAfter = PageSize;
}
- _context.Memory.ZeroFill(lastPageFillAddr, unusedSizeAfter);
+ _context.Memory.ZeroFill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter);
if (pages.AddRange(dstLastPagePa, 1) != KernelResult.Success)
{
@@ -1897,7 +1898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private KernelResult MapPagesFromAnotherProcess(
ulong size,
ulong address,
- MemoryPermission permission,
+ KMemoryPermission permission,
MemoryState state,
KPageList pageList,
out ulong dst)
@@ -1975,8 +1976,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
state,
- MemoryPermission.Read,
- MemoryPermission.Read,
+ KMemoryPermission.Read,
+ KMemoryPermission.Read,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@@ -1996,14 +1997,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = (endAddrRounded - addressTruncated) / PageSize;
- KernelResult result = DoMmuOperation(
- addressTruncated,
- pagesCount,
- 0,
- false,
- MemoryPermission.None,
- MemoryOperation.Unmap);
-
// Free pages we had to create on-demand, if any of the buffer was not page aligned.
// Real kernel has page ref counting, so this is done as part of the unmap operation.
if (addressTruncated != addressRounded)
@@ -2016,6 +2009,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
FreeSinglePage(_memRegion, ConvertVaToPa(endAddrTruncated));
}
+ KernelResult result = DoMmuOperation(
+ addressTruncated,
+ pagesCount,
+ 0,
+ false,
+ KMemoryPermission.None,
+ MemoryOperation.Unmap);
+
if (result == KernelResult.Success)
{
InsertBlock(addressTruncated, pagesCount, MemoryState.Unmapped);
@@ -2037,7 +2038,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong addressRounded = BitUtils.AlignUp (address, PageSize);
ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize);
- ulong pagesCount = (endAddrTruncated - addressRounded) / PageSize;
+ ulong pagesCount = addressRounded < endAddrTruncated ? (endAddrTruncated - addressRounded) / PageSize : 0;
+
+ if (pagesCount == 0)
+ {
+ return KernelResult.Success;
+ }
MemoryState stateMask;
@@ -2111,23 +2117,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.IpcBufferAllowed,
MemoryState.IpcBufferAllowed,
- MemoryPermission.Mask,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.Mask,
+ KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask,
MemoryAttribute.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.Borrowed);
}
- public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, MemoryPermission permission)
+ public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, KMemoryPermission permission)
{
return SetAttributesAndChangePermission(
address,
size,
MemoryState.TransferMemoryAllowed,
MemoryState.TransferMemoryAllowed,
- MemoryPermission.Mask,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.Mask,
+ KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask,
MemoryAttribute.None,
permission,
@@ -2140,11 +2146,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
MemoryState stateMask,
MemoryState stateExpected,
- MemoryPermission permissionMask,
- MemoryPermission permissionExpected,
+ KMemoryPermission permissionMask,
+ KMemoryPermission permissionExpected,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected,
- MemoryPermission newPermission,
+ KMemoryPermission newPermission,
MemoryAttribute attributeSetMask,
KPageList pageList = null)
{
@@ -2166,7 +2172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
attributeExpected,
MemoryAttribute.IpcAndDeviceMapped,
out MemoryState oldState,
- out MemoryPermission oldPermission,
+ out KMemoryPermission oldPermission,
out MemoryAttribute oldAttribute))
{
ulong pagesCount = size / PageSize;
@@ -2181,7 +2187,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource;
}
- if (newPermission == MemoryPermission.None)
+ if (newPermission == KMemoryPermission.None)
{
newPermission = oldPermission;
}
@@ -2222,11 +2228,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.IpcBufferAllowed,
MemoryState.IpcBufferAllowed,
- MemoryPermission.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.Borrowed,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.ReadAndWrite,
MemoryAttribute.Borrowed);
}
@@ -2237,11 +2243,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.TransferMemoryAllowed,
MemoryState.TransferMemoryAllowed,
- MemoryPermission.None,
- MemoryPermission.None,
+ KMemoryPermission.None,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.Borrowed,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.ReadAndWrite,
MemoryAttribute.Borrowed,
pageList);
}
@@ -2251,11 +2257,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
MemoryState stateMask,
MemoryState stateExpected,
- MemoryPermission permissionMask,
- MemoryPermission permissionExpected,
+ KMemoryPermission permissionMask,
+ KMemoryPermission permissionExpected,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected,
- MemoryPermission newPermission,
+ KMemoryPermission newPermission,
MemoryAttribute attributeClearMask,
KPageList pageList = null)
{
@@ -2277,7 +2283,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
attributeExpected,
MemoryAttribute.IpcAndDeviceMapped,
out MemoryState oldState,
- out MemoryPermission oldPermission,
+ out KMemoryPermission oldPermission,
out MemoryAttribute oldAttribute))
{
ulong pagesCount = size / PageSize;
@@ -2299,7 +2305,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource;
}
- if (newPermission == MemoryPermission.None)
+ if (newPermission == KMemoryPermission.None)
{
newPermission = oldPermission;
}
@@ -2385,8 +2391,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
MemoryState.Unmapped,
- MemoryPermission.Mask,
- MemoryPermission.None,
+ KMemoryPermission.Mask,
+ KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@@ -2400,13 +2406,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
MemoryState stateMask,
MemoryState stateExpected,
- MemoryPermission permissionMask,
- MemoryPermission permissionExpected,
+ KMemoryPermission permissionMask,
+ KMemoryPermission permissionExpected,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected,
MemoryAttribute attributeIgnoreMask,
out MemoryState outState,
- out MemoryPermission outPermission,
+ out KMemoryPermission outPermission,
out MemoryAttribute outAttribute)
{
ulong endAddr = address + size;
@@ -2416,7 +2422,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
KMemoryInfo info = node.Value.GetInfo();
MemoryState firstState = info.State;
- MemoryPermission firstPermission = info.Permission;
+ KMemoryPermission firstPermission = info.Permission;
MemoryAttribute firstAttribute = info.Attribute;
do
@@ -2432,7 +2438,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
(firstPermission & permissionMask) != permissionExpected)
{
outState = MemoryState.Unmapped;
- outPermission = MemoryPermission.None;
+ outPermission = KMemoryPermission.None;
outAttribute = MemoryAttribute.None;
return false;
@@ -2452,8 +2458,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
MemoryState stateMask,
MemoryState stateExpected,
- MemoryPermission permissionMask,
- MemoryPermission permissionExpected,
+ KMemoryPermission permissionMask,
+ KMemoryPermission permissionExpected,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected)
{
@@ -2490,10 +2496,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong baseAddress,
ulong pagesCount,
MemoryState oldState,
- MemoryPermission oldPermission,
+ KMemoryPermission oldPermission,
MemoryAttribute oldAttribute,
MemoryState newState,
- MemoryPermission newPermission,
+ KMemoryPermission newPermission,
MemoryAttribute newAttribute)
{
// Insert new block on the list only on areas where the state
@@ -2553,13 +2559,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
_blockAllocator.Count += _blocks.Count - oldCount;
+
+ ValidateInternalState();
}
private void InsertBlock(
ulong baseAddress,
ulong pagesCount,
MemoryState state,
- MemoryPermission permission = MemoryPermission.None,
+ KMemoryPermission permission = KMemoryPermission.None,
MemoryAttribute attribute = MemoryAttribute.None)
{
// Inserts new block at the list, replacing and splitting
@@ -2605,25 +2613,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
_blockAllocator.Count += _blocks.Count - oldCount;
+
+ ValidateInternalState();
}
- private static void SetIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission)
+ private static void SetIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission)
{
block.SetIpcMappingPermission(permission);
}
- private static void RestoreIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission)
+ private static void RestoreIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission)
{
block.RestoreIpcMappingPermission();
}
- private delegate void BlockMutator(KMemoryBlock block, MemoryPermission newPerm);
+ private delegate void BlockMutator(KMemoryBlock block, KMemoryPermission newPerm);
private void InsertBlock(
ulong baseAddress,
ulong pagesCount,
BlockMutator blockMutate,
- MemoryPermission permission = MemoryPermission.None)
+ KMemoryPermission permission = KMemoryPermission.None)
{
// Inserts new block at the list, replacing and splitting
// existing blocks as needed, then calling the callback
@@ -2671,6 +2681,31 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
_blockAllocator.Count += _blocks.Count - oldCount;
+
+ ValidateInternalState();
+ }
+
+ [Conditional("DEBUG")]
+ private void ValidateInternalState()
+ {
+ ulong expectedAddress = 0;
+
+ LinkedListNode<KMemoryBlock> node = _blocks.First;
+
+ while (node != null)
+ {
+ LinkedListNode<KMemoryBlock> newNode = node;
+
+ KMemoryBlock currBlock = node.Value;
+
+ Debug.Assert(currBlock.BaseAddress == expectedAddress);
+
+ expectedAddress = currBlock.BaseAddress + currBlock.PagesCount * PageSize;
+
+ node = newNode.Next;
+ }
+
+ Debug.Assert(expectedAddress == AddrSpaceEnd);
}
private LinkedListNode<KMemoryBlock> MergeEqualStateNeighbors(LinkedListNode<KMemoryBlock> node)
@@ -2876,13 +2911,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return null;
}
- private bool ValidateRegionForState(ulong address, ulong size, MemoryState state)
+ public bool CanContain(ulong address, ulong size, MemoryState state)
{
ulong endAddr = address + size;
- ulong regionBaseAddr = GetBaseAddrForState(state);
-
- ulong regionEndAddr = regionBaseAddr + GetSizeForState(state);
+ ulong regionBaseAddr = GetBaseAddress(state);
+ ulong regionEndAddr = regionBaseAddr + GetSize(state);
bool InsideRegion()
{
@@ -2891,17 +2925,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
endAddr - 1 <= regionEndAddr - 1;
}
- bool OutsideHeapRegion()
- {
- return endAddr <= HeapRegionStart ||
- address >= HeapRegionEnd;
- }
-
- bool OutsideMapRegion()
- {
- return endAddr <= AliasRegionStart ||
- address >= AliasRegionEnd;
- }
+ bool OutsideHeapRegion() => endAddr <= HeapRegionStart || address >= HeapRegionEnd;
+ bool OutsideAliasRegion() => endAddr <= AliasRegionStart || address >= AliasRegionEnd;
switch (state)
{
@@ -2919,10 +2944,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
case MemoryState.ProcessMemory:
case MemoryState.CodeReadOnly:
case MemoryState.CodeWritable:
- return InsideRegion() && OutsideHeapRegion() && OutsideMapRegion();
+ return InsideRegion() && OutsideHeapRegion() && OutsideAliasRegion();
case MemoryState.Heap:
- return InsideRegion() && OutsideMapRegion();
+ return InsideRegion() && OutsideAliasRegion();
case MemoryState.IpcBuffer0:
case MemoryState.IpcBuffer1:
@@ -2936,7 +2961,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
throw new ArgumentException($"Invalid state value \"{state}\".");
}
- private ulong GetBaseAddrForState(MemoryState state)
+ private ulong GetBaseAddress(MemoryState state)
{
switch (state)
{
@@ -2975,7 +3000,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
throw new ArgumentException($"Invalid state value \"{state}\".");
}
- private ulong GetSizeForState(MemoryState state)
+ private ulong GetSize(MemoryState state)
{
switch (state)
{
@@ -3050,7 +3075,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- private KernelResult MapPages(ulong address, KPageList pageList, MemoryPermission permission)
+ private KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission)
{
ulong currAddr = address;
@@ -3090,11 +3115,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pagesCount,
0,
false,
- MemoryPermission.None,
+ KMemoryPermission.None,
MemoryOperation.Unmap);
}
- private KernelResult MmuChangePermission(ulong address, ulong pagesCount, MemoryPermission permission)
+ private KernelResult MmuChangePermission(ulong address, ulong pagesCount, KMemoryPermission permission)
{
return DoMmuOperation(
address,
@@ -3110,7 +3135,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount,
ulong srcPa,
bool map,
- MemoryPermission permission,
+ KMemoryPermission permission,
MemoryOperation operation)
{
if (map != (operation == MemoryOperation.MapPa))
@@ -3171,7 +3196,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address,
ulong pagesCount,
KPageList pageList,
- MemoryPermission permission,
+ KMemoryPermission permission,
MemoryOperation operation)
{
if (operation != MemoryOperation.MapVa)
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
index 65134f0d..ca0e3421 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
@@ -10,15 +10,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private readonly long _ownerPid;
- private readonly MemoryPermission _ownerPermission;
- private readonly MemoryPermission _userPermission;
+ private readonly KMemoryPermission _ownerPermission;
+ private readonly KMemoryPermission _userPermission;
public KSharedMemory(
KernelContext context,
KPageList pageList,
long ownerPid,
- MemoryPermission ownerPermission,
- MemoryPermission userPermission) : base(context)
+ KMemoryPermission ownerPermission,
+ KMemoryPermission userPermission) : base(context)
{
_pageList = pageList;
_ownerPid = ownerPid;
@@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address,
ulong size,
KProcess process,
- MemoryPermission permission)
+ KMemoryPermission permission)
{
ulong pagesCountRounded = BitUtils.DivRoundUp(size, KMemoryManager.PageSize);
@@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.InvalidSize;
}
- MemoryPermission expectedPermission = process.Pid == _ownerPid
+ KMemoryPermission expectedPermission = process.Pid == _ownerPid
? _ownerPermission
: _userPermission;
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
index d3e6208e..96349452 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
@@ -8,12 +8,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
private KProcess _creator;
+ // TODO: Remove when we no longer need to read it from the owner directly.
+ public KProcess Creator => _creator;
+
private readonly KPageList _pageList;
public ulong Address { get; private set; }
public ulong Size => _pageList.GetPagesCount() * KMemoryManager.PageSize;
- public MemoryPermission Permission { get; private set; }
+ public KMemoryPermission Permission { get; private set; }
private bool _hasBeenInitialized;
private bool _isMapped;
@@ -23,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_pageList = new KPageList();
}
- public KernelResult Initialize(ulong address, ulong size, MemoryPermission permission)
+ public KernelResult Initialize(ulong address, ulong size, KMemoryPermission permission)
{
KProcess creator = KernelContext.Scheduler.GetCurrentProcess();
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs b/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs
index 0ad90abd..8bfd8d94 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs
@@ -3,7 +3,7 @@ using System;
namespace Ryujinx.HLE.HOS.Kernel.Memory
{
[Flags]
- enum MemoryPermission : byte
+ enum KMemoryPermission : byte
{
None = 0,
Mask = 0xff,
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
index 376badfb..5ad33154 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
@@ -1,7 +1,7 @@
-using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.Loaders.Elf;
+using Ryujinx.Memory;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -224,7 +224,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
break;
}
- if (info.State == MemoryState.CodeStatic && info.Permission == MemoryPermission.ReadAndExecute)
+ if (info.State == MemoryState.CodeStatic && info.Permission == KMemoryPermission.ReadAndExecute)
{
LoadMod0Symbols(_owner.CpuMemory, info.Address);
}
@@ -235,7 +235,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
- private void LoadMod0Symbols(MemoryManager memory, ulong textOffset)
+ private void LoadMod0Symbols(IVirtualMemoryManager memory, ulong textOffset)
{
ulong mod0Offset = textOffset + memory.Read<uint>(textOffset + 4);
@@ -319,7 +319,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
- private ElfSymbol GetSymbol64(MemoryManager memory, ulong address, ulong strTblAddr)
+ private ElfSymbol GetSymbol64(IVirtualMemoryManager memory, ulong address, ulong strTblAddr)
{
ElfSymbol64 sym = memory.Read<ElfSymbol64>(address);
@@ -335,7 +335,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size);
}
- private ElfSymbol GetSymbol32(MemoryManager memory, ulong address, ulong strTblAddr)
+ private ElfSymbol GetSymbol32(IVirtualMemoryManager memory, ulong address, ulong strTblAddr)
{
ElfSymbol32 sym = memory.Read<ElfSymbol32>(address);
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
new file mode 100644
index 00000000..758ac6b1
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
@@ -0,0 +1,13 @@
+using ARMeilleure.State;
+using Ryujinx.Memory;
+using System;
+
+namespace Ryujinx.HLE.HOS.Kernel.Process
+{
+ interface IProcessContext : IDisposable
+ {
+ IVirtualMemoryManager AddressSpace { get; }
+
+ void Execute(ExecutionContext context, ulong codeAddress);
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs
new file mode 100644
index 00000000..c438b570
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs
@@ -0,0 +1,10 @@
+using Ryujinx.Cpu;
+using Ryujinx.Memory;
+
+namespace Ryujinx.HLE.HOS.Kernel.Process
+{
+ interface IProcessContextFactory
+ {
+ IProcessContext Create(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler);
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
index d02e25a3..8e914f19 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
@@ -6,6 +6,7 @@ using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -15,13 +16,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
class KProcess : KSynchronizationObject
{
- public const int KernelVersionMajor = 10;
- public const int KernelVersionMinor = 4;
+ public const int KernelVersionMajor = 10;
+ public const int KernelVersionMinor = 4;
public const int KernelVersionRevision = 0;
public const int KernelVersionPacked =
- (KernelVersionMajor << 19) |
- (KernelVersionMinor << 15) |
+ (KernelVersionMajor << 19) |
+ (KernelVersionMinor << 15) |
(KernelVersionRevision << 0);
public KMemoryManager MemoryManager { get; private set; }
@@ -47,27 +48,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public long[] RandomEntropy { get; private set; }
private bool _signaled;
- private bool _useSystemMemBlocks;
public string Name { get; private set; }
private int _threadCount;
- public int MmuFlags { get; private set; }
+ public ProcessCreationFlags Flags { get; private set; }
private MemoryRegion _memRegion;
public KProcessCapabilities Capabilities { get; private set; }
public ulong TitleId { get; private set; }
- public long Pid { get; private set; }
+ public long Pid { get; private set; }
- private long _creationTimestamp;
+ private long _creationTimestamp;
private ulong _entrypoint;
+ private ThreadStart _customThreadStart;
private ulong _imageSize;
private ulong _mainThreadStackSize;
private ulong _memoryUsageCapacity;
- private int _version;
+ private int _version;
public KHandleTable HandleTable { get; private set; }
@@ -77,14 +78,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public bool IsPaused { get; private set; }
- public MemoryManager CpuMemory { get; private set; }
- public CpuContext CpuContext { get; private set; }
+ private IProcessContextFactory _contextFactory;
+ public IProcessContext Context { get; private set; }
+ public IVirtualMemoryManager CpuMemory => Context.AddressSpace;
public HleProcessDebugger Debugger { get; private set; }
public KProcess(KernelContext context) : base(context)
{
- _processLock = new object();
+ _processLock = new object();
_threadingLock = new object();
AddressArbiter = new KAddressArbiter(context);
@@ -96,6 +98,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
RandomEntropy = new long[KScheduler.CpuCoresCount];
+ // TODO: Remove once we no longer need to initialize it externally.
+ HandleTable = new KHandleTable(context);
+
_threads = new LinkedList<KThread>();
Debugger = new HleProcessDebugger(this);
@@ -103,25 +108,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public KernelResult InitializeKip(
ProcessCreationInfo creationInfo,
- int[] caps,
- KPageList pageList,
- KResourceLimit resourceLimit,
- MemoryRegion memRegion)
+ ReadOnlySpan<int> capabilities,
+ KPageList pageList,
+ KResourceLimit resourceLimit,
+ MemoryRegion memRegion,
+ IProcessContextFactory contextFactory)
{
ResourceLimit = resourceLimit;
- _memRegion = memRegion;
+ _memRegion = memRegion;
+ _contextFactory = contextFactory ?? new ProcessContextFactory();
- AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7);
+ AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
- InitializeMemoryManager(addrSpaceType, memRegion);
+ InitializeMemoryManager(creationInfo.Flags);
- bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0;
+ bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
ulong codeAddress = creationInfo.CodeAddress;
ulong codeSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
- KMemoryBlockAllocator memoryBlockAllocator = (MmuFlags & 0x40) != 0
+ KMemoryBlockAllocator memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
? KernelContext.LargeMemoryBlockAllocator
: KernelContext.SmallMemoryBlockAllocator;
@@ -139,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result;
}
- if (!ValidateCodeAddressAndSize(codeAddress, codeSize))
+ if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
{
return KernelResult.InvalidMemRange;
}
@@ -148,14 +155,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
codeAddress,
pageList,
MemoryState.CodeStatic,
- MemoryPermission.None);
+ KMemoryPermission.None);
if (result != KernelResult.Success)
{
return result;
}
- result = Capabilities.InitializeForKernel(caps, MemoryManager);
+ result = Capabilities.InitializeForKernel(capabilities, MemoryManager);
if (result != KernelResult.Success)
{
@@ -176,14 +183,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public KernelResult Initialize(
ProcessCreationInfo creationInfo,
- int[] caps,
- KResourceLimit resourceLimit,
- MemoryRegion memRegion)
+ ReadOnlySpan<int> capabilities,
+ KResourceLimit resourceLimit,
+ MemoryRegion memRegion,
+ IProcessContextFactory contextFactory,
+ ThreadStart customThreadStart = null)
{
ResourceLimit = resourceLimit;
- _memRegion = memRegion;
+ _memRegion = memRegion;
+ _contextFactory = contextFactory ?? new ProcessContextFactory();
- ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.PersonalMmHeapPagesCount, memRegion);
+ ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.SystemResourcePagesCount, memRegion);
ulong codePagesCount = (ulong)creationInfo.CodePagesCount;
@@ -205,7 +215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
- PersonalMmHeapPagesCount = (ulong)creationInfo.PersonalMmHeapPagesCount;
+ PersonalMmHeapPagesCount = (ulong)creationInfo.SystemResourcePagesCount;
KMemoryBlockAllocator memoryBlockAllocator;
@@ -215,16 +225,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
else
{
- memoryBlockAllocator = (MmuFlags & 0x40) != 0
+ memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
? KernelContext.LargeMemoryBlockAllocator
: KernelContext.SmallMemoryBlockAllocator;
}
- AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7);
+ AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
- InitializeMemoryManager(addrSpaceType, memRegion);
+ InitializeMemoryManager(creationInfo.Flags);
- bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0;
+ bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
ulong codeAddress = creationInfo.CodeAddress;
@@ -246,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result;
}
- if (!ValidateCodeAddressAndSize(codeAddress, codeSize))
+ if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
{
CleanUpForError();
@@ -257,7 +267,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
codeAddress,
codePagesCount,
MemoryState.CodeStatic,
- MemoryPermission.None);
+ KMemoryPermission.None);
if (result != KernelResult.Success)
{
@@ -266,7 +276,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result;
}
- result = Capabilities.InitializeForUser(caps, MemoryManager);
+ result = Capabilities.InitializeForUser(capabilities, MemoryManager);
if (result != KernelResult.Success)
{
@@ -289,57 +299,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
CleanUpForError();
}
- return result;
- }
-
- private bool ValidateCodeAddressAndSize(ulong address, ulong size)
- {
- ulong codeRegionStart;
- ulong codeRegionSize;
-
- switch (MemoryManager.AddrSpaceWidth)
- {
- case 32:
- codeRegionStart = 0x200000;
- codeRegionSize = 0x3fe00000;
- break;
-
- case 36:
- codeRegionStart = 0x8000000;
- codeRegionSize = 0x78000000;
- break;
-
- case 39:
- codeRegionStart = 0x8000000;
- codeRegionSize = 0x7ff8000000;
- break;
-
- default: throw new InvalidOperationException("Invalid address space width on memory manager.");
- }
-
- ulong endAddr = address + size;
-
- ulong codeRegionEnd = codeRegionStart + codeRegionSize;
-
- if (endAddr <= address ||
- endAddr - 1 > codeRegionEnd - 1)
- {
- return false;
- }
-
- if (MemoryManager.InsideHeapRegion (address, size) ||
- MemoryManager.InsideAliasRegion(address, size))
- {
- return false;
- }
+ _customThreadStart = customThreadStart;
- return true;
+ return result;
}
private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo)
{
// Ensure that the current kernel version is equal or above to the minimum required.
- uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
+ uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf;
if (KernelContext.EnableVersionChecks)
@@ -377,31 +345,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
_creationTimestamp = PerformanceCounter.ElapsedMilliseconds;
- MmuFlags = creationInfo.MmuFlags;
- _version = creationInfo.Version;
- TitleId = creationInfo.TitleId;
+ Flags = creationInfo.Flags;
+ _version = creationInfo.Version;
+ TitleId = creationInfo.TitleId;
_entrypoint = creationInfo.CodeAddress;
- _imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
-
- _useSystemMemBlocks = ((MmuFlags >> 6) & 1) != 0;
+ _imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
- switch ((AddressSpaceType)((MmuFlags >> 1) & 7))
+ switch (Flags & ProcessCreationFlags.AddressSpaceMask)
{
- case AddressSpaceType.Addr32Bits:
- case AddressSpaceType.Addr36Bits:
- case AddressSpaceType.Addr39Bits:
+ case ProcessCreationFlags.AddressSpace32Bit:
+ case ProcessCreationFlags.AddressSpace64BitDeprecated:
+ case ProcessCreationFlags.AddressSpace64Bit:
_memoryUsageCapacity = MemoryManager.HeapRegionEnd -
MemoryManager.HeapRegionStart;
break;
- case AddressSpaceType.Addr32BitsNoMap:
+ case ProcessCreationFlags.AddressSpace32BitWithoutAlias:
_memoryUsageCapacity = MemoryManager.HeapRegionEnd -
MemoryManager.HeapRegionStart +
MemoryManager.AliasRegionEnd -
MemoryManager.AliasRegionStart;
break;
- default: throw new InvalidOperationException($"Invalid MMU flags value 0x{MmuFlags:x2}.");
+ default: throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}.");
}
GenerateRandomEntropy();
@@ -469,7 +435,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
ulong regionStart = MemoryManager.TlsIoRegionStart;
- ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart;
+ ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart;
ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
@@ -481,7 +447,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
regionStart,
regionPagesCount,
MemoryState.ThreadLocal,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.ReadAndWrite,
out ulong tlsPageVa);
if (result != KernelResult.Success)
@@ -506,7 +472,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
KernelResult result = KernelResult.Success;
- KTlsPageInfo pageInfo = null;
+ KTlsPageInfo pageInfo;
if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo))
{
@@ -594,8 +560,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
// Check if the needed size for the code and the stack will fit on the
// memory usage capacity of this Process. Also check for possible overflow
// on the above addition.
- if (neededSize > _memoryUsageCapacity ||
- neededSize < stackSizeRounded)
+ if (neededSize > _memoryUsageCapacity || neededSize < stackSizeRounded)
{
threadResourceLimit?.Release(LimitableResource.Thread, 1);
@@ -646,7 +611,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize;
ulong regionStart = MemoryManager.StackRegionStart;
- ulong regionSize = MemoryManager.StackRegionEnd - regionStart;
+ ulong regionSize = MemoryManager.StackRegionEnd - regionStart;
ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
@@ -658,7 +623,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
regionStart,
regionPagesCount,
MemoryState.Stack,
- MemoryPermission.ReadAndWrite,
+ KMemoryPermission.ReadAndWrite,
out ulong stackBottom);
if (result != KernelResult.Success)
@@ -703,7 +668,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
stackTop,
mainThreadPriority,
DefaultCpuCore,
- this);
+ this,
+ ThreadType.User,
+ _customThreadStart);
if (result != KernelResult.Success)
{
@@ -730,20 +697,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
SetState(newState);
- // TODO: We can't call KThread.Start from a non-guest thread.
- // We will need to make some changes to allow the creation of
- // dummy threads that will be used to initialize the current
- // thread on KCoreContext so that GetCurrentThread doesn't fail.
- /* Result = MainThread.Start();
+ result = mainThread.Start();
- if (Result != KernelResult.Success)
+ if (result != KernelResult.Success)
{
- SetState(OldState);
+ SetState(oldState);
CleanUpForError();
- } */
-
- mainThread.Reschedule(ThreadSchedState.Running);
+ }
if (result == KernelResult.Success)
{
@@ -760,7 +721,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
if (State != newState)
{
- State = newState;
+ State = newState;
_signaled = true;
Signal();
@@ -769,23 +730,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public KernelResult InitializeThread(
KThread thread,
- ulong entrypoint,
- ulong argsPtr,
- ulong stackTop,
- int priority,
- int cpuCore)
+ ulong entrypoint,
+ ulong argsPtr,
+ ulong stackTop,
+ int priority,
+ int cpuCore)
{
lock (_processLock)
{
- return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this);
+ return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this, ThreadType.User, null);
}
}
public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context)
{
- context.Interrupt += InterruptHandler;
+ context.Interrupt += InterruptHandler;
context.SupervisorCall += KernelContext.SyscallHandler.SvcCall;
- context.Undefined += UndefinedInstructionHandler;
+ context.Undefined += UndefinedInstructionHandler;
}
private void InterruptHandler(object sender, EventArgs e)
@@ -910,8 +871,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
if (State >= ProcessState.Started)
{
- if (State == ProcessState.Started ||
- State == ProcessState.Crashed ||
+ if (State == ProcessState.Started ||
+ State == ProcessState.Crashed ||
State == ProcessState.Attached ||
State == ProcessState.DebugSuspended)
{
@@ -1072,23 +1033,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result;
}
- private void InitializeMemoryManager(AddressSpaceType addrSpaceType, MemoryRegion memRegion)
+ private void InitializeMemoryManager(ProcessCreationFlags flags)
{
- int addrSpaceBits = addrSpaceType switch
+ int addrSpaceBits = (flags & ProcessCreationFlags.AddressSpaceMask) switch
{
- AddressSpaceType.Addr32Bits => 32,
- AddressSpaceType.Addr36Bits => 36,
- AddressSpaceType.Addr32BitsNoMap => 32,
- AddressSpaceType.Addr39Bits => 39,
- _ => throw new ArgumentException(nameof(addrSpaceType))
+ ProcessCreationFlags.AddressSpace32Bit => 32,
+ ProcessCreationFlags.AddressSpace64BitDeprecated => 36,
+ ProcessCreationFlags.AddressSpace32BitWithoutAlias => 32,
+ ProcessCreationFlags.AddressSpace64Bit => 39,
+ _ => 39
};
- CpuMemory = new MemoryManager(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler);
- CpuContext = new CpuContext(CpuMemory);
+ Context = _contextFactory.Create(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler);
// TODO: This should eventually be removed.
// The GPU shouldn't depend on the CPU memory manager at all.
- KernelContext.Device.Gpu.SetVmm(CpuMemory);
+ if (flags.HasFlag(ProcessCreationFlags.IsApplication))
+ {
+ KernelContext.Device.Gpu.SetVmm((MemoryManager)CpuMemory);
+ }
MemoryManager = new KMemoryManager(KernelContext, CpuMemory);
}
@@ -1109,9 +1072,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
throw new UndefinedInstructionException(e.Address, e.OpCode);
}
- protected override void Destroy()
- {
- CpuMemory.Dispose();
- }
+ protected override void Destroy() => Context.Dispose();
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
index 2396aea8..e1cdb30f 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
@@ -2,6 +2,7 @@ using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using System;
namespace Ryujinx.HLE.HOS.Kernel.Process
{
@@ -24,29 +25,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
IrqAccessMask = new byte[0x80];
}
- public KernelResult InitializeForKernel(int[] caps, KMemoryManager memoryManager)
+ public KernelResult InitializeForKernel(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
{
AllowedCpuCoresMask = 0xf;
AllowedThreadPriosMask = -1;
DebuggingFlags &= ~3;
KernelReleaseVersion = KProcess.KernelVersionPacked;
- return Parse(caps, memoryManager);
+ return Parse(capabilities, memoryManager);
}
- public KernelResult InitializeForUser(int[] caps, KMemoryManager memoryManager)
+ public KernelResult InitializeForUser(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
{
- return Parse(caps, memoryManager);
+ return Parse(capabilities, memoryManager);
}
- private KernelResult Parse(int[] caps, KMemoryManager memoryManager)
+ private KernelResult Parse(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
{
int mask0 = 0;
int mask1 = 0;
- for (int index = 0; index < caps.Length; index++)
+ for (int index = 0; index < capabilities.Length; index++)
{
- int cap = caps[index];
+ int cap = capabilities[index];
if (((cap + 1) & ~cap) != 0x40)
{
@@ -59,14 +60,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
else
{
- if ((uint)index + 1 >= caps.Length)
+ if ((uint)index + 1 >= capabilities.Length)
{
return KernelResult.InvalidCombination;
}
int prevCap = cap;
- cap = caps[++index];
+ cap = capabilities[++index];
if (((cap + 1) & ~cap) != 0x40)
{
@@ -91,9 +92,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return KernelResult.InvalidAddress;
}
- MemoryPermission perm = (prevCap >> 31) != 0
- ? MemoryPermission.Read
- : MemoryPermission.ReadAndWrite;
+ KMemoryPermission perm = (prevCap >> 31) != 0
+ ? KMemoryPermission.Read
+ : KMemoryPermission.ReadAndWrite;
KernelResult result;
@@ -216,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
long address = ((long)(uint)cap << 4) & 0xffffff000;
- memoryManager.MapIoMemory(address, KMemoryManager.PageSize, MemoryPermission.ReadAndWrite);
+ memoryManager.MapIoMemory(address, KMemoryManager.PageSize, KMemoryPermission.ReadAndWrite);
break;
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
new file mode 100644
index 00000000..54997cb7
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
@@ -0,0 +1,25 @@
+using ARMeilleure.State;
+using Ryujinx.Memory;
+using System;
+
+namespace Ryujinx.HLE.HOS.Kernel.Process
+{
+ class ProcessContext : IProcessContext
+ {
+ public IVirtualMemoryManager AddressSpace { get; }
+
+ public ProcessContext(IVirtualMemoryManager asManager)
+ {
+ AddressSpace = asManager;
+ }
+
+ public void Execute(ExecutionContext context, ulong codeAddress)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
new file mode 100644
index 00000000..03db62fa
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
@@ -0,0 +1,13 @@
+using Ryujinx.Cpu;
+using Ryujinx.Memory;
+
+namespace Ryujinx.HLE.HOS.Kernel.Process
+{
+ class ProcessContextFactory : IProcessContextFactory
+ {
+ public IProcessContext Create(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler)
+ {
+ return new ProcessContext(new AddressSpaceManager(backingMemory, addressSpaceSize));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
new file mode 100644
index 00000000..a34481e5
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
@@ -0,0 +1,38 @@
+namespace Ryujinx.HLE.HOS.Kernel.Process
+{
+ enum ProcessCreationFlags
+ {
+ Is64Bit = 1 << 0,
+
+ AddressSpaceShift = 1,
+ AddressSpace32Bit = 0 << AddressSpaceShift,
+ AddressSpace64BitDeprecated = 1 << AddressSpaceShift,
+ AddressSpace32BitWithoutAlias = 2 << AddressSpaceShift,
+ AddressSpace64Bit = 3 << AddressSpaceShift,
+ AddressSpaceMask = 7 << AddressSpaceShift,
+
+ EnableDebug = 1 << 4,
+ EnableAslr = 1 << 5,
+ IsApplication = 1 << 6,
+ DeprecatedUseSecureMemory = 1 << 7,
+
+ PoolPartitionShift = 7,
+ PoolPartitionApplication = 0 << PoolPartitionShift,
+ PoolPartitionApplet = 1 << PoolPartitionShift,
+ PoolPartitionSystem = 2 << PoolPartitionShift,
+ PoolPartitionSystemNonSecure = 3 << PoolPartitionShift,
+ PoolPartitionMask = 0xf << PoolPartitionShift,
+
+ OptimizeMemoryAllocation = 1 << 11,
+
+ All =
+ Is64Bit |
+ AddressSpaceMask |
+ EnableDebug |
+ EnableAslr |
+ IsApplication |
+ DeprecatedUseSecureMemory |
+ PoolPartitionMask |
+ OptimizeMemoryAllocation
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs
index a5820865..26c23b3b 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs
@@ -2,36 +2,36 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
struct ProcessCreationInfo
{
- public string Name { get; private set; }
+ public string Name { get; }
- public int Version { get; private set; }
- public ulong TitleId { get; private set; }
+ public int Version { get; }
+ public ulong TitleId { get; }
- public ulong CodeAddress { get; private set; }
- public int CodePagesCount { get; private set; }
+ public ulong CodeAddress { get; }
+ public int CodePagesCount { get; }
- public int MmuFlags { get; private set; }
- public int ResourceLimitHandle { get; private set; }
- public int PersonalMmHeapPagesCount { get; private set; }
+ public ProcessCreationFlags Flags { get; }
+ public int ResourceLimitHandle { get; }
+ public int SystemResourcePagesCount { get; }
public ProcessCreationInfo(
string name,
- int category,
- ulong titleId,
- ulong codeAddress,
- int codePagesCount,
- int mmuFlags,
- int resourceLimitHandle,
- int personalMmHeapPagesCount)
+ int version,
+ ulong titleId,
+ ulong codeAddress,
+ int codePagesCount,
+ ProcessCreationFlags flags,
+ int resourceLimitHandle,
+ int systemResourcePagesCount)
{
- Name = name;
- Version = category;
- TitleId = titleId;
- CodeAddress = codeAddress;
- CodePagesCount = codePagesCount;
- MmuFlags = mmuFlags;
- ResourceLimitHandle = resourceLimitHandle;
- PersonalMmHeapPagesCount = personalMmHeapPagesCount;
+ Name = name;
+ Version = version;
+ TitleId = titleId;
+ CodeAddress = codeAddress;
+ CodePagesCount = codePagesCount;
+ Flags = flags;
+ ResourceLimitHandle = resourceLimitHandle;
+ SystemResourcePagesCount = systemResourcePagesCount;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
index c1e7026b..5e32ca58 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
@@ -7,124 +7,223 @@ using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Memory;
using System;
+using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
class Syscall
{
- private readonly Switch _device;
private readonly KernelContext _context;
- public Syscall(Switch device, KernelContext context)
+ public Syscall(KernelContext context)
{
- _device = device;
_context = context;
}
- // IPC
+ // Process
- public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
+ public KernelResult GetProcessId(int handle, out long pid)
+ {
+ KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
+
+ KProcess process = currentProcess.HandleTable.GetKProcess(handle);
+
+ if (process == null)
+ {
+ KThread thread = currentProcess.HandleTable.GetKThread(handle);
+
+ if (thread != null)
+ {
+ process = thread.Owner;
+ }
+
+ // TODO: KDebugEvent.
+ }
+
+ pid = process?.Pid ?? 0;
+
+ return process != null
+ ? KernelResult.Success
+ : KernelResult.InvalidHandle;
+ }
+
+ public KernelResult CreateProcess(
+ ProcessCreationInfo info,
+ ReadOnlySpan<int> capabilities,
+ out int handle,
+ IProcessContextFactory contextFactory,
+ ThreadStart customThreadStart = null)
{
handle = 0;
- if (!KernelTransfer.UserToKernelString(_context, namePtr, 12, out string name))
+ if ((info.Flags & ~ProcessCreationFlags.All) != 0)
{
- return KernelResult.UserCopyFailed;
+ return KernelResult.InvalidEnumValue;
}
- if (name.Length > 11)
+ // TODO: Address space check.
+
+ if ((info.Flags & ProcessCreationFlags.PoolPartitionMask) > ProcessCreationFlags.PoolPartitionSystemNonSecure)
{
- return KernelResult.MaximumExceeded;
+ return KernelResult.InvalidEnumValue;
}
- KAutoObject autoObj = KAutoObject.FindNamedObject(_context, name);
+ if ((info.CodeAddress & 0x1fffff) != 0)
+ {
+ return KernelResult.InvalidAddress;
+ }
- if (!(autoObj is KClientPort clientPort))
+ if (info.CodePagesCount < 0 || info.SystemResourcePagesCount < 0)
{
- return KernelResult.NotFound;
+ return KernelResult.InvalidSize;
}
- KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
+ if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) &&
+ !info.Flags.HasFlag(ProcessCreationFlags.IsApplication))
+ {
+ return KernelResult.InvalidThread;
+ }
- KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
+ KHandleTable handleTable = _context.Scheduler.GetCurrentProcess().HandleTable;
- if (result != KernelResult.Success)
+ KProcess process = new KProcess(_context);
+
+ using var _ = new OnScopeExit(process.DecrementReferenceCount);
+
+ KResourceLimit resourceLimit;
+
+ if (info.ResourceLimitHandle != 0)
{
- return result;
+ resourceLimit = handleTable.GetObject<KResourceLimit>(info.ResourceLimitHandle);
+
+ if (resourceLimit == null)
+ {
+ return KernelResult.InvalidHandle;
+ }
+ }
+ else
+ {
+ resourceLimit = _context.ResourceLimit;
}
- result = clientPort.Connect(out KClientSession clientSession);
+ MemoryRegion memRegion = (info.Flags & ProcessCreationFlags.PoolPartitionMask) switch
+ {
+ ProcessCreationFlags.PoolPartitionApplication => MemoryRegion.Application,
+ ProcessCreationFlags.PoolPartitionApplet => MemoryRegion.Applet,
+ ProcessCreationFlags.PoolPartitionSystem => MemoryRegion.Service,
+ ProcessCreationFlags.PoolPartitionSystemNonSecure => MemoryRegion.NvServices,
+ _ => MemoryRegion.NvServices
+ };
+
+ KernelResult result = process.Initialize(
+ info,
+ capabilities,
+ resourceLimit,
+ memRegion,
+ contextFactory,
+ customThreadStart);
if (result != KernelResult.Success)
{
- currentProcess.HandleTable.CancelHandleReservation(handle);
-
return result;
}
- currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession);
-
- clientSession.DecrementReferenceCount();
+ _context.Processes.TryAdd(process.Pid, process);
- return result;
+ return handleTable.GenerateHandle(process, out handle);
}
- public KernelResult SendSyncRequestHLE(int handle)
+ public KernelResult StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
{
- KProcess process = _context.Scheduler.GetCurrentProcess();
+ KProcess process = _context.Scheduler.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
- KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
+ if (process == null)
+ {
+ return KernelResult.InvalidHandle;
+ }
- if (clientSession == null || clientSession.Service == null)
+ if ((uint)cpuCore >= KScheduler.CpuCoresCount || !process.IsCpuCoreAllowed(cpuCore))
{
- return SendSyncRequest(handle);
+ return KernelResult.InvalidCpuCore;
+ }
+
+ if ((uint)priority >= KScheduler.PrioritiesCount || !process.IsPriorityAllowed(priority))
+ {
+ return KernelResult.InvalidPriority;
+ }
+
+ process.DefaultCpuCore = cpuCore;
+
+ KernelResult result = process.Start(priority, mainThreadStackSize);
+
+ if (result != KernelResult.Success)
+ {
+ return result;
}
- return SendSyncRequestWithUserBufferHLE((ulong)_context.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
+ process.IncrementReferenceCount();
+
+ return KernelResult.Success;
}
- public KernelResult SendSyncRequestWithUserBufferHLE(ulong messagePtr, ulong messageSize, int handle)
+ // IPC
+
+ public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
{
- KProcess process = _context.Scheduler.GetCurrentProcess();
+ handle = 0;
- byte[] messageData = new byte[messageSize];
+ if (!KernelTransfer.UserToKernelString(_context, namePtr, 12, out string name))
+ {
+ return KernelResult.UserCopyFailed;
+ }
- process.CpuMemory.Read(messagePtr, messageData);
+ return ConnectToNamedPort(name, out handle);
+ }
- KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
+ public KernelResult ConnectToNamedPort(string name, out int handle)
+ {
+ handle = 0;
- if (clientSession == null || clientSession.Service == null)
+ if (name.Length > 11)
{
- return SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
+ return KernelResult.MaximumExceeded;
}
- if (clientSession != null)
- {
- _context.CriticalSection.Enter();
+ KAutoObject autoObj = KAutoObject.FindNamedObject(_context, name);
- KThread currentThread = _context.Scheduler.GetCurrentThread();
+ if (!(autoObj is KClientPort clientPort))
+ {
+ return KernelResult.NotFound;
+ }
- currentThread.SignaledObj = null;
- currentThread.ObjSyncResult = KernelResult.Success;
+ KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
- currentThread.Reschedule(ThreadSchedState.Paused);
+ KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
- clientSession.Service.Server.PushMessage(_device, currentThread, clientSession, messagePtr, messageSize);
+ if (result != KernelResult.Success)
+ {
+ return result;
+ }
- _context.CriticalSection.Leave();
+ result = clientPort.Connect(out KClientSession clientSession);
- return currentThread.ObjSyncResult;
- }
- else
+ if (result != KernelResult.Success)
{
- Logger.Warning?.Print(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
+ currentProcess.HandleTable.CancelHandleReservation(handle);
- return KernelResult.InvalidHandle;
+ return result;
}
+
+ currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession);
+
+ clientSession.DecrementReferenceCount();
+
+ return result;
}
- private KernelResult SendSyncRequest(int handle)
+ public KernelResult SendSyncRequest(int handle)
{
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
@@ -407,9 +506,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.UserCopyFailed;
}
- KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount];
+ return ReplyAndReceive(handles, replyTargetHandle, timeout, out handleIndex);
+ }
- for (int index = 0; index < handlesCount; index++)
+ public KernelResult ReplyAndReceive(ReadOnlySpan<int> handles, int replyTargetHandle, long timeout, out int handleIndex)
+ {
+ handleIndex = 0;
+
+ KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
+
+ KSynchronizationObject[] syncObjs = new KSynchronizationObject[handles.Length];
+
+ for (int index = 0; index < handles.Length; index++)
{
KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
@@ -601,7 +709,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.UserCopyFailed;
}
- if (maxSessions < 0 || name.Length > 11)
+ if (name.Length > 11)
+ {
+ return KernelResult.MaximumExceeded;
+ }
+
+ return ManageNamedPort(name, maxSessions, out handle);
+ }
+
+ public KernelResult ManageNamedPort(string name, int maxSessions, out int handle)
+ {
+ handle = 0;
+
+ if (maxSessions < 0)
{
return KernelResult.MaximumExceeded;
}
@@ -826,7 +946,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
- public KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission)
+ public KernelResult MapSharedMemory(int handle, ulong address, ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
{
@@ -843,7 +963,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidMemState;
}
- if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
+ if ((permission | KMemoryPermission.Write) != KMemoryPermission.ReadAndWrite)
{
return KernelResult.InvalidPermission;
}
@@ -912,7 +1032,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
currentProcess);
}
- public KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle)
+ public KernelResult CreateTransferMemory(ulong address, ulong size, KMemoryPermission permission, out int handle)
{
handle = 0;
@@ -931,7 +1051,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidMemState;
}
- if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
+ if (permission > KMemoryPermission.ReadAndWrite || permission == KMemoryPermission.Write)
{
return KernelResult.InvalidPermission;
}
@@ -1119,7 +1239,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
}
- public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, MemoryPermission permission)
+ public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, KMemoryPermission permission)
{
if (!PageAligned(src))
{
@@ -1131,10 +1251,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidSize;
}
- if (permission != MemoryPermission.None &&
- permission != MemoryPermission.Read &&
- permission != MemoryPermission.ReadAndWrite &&
- permission != MemoryPermission.ReadAndExecute)
+ if (permission != KMemoryPermission.None &&
+ permission != KMemoryPermission.Read &&
+ permission != KMemoryPermission.ReadAndWrite &&
+ permission != KMemoryPermission.ReadAndExecute)
{
return KernelResult.InvalidPermission;
}
@@ -1282,31 +1402,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return _context.Scheduler.GetCurrentThread().Context.CntpctEl0;
}
- public KernelResult GetProcessId(int handle, out long pid)
- {
- KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
-
- KProcess process = currentProcess.HandleTable.GetKProcess(handle);
-
- if (process == null)
- {
- KThread thread = currentProcess.HandleTable.GetKThread(handle);
-
- if (thread != null)
- {
- process = thread.Owner;
- }
-
- // TODO: KDebugEvent.
- }
-
- pid = process?.Pid ?? 0;
-
- return process != null
- ? KernelResult.Success
- : KernelResult.InvalidHandle;
- }
-
public void Break(ulong reason)
{
KThread currentThread = _context.Scheduler.GetCurrentThread();
@@ -1997,7 +2092,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidThread;
}
- MemoryManager memory = currentProcess.CpuMemory;
+ IVirtualMemoryManager memory = currentProcess.CpuMemory;
memory.Write(address + 0x0, thread.Context.GetX(0));
memory.Write(address + 0x8, thread.Context.GetX(1));
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs
index 224af6d8..b57175a3 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs
@@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
public KernelResult SendSyncRequest32([R(0)] int handle)
{
- return _syscall.SendSyncRequestHLE(handle);
+ return _syscall.SendSyncRequest(handle);
}
public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint messageSize, [R(2)] int handle)
{
- return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle);
+ return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
}
public KernelResult CreateSession32(
@@ -116,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
- public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] MemoryPermission permission)
+ public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] KMemoryPermission permission)
{
return _syscall.MapSharedMemory(handle, address, size, permission);
}
@@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
public KernelResult CreateTransferMemory32(
[R(1)] uint address,
[R(2)] uint size,
- [R(3)] MemoryPermission permission,
+ [R(3)] KMemoryPermission permission,
[R(1)] out int handle)
{
return _syscall.CreateTransferMemory(address, size, permission, out handle);
@@ -169,7 +169,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
[R(2)] uint srcLow,
[R(3)] uint srcHigh,
[R(4)] uint sizeHigh,
- [R(5)] MemoryPermission permission)
+ [R(5)] KMemoryPermission permission)
{
ulong src = srcLow | ((ulong)srcHigh << 32);
ulong size = sizeLow | ((ulong)sizeHigh << 32);
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs
index 47f78a25..07ca4aae 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs
@@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
public KernelResult SendSyncRequest64([R(0)] int handle)
{
- return _syscall.SendSyncRequestHLE(handle);
+ return _syscall.SendSyncRequest(handle);
}
public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong messageSize, [R(2)] int handle)
{
- return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle);
+ return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
}
public KernelResult SendAsyncRequestWithUserBuffer64(
@@ -133,7 +133,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return _syscall.QueryMemory(infoPtr, position, out pageInfo);
}
- public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] MemoryPermission permission)
+ public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
{
return _syscall.MapSharedMemory(handle, address, size, permission);
}
@@ -146,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
public KernelResult CreateTransferMemory64(
[R(1)] ulong address,
[R(2)] ulong size,
- [R(3)] MemoryPermission permission,
+ [R(3)] KMemoryPermission permission,
[R(1)] out int handle)
{
return _syscall.CreateTransferMemory(address, size, permission, out handle);
@@ -172,7 +172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return _syscall.UnmapProcessCodeMemory(handle, dst, src, size);
}
- public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] MemoryPermission permission)
+ public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
{
return _syscall.SetProcessMemoryPermission(handle, src, size, permission);
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs
index 84995513..c6da361d 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs
@@ -229,6 +229,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KProcess dummyProcess = new KProcess(_context);
+ dummyProcess.HandleTable.Initialize(1024);
+
KThread dummyThread = new KThread(_context);
dummyThread.Initialize(0, 0, 0, 44, 0, dummyProcess, ThreadType.Dummy);
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
index 27ff3883..f523cb9c 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
@@ -31,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public ulong CondVarAddress { get; set; }
private ulong _entrypoint;
+ private ThreadStart _customThreadStart;
public ulong MutexAddress { get; set; }
@@ -48,12 +49,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
- public LinkedList<KThread> Withholder { get; set; }
+ public LinkedList<KThread> Withholder { get; set; }
public LinkedListNode<KThread> WithholderNode { get; set; }
public LinkedListNode<KThread> ProcessListNode { get; set; }
- private LinkedList<KThread> _mutexWaiters;
+ private LinkedList<KThread> _mutexWaiters;
private LinkedListNode<KThread> _mutexWaiterNode;
public KThread MutexOwner { get; private set; }
@@ -65,24 +66,28 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public KernelResult ObjSyncResult { get; set; }
public int DynamicPriority { get; set; }
- public int CurrentCore { get; set; }
- public int BasePriority { get; set; }
- public int PreferredCore { get; set; }
+ public int CurrentCore { get; set; }
+ public int BasePriority { get; set; }
+ public int PreferredCore { get; set; }
private long _affinityMaskOverride;
- private int _preferredCoreOverride;
+ private int _preferredCoreOverride;
#pragma warning disable CS0649
- private int _affinityOverrideCount;
+ private int _affinityOverrideCount;
#pragma warning restore CS0649
public ThreadSchedState SchedFlags { get; private set; }
private int _shallBeTerminated;
- public bool ShallBeTerminated { get => _shallBeTerminated != 0; set => _shallBeTerminated = value ? 1 : 0; }
+ public bool ShallBeTerminated
+ {
+ get => _shallBeTerminated != 0;
+ set => _shallBeTerminated = value ? 1 : 0;
+ }
public bool SyncCancelled { get; set; }
- public bool WaitingSync { get; set; }
+ public bool WaitingSync { get; set; }
private bool _hasExited;
private bool _hasBeenInitialized;
@@ -98,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public KThread(KernelContext context) : base(context)
{
- _scheduler = KernelContext.Scheduler;
+ _scheduler = KernelContext.Scheduler;
_schedulingData = KernelContext.Scheduler.SchedulingData;
WaitSyncObjects = new KSynchronizationObject[MaxWaitSyncObjects];
@@ -110,14 +115,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
}
public KernelResult Initialize(
- ulong entrypoint,
- ulong argsPtr,
- ulong stackTop,
- int priority,
- int defaultCpuCore,
- KProcess owner,
- ThreadType type = ThreadType.User,
- ThreadStart customHostThreadStart = null)
+ ulong entrypoint,
+ ulong argsPtr,
+ ulong stackTop,
+ int priority,
+ int defaultCpuCore,
+ KProcess owner,
+ ThreadType type,
+ ThreadStart customThreadStart = null)
{
if ((uint)type > 3)
{
@@ -135,11 +140,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
CurrentCore = PreferredCore;
DynamicPriority = priority;
- BasePriority = priority;
+ BasePriority = priority;
ObjSyncResult = KernelResult.ThreadNotStarted;
_entrypoint = entrypoint;
+ _customThreadStart = customThreadStart;
if (type == ThreadType.User)
{
@@ -162,18 +168,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
owner.IncrementReferenceCount();
owner.IncrementThreadCount();
- is64Bits = (owner.MmuFlags & 1) != 0;
+ is64Bits = owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
}
else
{
is64Bits = true;
}
- HostThread = new Thread(customHostThreadStart ?? (() => ThreadStart(entrypoint)));
+ HostThread = new Thread(ThreadStart);
Context = CpuContext.CreateExecutionContext();
- bool isAarch32 = (Owner.MmuFlags & 1) == 0;
+ bool isAarch32 = !Owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
Context.IsAarch32 = isAarch32;
@@ -189,7 +195,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
}
Context.CntfrqEl0 = 19200000;
- Context.Tpidr = (long)_tlsAddress;
+ Context.Tpidr = (long)_tlsAddress;
owner.SubscribeThreadEventHandlers(Context);
@@ -249,7 +255,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
KThread currentThread = KernelContext.Scheduler.GetCurrentThread();
- while (SchedFlags != ThreadSchedState.TerminationPending &&
+ while (SchedFlags != ThreadSchedState.TerminationPending &&
currentThread.SchedFlags != ThreadSchedState.TerminationPending &&
!currentThread.ShallBeTerminated)
{
@@ -351,7 +357,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
Context.RequestInterrupt();
}
- SignaledObj = null;
+ SignaledObj = null;
ObjSyncResult = KernelResult.ThreadTerminating;
ReleaseAndResume();
@@ -524,7 +530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
// If the candidate was scheduled after the current thread, then it's not worth it,
// unless the priority is higher than the current one.
if (nextThreadOnCurrentQueue.LastScheduledTime >= thread.LastScheduledTime ||
- nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
+ nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
{
yield return thread;
}
@@ -701,7 +707,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
}
else
{
- SignaledObj = null;
+ SignaledObj = null;
ObjSyncResult = KernelResult.Cancelled;
SetNewSchedFlags(ThreadSchedState.Running);
@@ -734,14 +740,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
if (useOverride)
{
_preferredCoreOverride = newCore;
- _affinityMaskOverride = newAffinityMask;
+ _affinityMaskOverride = newAffinityMask;
}
else
{
long oldAffinityMask = AffinityMask;
PreferredCore = newCore;
- AffinityMask = newAffinityMask;
+ AffinityMask = newAffinityMask;
if (oldAffinityMask != newAffinityMask)
{
@@ -783,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
private void CombineForcePauseFlags()
{
- ThreadSchedState oldFlags = SchedFlags;
+ ThreadSchedState oldFlags = SchedFlags;
ThreadSchedState lowNibble = SchedFlags & ThreadSchedState.LowMask;
SchedFlags = lowNibble | _forcePauseFlags;
@@ -1143,19 +1149,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
}
}
- private void ThreadStart(ulong entrypoint)
+ private void ThreadStart()
{
- Owner.CpuContext.Execute(Context, entrypoint);
+ KernelStatic.SetKernelContext(KernelContext);
- ThreadExit();
-
- Context.Dispose();
- }
+ if (_customThreadStart != null)
+ {
+ _customThreadStart();
+ }
+ else
+ {
+ Owner.Context.Execute(Context, _entrypoint);
+ }
- private void ThreadExit()
- {
KernelContext.Scheduler.ExitThread(this);
KernelContext.Scheduler.RemoveThread(this);
+
+ Context.Dispose();
}
public bool IsCurrentHostThread()
@@ -1203,9 +1213,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
// Wake up all threads that may be waiting for a mutex being held by this thread.
foreach (KThread thread in _mutexWaiters)
{
- thread.MutexOwner = null;
+ thread.MutexOwner = null;
thread._preferredCoreOverride = 0;
- thread.ObjSyncResult = KernelResult.InvalidState;
+ thread.ObjSyncResult = KernelResult.InvalidState;
thread.ReleaseAndResume();
}
diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs
index 58e37041..637c3efc 100644
--- a/Ryujinx.HLE/HOS/ProgramLoader.cs
+++ b/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);
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/ServiceCtx.cs b/Ryujinx.HLE/HOS/ServiceCtx.cs
index 533c1d67..36d4163e 100644
--- a/Ryujinx.HLE/HOS/ServiceCtx.cs
+++ b/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;
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs
index f131aff8..55539637 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
index 16ffe9ee..7d9d06e5 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
index 62319d47..e3b73c29 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs
index 5fafa154..580574a8 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs
+++ b/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);
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs
index decf5470..5b91e235 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs
+++ b/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));
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
index 8b1275ac..b2cc7160 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
+++ b/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)
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IWindowController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IWindowController.cs
index 5c5c9b88..8c127b98 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IWindowController.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs
index d29a8da4..d518dde4 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
index b9dfee30..6a5ad4c1 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs
index 700886fd..28a52573 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/IApplicationProxyService.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/IApplicationProxyService.cs
index 0aee24fe..8487d319 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/IApplicationProxyService.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs
index af9cccb2..86e5566a 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs
+++ b/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);
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs
index e12a9919..5aff3475 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs
+++ b/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)
{
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs
index effd8f15..a789dfed 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs
index 3081cd49..b3f7f5e0 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs
+++ b/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;
diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs
index 646acef4..91ec287c 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs
+++ b/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);
diff --git a/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs
index ed40cdad..c8cc281e 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs
index d56a6a43..54b1a58a 100644
--- a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs
+++ b/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);
diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
index 44f406a0..e29a040f 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
+++ b/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);
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs
index 2c3a6500..dfce2d73 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
index d3bf9319..dfcf2b25 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
+++ b/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;
diff --git a/Ryujinx.HLE/HOS/Services/IpcService.cs b/Ryujinx.HLE/HOS/Services/IpcService.cs
index 9d40d80f..f9858107 100644
--- a/Ryujinx.HLE/HOS/Services/IpcService.cs
+++ b/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;
+ }
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs
index bc55d1a1..2cd35b9e 100644
--- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs
+++ b/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);
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
index 2f6be8bf..51f9487f 100644
--- a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
+++ b/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.
diff --git a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs
index 8cfafb1a..e6fca499 100644
--- a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs
+++ b/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);
diff --git a/Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs b/Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs
index e9f27cb5..debcd57e 100644
--- a/Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs
+++ b/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)
{
diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs
index 0812683b..9f1ace36 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs
+++ b/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+
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvDeviceFile.cs
index af4734ea..34ff4ccb 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvDeviceFile.cs
+++ b/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)
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs
index 0000f495..6c49fd5c 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs
+++ b/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)
{
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs
index 863b01d1..d675ffc7 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs
+++ b/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;
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs
index 52389140..f27c065e 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs
+++ b/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!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlDeviceFile.cs
index a5384596..f0e5634e 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlDeviceFile.cs
+++ b/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!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs
index e0acf0df..840d95b9 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs
+++ b/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!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs
index 3cc47c42..a549c81c 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs
+++ b/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);
}
diff --git a/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs b/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
index 46374acc..c78634fa 100644
--- a/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs b/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs
index 001c38e2..5be54f00 100644
--- a/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/ServerBase.cs b/Ryujinx.HLE/HOS/Services/ServerBase.cs
index 211e0e6b..f70d930f 100644
--- a/Ryujinx.HLE/HOS/Services/ServerBase.cs
+++ b/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)
diff --git a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
index d8f31faf..69bb3708 100644
--- a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs
index 4ed62128..f7dd7e17 100644
--- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs
+++ b/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;
}
diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs
index 02a508b0..90f22dfb 100644
--- a/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs
+++ b/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);
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueue.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueue.cs
index 3dd21fde..2a9a6064 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueue.cs
+++ b/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;
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs
index 7f6f6c31..389a980b 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs
+++ b/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)
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs
index 6ef49538..03df04ad 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs
@@ -816,6 +816,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
Core.WaitDequeueEvent();
+
+ if (!Core.Active)
+ {
+ break;
+ }
}
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
index 8ee943df..b3c81381 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
+++ b/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>
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
index 4713e50b..4927b40e 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
+++ b/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)
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/GraphicBuffer.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/GraphicBuffer.cs
index 8d63d9cc..d86ff21e 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/GraphicBuffer.cs
+++ b/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);
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForGlue.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForGlue.cs
index 743b9e13..ecee7206 100644
--- a/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForGlue.cs
+++ b/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)]
diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs
index 64b21381..aeb0e8a8 100644
--- a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs
+++ b/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);
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs
index 22ffe656..ee99da77 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs
+++ b/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>
diff --git a/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs
index a90690ea..6157a16f 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs
+++ b/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>
diff --git a/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs
index 65b21613..9847a2da 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs
+++ b/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>
diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs
index 012a81ff..6b874722 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs
+++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs
@@ -1,11 +1,10 @@
using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Services.SurfaceFlinger;
namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
{
class IManagerDisplayService : IpcService
{
- private static IApplicationDisplayService _applicationDisplayService;
+ private IApplicationDisplayService _applicationDisplayService;
public IManagerDisplayService(IApplicationDisplayService applicationDisplayService)
{
@@ -16,10 +15,13 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
// CreateManagedLayer(u32, u64, nn::applet::AppletResourceUserId) -> u64
public ResultCode CreateManagedLayer(ServiceCtx context)
{
- long layerFlags = context.RequestData.ReadInt64();
- long displayId = context.RequestData.ReadInt64();
+ long layerFlags = context.RequestData.ReadInt64();
+ long displayId = context.RequestData.ReadInt64();
+ long appletResourceUserId = context.RequestData.ReadInt64();
- context.Device.System.SurfaceFlinger.CreateLayer(context.Process, out long layerId);
+ long pid = context.Device.System.AppletState.AppletResourceUserIds.GetData<long>((int)appletResourceUserId);
+
+ context.Device.System.SurfaceFlinger.CreateLayer(pid, out long layerId);
context.ResponseData.Write(layerId);
diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs
index 194bda2d..36f220c6 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs
+++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs
@@ -4,7 +4,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
{
class ISystemDisplayService : IpcService
{
- private static IApplicationDisplayService _applicationDisplayService;
+ private IApplicationDisplayService _applicationDisplayService;
public ISystemDisplayService(IApplicationDisplayService applicationDisplayService)
{
diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs
index bd00fc02..a4b9f358 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs
+++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs
@@ -11,7 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
{
class IApplicationDisplayService : IpcService
{
- private IdDictionary _displays;
+ private readonly IdDictionary _displays;
+
+ private int _vsyncEventHandle;
public IApplicationDisplayService()
{
@@ -121,7 +123,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
long userId = context.RequestData.ReadInt64();
long parcelPtr = context.Request.ReceiveBuff[0].Position;
- IBinder producer = context.Device.System.SurfaceFlinger.OpenLayer(context.Process, layerId);
+ IBinder producer = context.Device.System.SurfaceFlinger.OpenLayer(context.Request.HandleDesc.PId, layerId);
Parcel parcel = new Parcel(0x28, 0x4);
@@ -159,7 +161,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
// TODO: support multi display.
Display disp = _displays.GetData<Display>((int)displayId);
- IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(context.Process, out long layerId);
+ IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(0, out long layerId);
Parcel parcel = new Parcel(0x28, 0x4);
@@ -268,8 +270,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
const ulong defaultAlignment = 0x1000;
const ulong defaultSize = 0x20000;
- // NOTE: The official service setup a A8B8G8R8 texture with a linear layout and then query its size.
- // As we don't need this texture on the emulator, we can just simplify this logic and directly
+ // NOTE: The official service setup a A8B8G8R8 texture with a linear layout and then query its size.
+ // As we don't need this texture on the emulator, we can just simplify this logic and directly
// do a linear layout size calculation. (stride * height * bytePerPixel)
int pitch = BitUtils.AlignUp(BitUtils.DivRoundUp(width * 32, 8), 64);
int memorySize = pitch * BitUtils.AlignUp(height, 64);
@@ -289,12 +291,15 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
{
string name = GetDisplayName(context);
- if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ if (_vsyncEventHandle == 0)
{
- throw new InvalidOperationException("Out of handles!");
+ if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out _vsyncEventHandle) != KernelResult.Success)
+ {
+ throw new InvalidOperationException("Out of handles!");
+ }
}
- context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+ context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_vsyncEventHandle);
return ResultCode.Success;
}
diff --git a/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs
index 14348a12..b9229b33 100644
--- a/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs
+++ b/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs
@@ -10,13 +10,17 @@ namespace Ryujinx.HLE.HOS.SystemState
public FocusState FocusState { get; private set; }
- public KEvent MessageEvent { get; private set; }
+ public KEvent MessageEvent { get; }
+
+ public IdDictionary AppletResourceUserIds { get; }
public AppletStateMgr(Horizon system)
{
_messages = new ConcurrentQueue<MessageInfo>();
MessageEvent = new KEvent(system.KernelContext);
+
+ AppletResourceUserIds = new IdDictionary();
}
public void SetFocus(bool isFocused)
diff --git a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs
index 7f1e2935..29a2b0fc 100644
--- a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs
+++ b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs
@@ -11,7 +11,7 @@ namespace Ryujinx.HLE.Loaders.Npdm
{
private const int MetaMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24;
- public byte MmuFlags { get; private set; }
+ public byte ProcessFlags { get; private set; }
public bool Is64Bit { get; private set; }
public byte MainThreadPriority { get; private set; }
public byte DefaultCpuId { get; private set; }
@@ -35,9 +35,9 @@ namespace Ryujinx.HLE.Loaders.Npdm
reader.ReadInt64();
- MmuFlags = reader.ReadByte();
+ ProcessFlags = reader.ReadByte();
- Is64Bit = (MmuFlags & 1) != 0;
+ Is64Bit = (ProcessFlags & 1) != 0;
reader.ReadByte();
diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs
index 36ffc563..2c58898c 100644
--- a/Ryujinx.HLE/Switch.cs
+++ b/Ryujinx.HLE/Switch.cs
@@ -93,6 +93,7 @@ namespace Ryujinx.HLE
FileSystem = fileSystem;
System = new Horizon(this, contentManager);
+ System.InitializeServices();
Statistics = new PerformanceStatistics();
diff --git a/Ryujinx.HLE/Utilities/StructReader.cs b/Ryujinx.HLE/Utilities/StructReader.cs
index 0c45a8ee..3bde1c77 100644
--- a/Ryujinx.HLE/Utilities/StructReader.cs
+++ b/Ryujinx.HLE/Utilities/StructReader.cs
@@ -1,15 +1,16 @@
using Ryujinx.Cpu;
+using Ryujinx.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.Utilities
{
class StructReader
{
- private MemoryManager _memory;
+ private IVirtualMemoryManager _memory;
public long Position { get; private set; }
- public StructReader(MemoryManager memory, long position)
+ public StructReader(IVirtualMemoryManager memory, long position)
{
_memory = memory;
Position = position;
diff --git a/Ryujinx.HLE/Utilities/StructWriter.cs b/Ryujinx.HLE/Utilities/StructWriter.cs
index 46a07a60..6b1e0838 100644
--- a/Ryujinx.HLE/Utilities/StructWriter.cs
+++ b/Ryujinx.HLE/Utilities/StructWriter.cs
@@ -1,15 +1,16 @@
using Ryujinx.Cpu;
+using Ryujinx.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.Utilities
{
class StructWriter
{
- private MemoryManager _memory;
+ private IVirtualMemoryManager _memory;
public long Position { get; private set; }
- public StructWriter(MemoryManager memory, long position)
+ public StructWriter(IVirtualMemoryManager memory, long position)
{
_memory = memory;
Position = position;
diff --git a/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs b/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
index 037bedc8..c673bc80 100644
--- a/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
+++ b/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Memory.Tracking;
+using System;
namespace Ryujinx.Memory.Tests
{
@@ -10,19 +10,73 @@ namespace Ryujinx.Memory.Tests
{
}
+ public void Map(ulong va, ulong pa, ulong size)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Unmap(ulong va, ulong size)
+ {
+ throw new NotImplementedException();
+ }
+
+ public T Read<T>(ulong va) where T : unmanaged
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Read(ulong va, Span<byte> data)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Write<T>(ulong va, T value) where T : unmanaged
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Write(ulong va, ReadOnlySpan<byte> data)
+ {
+ throw new NotImplementedException();
+ }
+
+ public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
+ {
+ throw new NotImplementedException();
+ }
+
+ public WritableRegion GetWritableRegion(ulong va, int size)
+ {
+ throw new NotImplementedException();
+ }
+
+ public ref T GetRef<T>(ulong va) where T : unmanaged
+ {
+ throw new NotImplementedException();
+ }
+
public (ulong address, ulong size)[] GetPhysicalRegions(ulong va, ulong size)
{
return NoMappings ? new (ulong address, ulong size)[0] : new (ulong address, ulong size)[] { (va, size) };
}
+ public bool IsMapped(ulong va)
+ {
+ return true;
+ }
+
public bool IsRangeMapped(ulong va, ulong size)
{
return true;
}
+ public ulong GetPhysicalAddress(ulong va)
+ {
+ throw new NotImplementedException();
+ }
+
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection)
{
-
}
}
}
diff --git a/Ryujinx.Memory/AddressSpaceManager.cs b/Ryujinx.Memory/AddressSpaceManager.cs
new file mode 100644
index 00000000..c6d6cab5
--- /dev/null
+++ b/Ryujinx.Memory/AddressSpaceManager.cs
@@ -0,0 +1,549 @@
+using Ryujinx.Common;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Memory
+{
+ /// <summary>
+ /// Represents a address space manager.
+ /// Supports virtual memory region mapping, address translation and read/write access to mapped regions.
+ /// </summary>
+ public sealed class AddressSpaceManager : IVirtualMemoryManager
+ {
+ public const int PageBits = 12;
+ public const int PageSize = 1 << PageBits;
+ public const int PageMask = PageSize - 1;
+
+ private const int PtLevelBits = 9; // 9 * 4 + 12 = 48 (max address space size)
+ private const int PtLevelSize = 1 << PtLevelBits;
+ private const int PtLevelMask = PtLevelSize - 1;
+
+ private const ulong Unmapped = ulong.MaxValue;
+
+ /// <summary>
+ /// Address space width in bits.
+ /// </summary>
+ public int AddressSpaceBits { get; }
+
+ private readonly ulong _addressSpaceSize;
+
+ private readonly MemoryBlock _backingMemory;
+
+ private readonly ulong[][][][] _pageTable;
+
+ /// <summary>
+ /// Creates a new instance of the memory manager.
+ /// </summary>
+ /// <param name="backingMemory">Physical backing memory where virtual memory will be mapped to</param>
+ /// <param name="addressSpaceSize">Size of the address space</param>
+ public AddressSpaceManager(MemoryBlock backingMemory, ulong addressSpaceSize)
+ {
+ ulong asSize = PageSize;
+ int asBits = PageBits;
+
+ while (asSize < addressSpaceSize)
+ {
+ asSize <<= 1;
+ asBits++;
+ }
+
+ AddressSpaceBits = asBits;
+ _addressSpaceSize = asSize;
+ _backingMemory = backingMemory;
+ _pageTable = new ulong[PtLevelSize][][][];
+ }
+
+ /// <summary>
+ /// Maps a virtual memory range into a physical memory range.
+ /// </summary>
+ /// <remarks>
+ /// Addresses and size must be page aligned.
+ /// </remarks>
+ /// <param name="va">Virtual memory address</param>
+ /// <param name="pa">Physical memory address</param>
+ /// <param name="size">Size to be mapped</param>
+ public void Map(ulong va, ulong pa, ulong size)
+ {
+ while (size != 0)
+ {
+ PtMap(va, pa);
+
+ va += PageSize;
+ pa += PageSize;
+ size -= PageSize;
+ }
+ }
+
+ /// <summary>
+ /// Unmaps a previously mapped range of virtual memory.
+ /// </summary>
+ /// <param name="va">Virtual address of the range to be unmapped</param>
+ /// <param name="size">Size of the range to be unmapped</param>
+ public void Unmap(ulong va, ulong size)
+ {
+ while (size != 0)
+ {
+ PtUnmap(va);
+
+ va += PageSize;
+ size -= PageSize;
+ }
+ }
+
+ /// <summary>
+ /// Reads data from mapped memory.
+ /// </summary>
+ /// <typeparam name="T">Type of the data being read</typeparam>
+ /// <param name="va">Virtual address of the data in memory</param>
+ /// <returns>The data</returns>
+ /// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
+ public T Read<T>(ulong va) where T : unmanaged
+ {
+ return MemoryMarshal.Cast<byte, T>(GetSpan(va, Unsafe.SizeOf<T>()))[0];
+ }
+
+ /// <summary>
+ /// Reads data from mapped memory.
+ /// </summary>
+ /// <param name="va">Virtual address of the data in memory</param>
+ /// <param name="data">Span to store the data being read into</param>
+ /// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
+ public void Read(ulong va, Span<byte> data)
+ {
+ ReadImpl(va, data);
+ }
+
+ /// <summary>
+ /// Writes data to mapped memory.
+ /// </summary>
+ /// <typeparam name="T">Type of the data being written</typeparam>
+ /// <param name="va">Virtual address to write the data into</param>
+ /// <param name="value">Data to be written</param>
+ /// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
+ public void Write<T>(ulong va, T value) where T : unmanaged
+ {
+ Write(va, MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateSpan(ref value, 1)));
+ }
+
+ /// <summary>
+ /// Writes data to mapped memory.
+ /// </summary>
+ /// <param name="va">Virtual address to write the data into</param>
+ /// <param name="data">Data to be written</param>
+ /// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
+ public void Write(ulong va, ReadOnlySpan<byte> data)
+ {
+ if (data.Length == 0)
+ {
+ return;
+ }
+
+ if (IsContiguousAndMapped(va, data.Length))
+ {
+ data.CopyTo(_backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length));
+ }
+ else
+ {
+ int offset = 0, size;
+
+ if ((va & PageMask) != 0)
+ {
+ ulong pa = GetPhysicalAddressInternal(va);
+
+ size = Math.Min(data.Length, PageSize - (int)(va & PageMask));
+
+ data.Slice(0, size).CopyTo(_backingMemory.GetSpan(pa, size));
+
+ offset += size;
+ }
+
+ for (; offset < data.Length; offset += size)
+ {
+ ulong pa = GetPhysicalAddressInternal(va + (ulong)offset);
+
+ size = Math.Min(data.Length - offset, PageSize);
+
+ data.Slice(offset, size).CopyTo(_backingMemory.GetSpan(pa, size));
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets a read-only span of data from mapped memory.
+ /// </summary>
+ /// <remarks>
+ /// This may perform a allocation if the data is not contiguous in memory.
+ /// For this reason, the span is read-only, you can't modify the data.
+ /// </remarks>
+ /// <param name="va">Virtual address of the data</param>
+ /// <param name="size">Size of the data</param>
+ /// <param name="tracked">True if read tracking is triggered on the span</param>
+ /// <returns>A read-only span of the data</returns>
+ /// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
+ public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
+ {
+ if (size == 0)
+ {
+ return ReadOnlySpan<byte>.Empty;
+ }
+
+ if (IsContiguousAndMapped(va, size))
+ {
+ return _backingMemory.GetSpan(GetPhysicalAddressInternal(va), size);
+ }
+ else
+ {
+ Span<byte> data = new byte[size];
+
+ ReadImpl(va, data);
+
+ return data;
+ }
+ }
+
+ /// <summary>
+ /// Gets a region of memory that can be written to.
+ /// </summary>
+ /// <remarks>
+ /// If the requested region is not contiguous in physical memory,
+ /// this will perform an allocation, and flush the data (writing it
+ /// back to the backing memory) on disposal.
+ /// </remarks>
+ /// <param name="va">Virtual address of the data</param>
+ /// <param name="size">Size of the data</param>
+ /// <returns>A writable region of memory containing the data</returns>
+ /// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
+ public WritableRegion GetWritableRegion(ulong va, int size)
+ {
+ if (size == 0)
+ {
+ return new WritableRegion(null, va, Memory<byte>.Empty);
+ }
+
+ if (IsContiguousAndMapped(va, size))
+ {
+ return new WritableRegion(null, va, _backingMemory.GetMemory(GetPhysicalAddressInternal(va), size));
+ }
+ else
+ {
+ Memory<byte> memory = new byte[size];
+
+ GetSpan(va, size).CopyTo(memory.Span);
+
+ return new WritableRegion(this, va, memory);
+ }
+ }
+
+ /// <summary>
+ /// Gets a reference for the given type at the specified virtual memory address.
+ /// </summary>
+ /// <remarks>
+ /// The data must be located at a contiguous memory region.
+ /// </remarks>
+ /// <typeparam name="T">Type of the data to get the reference</typeparam>
+ /// <param name="va">Virtual address of the data</param>
+ /// <returns>A reference to the data in memory</returns>
+ /// <exception cref="MemoryNotContiguousException">Throw if the specified memory region is not contiguous in physical memory</exception>
+ public ref T GetRef<T>(ulong va) where T : unmanaged
+ {
+ if (!IsContiguous(va, Unsafe.SizeOf<T>()))
+ {
+ ThrowMemoryNotContiguous();
+ }
+
+ return ref _backingMemory.GetRef<T>(GetPhysicalAddressInternal(va));
+ }
+
+ private void ThrowMemoryNotContiguous() => throw new MemoryNotContiguousException();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private bool IsContiguousAndMapped(ulong va, int size) => IsContiguous(va, size) && IsMapped(va);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private bool IsContiguous(ulong va, int size)
+ {
+ if (!ValidateAddress(va))
+ {
+ return false;
+ }
+
+ ulong endVa = (va + (ulong)size + PageMask) & ~(ulong)PageMask;
+
+ va &= ~(ulong)PageMask;
+
+ int pages = (int)((endVa - va) / PageSize);
+
+ for (int page = 0; page < pages - 1; page++)
+ {
+ if (!ValidateAddress(va + PageSize))
+ {
+ return false;
+ }
+
+ if (GetPhysicalAddressInternal(va) + PageSize != GetPhysicalAddressInternal(va + PageSize))
+ {
+ return false;
+ }
+
+ va += PageSize;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Gets the physical regions that make up the given virtual address region.
+ /// If any part of the virtual region is unmapped, null is returned.
+ /// </summary>
+ /// <param name="va">Virtual address of the range</param>
+ /// <param name="size">Size of the range</param>
+ /// <returns>Array of physical regions</returns>
+ public (ulong address, ulong size)[] GetPhysicalRegions(ulong va, ulong size)
+ {
+ throw new NotImplementedException();
+ }
+
+ private void ReadImpl(ulong va, Span<byte> data)
+ {
+ if (data.Length == 0)
+ {
+ return;
+ }
+
+ int offset = 0, size;
+
+ if ((va & PageMask) != 0)
+ {
+ ulong pa = GetPhysicalAddressInternal(va);
+
+ size = Math.Min(data.Length, PageSize - (int)(va & PageMask));
+
+ _backingMemory.GetSpan(pa, size).CopyTo(data.Slice(0, size));
+
+ offset += size;
+ }
+
+ for (; offset < data.Length; offset += size)
+ {
+ ulong pa = GetPhysicalAddressInternal(va + (ulong)offset);
+
+ size = Math.Min(data.Length - offset, PageSize);
+
+ _backingMemory.GetSpan(pa, size).CopyTo(data.Slice(offset, size));
+ }
+ }
+
+ /// <summary>
+ /// Checks if the page at a given virtual address is mapped.
+ /// </summary>
+ /// <param name="va">Virtual address to check</param>
+ /// <returns>True if the address is mapped, false otherwise</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IsMapped(ulong va)
+ {
+ if (!ValidateAddress(va))
+ {
+ return false;
+ }
+
+ return PtRead(va) != Unmapped;
+ }
+
+ /// <summary>
+ /// Checks if a memory range is mapped.
+ /// </summary>
+ /// <param name="va">Virtual address of the range</param>
+ /// <param name="size">Size of the range in bytes</param>
+ /// <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;
+
+ while (va < endVa)
+ {
+ if (!IsMapped(va))
+ {
+ return false;
+ }
+
+ va += PageSize;
+ }
+
+ return true;
+ }
+
+ private bool ValidateAddress(ulong va)
+ {
+ return va < _addressSpaceSize;
+ }
+
+ /// <summary>
+ /// Performs address translation of the address inside a mapped memory range.
+ /// </summary>
+ /// <remarks>
+ /// If the address is invalid or unmapped, -1 will be returned.
+ /// </remarks>
+ /// <param name="va">Virtual address to be translated</param>
+ /// <returns>The physical address</returns>
+ public ulong GetPhysicalAddress(ulong va)
+ {
+ // We return -1L if the virtual address is invalid or unmapped.
+ if (!ValidateAddress(va) || !IsMapped(va))
+ {
+ return ulong.MaxValue;
+ }
+
+ return GetPhysicalAddressInternal(va);
+ }
+
+ private ulong GetPhysicalAddressInternal(ulong va)
+ {
+ return PtRead(va) + (va & PageMask);
+ }
+
+ /// <summary>
+ /// Reprotect a region of virtual memory for tracking. Sets software protection bits.
+ /// </summary>
+ /// <param name="va">Virtual address base</param>
+ /// <param name="size">Size of the region to protect</param>
+ /// <param name="protection">Memory protection to set</param>
+ public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection)
+ {
+ throw new NotImplementedException();
+ }
+
+ private ulong PtRead(ulong va)
+ {
+ int l3 = (int)(va >> PageBits) & PtLevelMask;
+ int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
+ int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
+ int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
+
+ if (_pageTable[l0] == null)
+ {
+ return Unmapped;
+ }
+
+ if (_pageTable[l0][l1] == null)
+ {
+ return Unmapped;
+ }
+
+ if (_pageTable[l0][l1][l2] == null)
+ {
+ return Unmapped;
+ }
+
+ return _pageTable[l0][l1][l2][l3];
+ }
+
+ private void PtMap(ulong va, ulong value)
+ {
+ int l3 = (int)(va >> PageBits) & PtLevelMask;
+ int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
+ int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
+ int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
+
+ if (_pageTable[l0] == null)
+ {
+ _pageTable[l0] = new ulong[PtLevelSize][][];
+ }
+
+ if (_pageTable[l0][l1] == null)
+ {
+ _pageTable[l0][l1] = new ulong[PtLevelSize][];
+ }
+
+ if (_pageTable[l0][l1][l2] == null)
+ {
+ _pageTable[l0][l1][l2] = new ulong[PtLevelSize];
+
+ for (int i = 0; i < _pageTable[l0][l1][l2].Length; i++)
+ {
+ _pageTable[l0][l1][l2][i] = Unmapped;
+ }
+ }
+
+ _pageTable[l0][l1][l2][l3] = value;
+ }
+
+ private void PtUnmap(ulong va)
+ {
+ int l3 = (int)(va >> PageBits) & PtLevelMask;
+ int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
+ int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
+ int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
+
+ if (_pageTable[l0] == null)
+ {
+ return;
+ }
+
+ if (_pageTable[l0][l1] == null)
+ {
+ return;
+ }
+
+ if (_pageTable[l0][l1][l2] == null)
+ {
+ return;
+ }
+
+ _pageTable[l0][l1][l2][l3] = Unmapped;
+
+ bool empty = true;
+
+ for (int i = 0; i < _pageTable[l0][l1][l2].Length; i++)
+ {
+ empty &= (_pageTable[l0][l1][l2][i] == Unmapped);
+ }
+
+ if (empty)
+ {
+ _pageTable[l0][l1][l2] = null;
+
+ RemoveIfAllNull(l0, l1);
+ }
+ }
+
+ private void RemoveIfAllNull(int l0, int l1)
+ {
+ bool empty = true;
+
+ for (int i = 0; i < _pageTable[l0][l1].Length; i++)
+ {
+ empty &= (_pageTable[l0][l1][i] == null);
+ }
+
+ if (empty)
+ {
+ _pageTable[l0][l1] = null;
+
+ RemoveIfAllNull(l0);
+ }
+ }
+
+ private void RemoveIfAllNull(int l0)
+ {
+ bool empty = true;
+
+ for (int i = 0; i < _pageTable[l0].Length; i++)
+ {
+ empty &= (_pageTable[l0][i] == null);
+ }
+
+ if (empty)
+ {
+ _pageTable[l0] = null;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Memory/IVirtualMemoryManager.cs b/Ryujinx.Memory/IVirtualMemoryManager.cs
new file mode 100644
index 00000000..8c2296e2
--- /dev/null
+++ b/Ryujinx.Memory/IVirtualMemoryManager.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Ryujinx.Memory
+{
+ public interface IVirtualMemoryManager
+ {
+ void Map(ulong va, ulong pa, ulong size);
+ void Unmap(ulong va, ulong size);
+
+ T Read<T>(ulong va) where T : unmanaged;
+ void Read(ulong va, Span<byte> data);
+
+ void Write<T>(ulong va, T value) where T : unmanaged;
+ void Write(ulong va, ReadOnlySpan<byte> data);
+
+ ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false);
+ WritableRegion GetWritableRegion(ulong va, int size);
+ ref T GetRef<T>(ulong va) where T : unmanaged;
+
+ (ulong address, ulong size)[] GetPhysicalRegions(ulong va, ulong size);
+
+ bool IsMapped(ulong va);
+ bool IsRangeMapped(ulong va, ulong size);
+ ulong GetPhysicalAddress(ulong va);
+
+ void TrackingReprotect(ulong va, ulong size, MemoryPermission protection);
+ }
+}
diff --git a/Ryujinx.Cpu/MemoryNotContiguousException.cs b/Ryujinx.Memory/MemoryNotContiguousException.cs
index d7c827cc..3106955b 100644
--- a/Ryujinx.Cpu/MemoryNotContiguousException.cs
+++ b/Ryujinx.Memory/MemoryNotContiguousException.cs
@@ -1,8 +1,8 @@
using System;
-namespace Ryujinx.Cpu
+namespace Ryujinx.Memory
{
- class MemoryNotContiguousException : Exception
+ public class MemoryNotContiguousException : Exception
{
public MemoryNotContiguousException() : base("The specified memory region is not contiguous.")
{
diff --git a/Ryujinx.Memory/Tracking/IVirtualMemoryManager.cs b/Ryujinx.Memory/Tracking/IVirtualMemoryManager.cs
deleted file mode 100644
index e6d8e8c9..00000000
--- a/Ryujinx.Memory/Tracking/IVirtualMemoryManager.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Ryujinx.Memory.Tracking
-{
- public interface IVirtualMemoryManager
- {
- (ulong address, ulong size)[] GetPhysicalRegions(ulong va, ulong size);
-
- bool IsRangeMapped(ulong va, ulong size);
- void TrackingReprotect(ulong va, ulong size, MemoryPermission protection);
- }
-}
diff --git a/Ryujinx.Cpu/WritableRegion.cs b/Ryujinx.Memory/WritableRegion.cs
index 5ea0a2d8..e8ea310f 100644
--- a/Ryujinx.Cpu/WritableRegion.cs
+++ b/Ryujinx.Memory/WritableRegion.cs
@@ -1,17 +1,17 @@
using System;
-namespace Ryujinx.Cpu
+namespace Ryujinx.Memory
{
public sealed class WritableRegion : IDisposable
{
- private readonly MemoryManager _mm;
+ private readonly IVirtualMemoryManager _mm;
private readonly ulong _va;
private bool NeedsWriteback => _mm != null;
public Memory<byte> Memory { get; }
- internal WritableRegion(MemoryManager mm, ulong va, Memory<byte> memory)
+ public WritableRegion(IVirtualMemoryManager mm, ulong va, Memory<byte> memory)
{
_mm = mm;
_va = va;
diff --git a/Ryujinx/Ui/GLRenderer.cs b/Ryujinx/Ui/GLRenderer.cs
index 10525a4b..c8887544 100644
--- a/Ryujinx/Ui/GLRenderer.cs
+++ b/Ryujinx/Ui/GLRenderer.cs
@@ -33,9 +33,9 @@ namespace Ryujinx.Ui
public static event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
- public bool IsActive { get; set; }
- public bool IsStopped { get; set; }
- public bool IsFocused { get; set; }
+ private bool _isActive;
+ private bool _isStopped;
+ private bool _isFocused;
private double _mouseX;
private double _mouseY;
@@ -48,9 +48,9 @@ namespace Ryujinx.Ui
private long _ticks = 0;
- private System.Diagnostics.Stopwatch _chrono;
+ private readonly System.Diagnostics.Stopwatch _chrono;
- private Switch _device;
+ private readonly Switch _device;
private Renderer _renderer;
@@ -60,11 +60,13 @@ namespace Ryujinx.Ui
private GraphicsDebugLevel _glLogLevel;
+ private readonly ManualResetEvent _exitEvent;
+
public GlRenderer(Switch device, GraphicsDebugLevel glLogLevel)
: base (GetGraphicsMode(),
3, 3,
- glLogLevel == GraphicsDebugLevel.None
- ? GraphicsContextFlags.ForwardCompatible
+ glLogLevel == GraphicsDebugLevel.None
+ ? GraphicsContextFlags.ForwardCompatible
: GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug)
{
WaitEvent = new ManualResetEvent(false);
@@ -92,6 +94,8 @@ namespace Ryujinx.Ui
_dsuClient = new Client();
_glLogLevel = glLogLevel;
+
+ _exitEvent = new ManualResetEvent(false);
}
private static GraphicsMode GetGraphicsMode()
@@ -107,12 +111,12 @@ namespace Ryujinx.Ui
private void Parent_FocusOutEvent(object o, Gtk.FocusOutEventArgs args)
{
- IsFocused = false;
+ _isFocused = false;
}
private void Parent_FocusInEvent(object o, Gtk.FocusInEventArgs args)
{
- IsFocused = true;
+ _isFocused = true;
}
private void GLRenderer_Destroyed(object sender, EventArgs e)
@@ -123,7 +127,7 @@ namespace Ryujinx.Ui
protected void Renderer_Shown(object sender, EventArgs e)
{
- IsFocused = this.ParentWindow.State.HasFlag(Gdk.WindowState.Focused);
+ _isFocused = this.ParentWindow.State.HasFlag(Gdk.WindowState.Focused);
}
public void HandleScreenState(KeyboardState keyboard)
@@ -204,7 +208,7 @@ namespace Ryujinx.Ui
_chrono.Restart();
- IsActive = true;
+ _isActive = true;
Gtk.Window parent = this.Toplevel as Gtk.Window;
@@ -316,13 +320,17 @@ namespace Ryujinx.Ui
public void Exit()
{
_dsuClient?.Dispose();
- if (IsStopped)
+
+ if (_isStopped)
{
return;
}
- IsStopped = true;
- IsActive = false;
+ _isStopped = true;
+ _isActive = false;
+
+ _exitEvent.WaitOne();
+ _exitEvent.Dispose();
}
public void Initialize()
@@ -353,9 +361,9 @@ namespace Ryujinx.Ui
_device.Gpu.InitializeShaderCache();
Translator.IsReadyForTranslation.Set();
- while (IsActive)
+ while (_isActive)
{
- if (IsStopped)
+ if (_isStopped)
{
return;
}
@@ -401,28 +409,30 @@ namespace Ryujinx.Ui
public void MainLoop()
{
- while (IsActive)
+ while (_isActive)
{
UpdateFrame();
// Polling becomes expensive if it's not slept
Thread.Sleep(1);
}
+
+ _exitEvent.Set();
}
private bool UpdateFrame()
{
- if (!IsActive)
+ if (!_isActive)
{
return true;
}
- if (IsStopped)
+ if (_isStopped)
{
return false;
}
- if (IsFocused)
+ if (_isFocused)
{
Gtk.Application.Invoke(delegate
{
@@ -444,7 +454,7 @@ namespace Ryujinx.Ui
List<SixAxisInput> motionInputs = new List<SixAxisInput>(NpadDevices.MaxControllers);
MotionDevice motionDevice = new MotionDevice(_dsuClient);
-
+
foreach (InputConfig inputConfig in ConfigurationState.Instance.Hid.InputConfig.Value)
{
ControllerKeys currentButton = 0;
@@ -464,7 +474,7 @@ namespace Ryujinx.Ui
if (inputConfig is KeyboardConfig keyboardConfig)
{
- if (IsFocused)
+ if (_isFocused)
{
// Keyboard Input
KeyboardController keyboardController = new KeyboardController(keyboardConfig);
@@ -571,11 +581,11 @@ namespace Ryujinx.Ui
motionInputs.Add(sixAxisInput);
}
}
-
+
_device.Hid.Npads.Update(gamepadInputs);
_device.Hid.Npads.UpdateSixAxis(motionInputs);
- if(IsFocused)
+ if(_isFocused)
{
// Hotkeys
HotkeyButtons currentHotkeyButtons = KeyboardController.GetHotkeyButtons(OpenTK.Input.Keyboard.GetState());
@@ -594,7 +604,7 @@ namespace Ryujinx.Ui
// Get screen touch position from left mouse click
// OpenTK always captures mouse events, even if out of focus, so check if window is focused.
- if (IsFocused && _mousePressed)
+ if (_isFocused && _mousePressed)
{
int screenWidth = AllocatedWidth;
int screenHeight = AllocatedHeight;