aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Horizon/Arp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Horizon/Arp')
-rw-r--r--src/Ryujinx.Horizon/Arp/ArpIpcServer.cs61
-rw-r--r--src/Ryujinx.Horizon/Arp/ArpMain.cs20
-rw-r--r--src/Ryujinx.Horizon/Arp/Ipc/Reader.cs135
-rw-r--r--src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs52
-rw-r--r--src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs25
-rw-r--r--src/Ryujinx.Horizon/Arp/Ipc/Updater.cs74
-rw-r--r--src/Ryujinx.Horizon/Arp/Ipc/Writer.cs75
7 files changed, 442 insertions, 0 deletions
diff --git a/src/Ryujinx.Horizon/Arp/ArpIpcServer.cs b/src/Ryujinx.Horizon/Arp/ArpIpcServer.cs
new file mode 100644
index 00000000..6080b475
--- /dev/null
+++ b/src/Ryujinx.Horizon/Arp/ArpIpcServer.cs
@@ -0,0 +1,61 @@
+using Ryujinx.Horizon.Arp.Ipc;
+using Ryujinx.Horizon.Sdk.Arp;
+using Ryujinx.Horizon.Sdk.Arp.Detail;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using Ryujinx.Horizon.Sdk.Sm;
+
+namespace Ryujinx.Horizon.Arp
+{
+ class ArpIpcServer
+ {
+ private const int ArpRMaxSessionsCount = 16;
+ private const int ArpWMaxSessionsCount = 8;
+ private const int MaxSessionsCount = ArpRMaxSessionsCount + ArpWMaxSessionsCount;
+
+ private const int PointerBufferSize = 0x1000;
+ private const int MaxDomains = 24;
+ private const int MaxDomainObjects = 32;
+ private const int MaxPortsCount = 2;
+
+ private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
+
+ private SmApi _sm;
+ private ServerManager _serverManager;
+ private ApplicationInstanceManager _applicationInstanceManager;
+
+ public IReader Reader { get; private set; }
+ public IWriter Writer { get; private set; }
+
+ public void Initialize()
+ {
+ HeapAllocator allocator = new();
+
+ _sm = new SmApi();
+ _sm.Initialize().AbortOnFailure();
+
+ _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _managerOptions, MaxSessionsCount);
+
+ _applicationInstanceManager = new ApplicationInstanceManager();
+
+ Reader reader = new(_applicationInstanceManager);
+ Reader = reader;
+
+ Writer writer = new(_applicationInstanceManager);
+ Writer = writer;
+
+ _serverManager.RegisterObjectForServer(reader, ServiceName.Encode("arp:r"), ArpRMaxSessionsCount);
+ _serverManager.RegisterObjectForServer(writer, ServiceName.Encode("arp:w"), ArpWMaxSessionsCount);
+ }
+
+ public void ServiceRequests()
+ {
+ _serverManager.ServiceRequests();
+ }
+
+ public void Shutdown()
+ {
+ _applicationInstanceManager.Dispose();
+ _serverManager.Dispose();
+ }
+ }
+}
diff --git a/src/Ryujinx.Horizon/Arp/ArpMain.cs b/src/Ryujinx.Horizon/Arp/ArpMain.cs
new file mode 100644
index 00000000..a28baa71
--- /dev/null
+++ b/src/Ryujinx.Horizon/Arp/ArpMain.cs
@@ -0,0 +1,20 @@
+namespace Ryujinx.Horizon.Arp
+{
+ class ArpMain : IService
+ {
+ public static void Main(ServiceTable serviceTable)
+ {
+ ArpIpcServer arpIpcServer = new();
+
+ arpIpcServer.Initialize();
+
+ serviceTable.ArpReader = arpIpcServer.Reader;
+ serviceTable.ArpWriter = arpIpcServer.Writer;
+
+ serviceTable.SignalServiceReady();
+
+ arpIpcServer.ServiceRequests();
+ arpIpcServer.Shutdown();
+ }
+ }
+}
diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Reader.cs b/src/Ryujinx.Horizon/Arp/Ipc/Reader.cs
new file mode 100644
index 00000000..de99c2ad
--- /dev/null
+++ b/src/Ryujinx.Horizon/Arp/Ipc/Reader.cs
@@ -0,0 +1,135 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Arp;
+using Ryujinx.Horizon.Sdk.Arp.Detail;
+using Ryujinx.Horizon.Sdk.Ns;
+using Ryujinx.Horizon.Sdk.Sf;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Arp.Ipc
+{
+ partial class Reader : IReader, IServiceObject
+ {
+ private readonly ApplicationInstanceManager _applicationInstanceManager;
+
+ public Reader(ApplicationInstanceManager applicationInstanceManager)
+ {
+ _applicationInstanceManager = applicationInstanceManager;
+ }
+
+ [CmifCommand(0)]
+ public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId)
+ {
+ if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].LaunchProperty.HasValue)
+ {
+ applicationLaunchProperty = default;
+
+ return ArpResult.InvalidInstanceId;
+ }
+
+ applicationLaunchProperty = _applicationInstanceManager.Entries[applicationInstanceId].LaunchProperty.Value;
+
+ return Result.Success;
+ }
+
+ [CmifCommand(1)]
+ public Result GetApplicationControlProperty([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias, 0x4000)] out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId)
+ {
+ if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].ControlProperty.HasValue)
+ {
+ applicationControlProperty = default;
+
+ return ArpResult.InvalidInstanceId;
+ }
+
+ applicationControlProperty = _applicationInstanceManager.Entries[applicationInstanceId].ControlProperty.Value;
+
+ return Result.Success;
+ }
+
+ [CmifCommand(2)]
+ public Result GetApplicationProcessProperty(out ApplicationProcessProperty applicationProcessProperty, ulong applicationInstanceId)
+ {
+ if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].ProcessProperty.HasValue)
+ {
+ applicationProcessProperty = default;
+
+ return ArpResult.InvalidInstanceId;
+ }
+
+ applicationProcessProperty = _applicationInstanceManager.Entries[applicationInstanceId].ProcessProperty.Value;
+
+ return Result.Success;
+ }
+
+ [CmifCommand(3)]
+ public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong pid)
+ {
+ applicationInstanceId = 0;
+
+ if (pid == 0)
+ {
+ return ArpResult.InvalidPid;
+ }
+
+ for (int i = 0; i < _applicationInstanceManager.Entries.Length; i++)
+ {
+ if (_applicationInstanceManager.Entries[i] != null && _applicationInstanceManager.Entries[i].Pid == pid)
+ {
+ applicationInstanceId = (ulong)i;
+
+ return Result.Success;
+ }
+ }
+
+ return ArpResult.InvalidPid;
+ }
+
+ [CmifCommand(4)]
+ public Result GetApplicationInstanceUnregistrationNotifier(out IUnregistrationNotifier unregistrationNotifier)
+ {
+ unregistrationNotifier = new UnregistrationNotifier(_applicationInstanceManager);
+
+ return Result.Success;
+ }
+
+ [CmifCommand(5)]
+ public Result ListApplicationInstanceId(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span<ulong> applicationInstanceIdList)
+ {
+ count = 0;
+
+ if (_applicationInstanceManager.Entries[0] != null)
+ {
+ applicationInstanceIdList[count++] = 0;
+ }
+
+ if (_applicationInstanceManager.Entries[1] != null)
+ {
+ applicationInstanceIdList[count++] = 1;
+ }
+
+ return Result.Success;
+ }
+
+ [CmifCommand(6)]
+ public Result GetMicroApplicationInstanceId(out ulong microApplicationInstanceId, [ClientProcessId] ulong pid)
+ {
+ return GetApplicationInstanceId(out microApplicationInstanceId, pid);
+ }
+
+ [CmifCommand(7)]
+ public Result GetApplicationCertificate([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize, 0x528)] out ApplicationCertificate applicationCertificate, ulong applicationInstanceId)
+ {
+ if (_applicationInstanceManager.Entries[applicationInstanceId] == null)
+ {
+ applicationCertificate = default;
+
+ return ArpResult.InvalidInstanceId;
+ }
+
+ applicationCertificate = _applicationInstanceManager.Entries[applicationInstanceId].Certificate.Value;
+
+ return Result.Success;
+ }
+ }
+}
diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs b/src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs
new file mode 100644
index 00000000..841ab760
--- /dev/null
+++ b/src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs
@@ -0,0 +1,52 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Arp;
+using Ryujinx.Horizon.Sdk.Arp.Detail;
+using Ryujinx.Horizon.Sdk.Ns;
+using Ryujinx.Horizon.Sdk.Sf;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Arp.Ipc
+{
+ partial class Registrar : IRegistrar, IServiceObject
+ {
+ private readonly ApplicationInstance _applicationInstance;
+
+ public Registrar(ApplicationInstance applicationInstance)
+ {
+ _applicationInstance = applicationInstance;
+ }
+
+ [CmifCommand(0)]
+ public Result Issue(out ulong applicationInstanceId)
+ {
+ throw new NotImplementedException();
+ }
+
+ [CmifCommand(1)]
+ public Result SetApplicationLaunchProperty(ApplicationLaunchProperty applicationLaunchProperty)
+ {
+ if (_applicationInstance.LaunchProperty != null)
+ {
+ return ArpResult.DataAlreadyBound;
+ }
+
+ _applicationInstance.LaunchProperty = applicationLaunchProperty;
+
+ return Result.Success;
+ }
+
+ [CmifCommand(2)]
+ public Result SetApplicationControlProperty([Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize, 0x4000)] in ApplicationControlProperty applicationControlProperty)
+ {
+ if (_applicationInstance.ControlProperty != null)
+ {
+ return ArpResult.DataAlreadyBound;
+ }
+
+ _applicationInstance.ControlProperty = applicationControlProperty;
+
+ return Result.Success;
+ }
+ }
+}
diff --git a/src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs b/src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs
new file mode 100644
index 00000000..49f2b1cc
--- /dev/null
+++ b/src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs
@@ -0,0 +1,25 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Arp;
+using Ryujinx.Horizon.Sdk.Arp.Detail;
+using Ryujinx.Horizon.Sdk.Sf;
+
+namespace Ryujinx.Horizon.Arp.Ipc
+{
+ partial class UnregistrationNotifier : IUnregistrationNotifier, IServiceObject
+ {
+ private readonly ApplicationInstanceManager _applicationInstanceManager;
+
+ public UnregistrationNotifier(ApplicationInstanceManager applicationInstanceManager)
+ {
+ _applicationInstanceManager = applicationInstanceManager;
+ }
+
+ [CmifCommand(0)]
+ public Result GetReadableHandle([CopyHandle] out int readableHandle)
+ {
+ readableHandle = _applicationInstanceManager.EventHandle;
+
+ return Result.Success;
+ }
+ }
+}
diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Updater.cs b/src/Ryujinx.Horizon/Arp/Ipc/Updater.cs
new file mode 100644
index 00000000..f7531d71
--- /dev/null
+++ b/src/Ryujinx.Horizon/Arp/Ipc/Updater.cs
@@ -0,0 +1,74 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Arp;
+using Ryujinx.Horizon.Sdk.Arp.Detail;
+using Ryujinx.Horizon.Sdk.Sf;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Arp.Ipc
+{
+ partial class Updater : IUpdater, IServiceObject
+ {
+ private readonly ApplicationInstanceManager _applicationInstanceManager;
+ private readonly ulong _applicationInstanceId;
+ private readonly bool _forCertificate;
+
+ public Updater(ApplicationInstanceManager applicationInstanceManager, ulong applicationInstanceId, bool forCertificate)
+ {
+ _applicationInstanceManager = applicationInstanceManager;
+ _applicationInstanceId = applicationInstanceId;
+ _forCertificate = forCertificate;
+ }
+
+ [CmifCommand(0)]
+ public Result Issue()
+ {
+ throw new NotImplementedException();
+ }
+
+ [CmifCommand(1)]
+ public Result SetApplicationProcessProperty(ulong pid, ApplicationProcessProperty applicationProcessProperty)
+ {
+ if (_forCertificate)
+ {
+ return ArpResult.DataAlreadyBound;
+ }
+
+ if (pid == 0)
+ {
+ return ArpResult.InvalidPid;
+ }
+
+ _applicationInstanceManager.Entries[_applicationInstanceId].Pid = pid;
+ _applicationInstanceManager.Entries[_applicationInstanceId].ProcessProperty = applicationProcessProperty;
+
+ return Result.Success;
+ }
+
+ [CmifCommand(2)]
+ public Result DeleteApplicationProcessProperty()
+ {
+ if (_forCertificate)
+ {
+ return ArpResult.DataAlreadyBound;
+ }
+
+ _applicationInstanceManager.Entries[_applicationInstanceId].ProcessProperty = new ApplicationProcessProperty();
+
+ return Result.Success;
+ }
+
+ [CmifCommand(3)]
+ public Result SetApplicationCertificate([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ApplicationCertificate applicationCertificate)
+ {
+ if (!_forCertificate)
+ {
+ return ArpResult.DataAlreadyBound;
+ }
+
+ _applicationInstanceManager.Entries[_applicationInstanceId].Certificate = applicationCertificate;
+
+ return Result.Success;
+ }
+ }
+}
diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Writer.cs b/src/Ryujinx.Horizon/Arp/Ipc/Writer.cs
new file mode 100644
index 00000000..29c98b77
--- /dev/null
+++ b/src/Ryujinx.Horizon/Arp/Ipc/Writer.cs
@@ -0,0 +1,75 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Arp;
+using Ryujinx.Horizon.Sdk.Arp.Detail;
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf;
+
+namespace Ryujinx.Horizon.Arp.Ipc
+{
+ partial class Writer : IWriter, IServiceObject
+ {
+ private readonly ApplicationInstanceManager _applicationInstanceManager;
+
+ public Writer(ApplicationInstanceManager applicationInstanceManager)
+ {
+ _applicationInstanceManager = applicationInstanceManager;
+ }
+
+ [CmifCommand(0)]
+ public Result AcquireRegistrar(out IRegistrar registrar)
+ {
+ if (_applicationInstanceManager.Entries[0] != null)
+ {
+ if (_applicationInstanceManager.Entries[1] != null)
+ {
+ registrar = null;
+
+ return ArpResult.NoFreeInstance;
+ }
+ else
+ {
+ _applicationInstanceManager.Entries[1] = new ApplicationInstance();
+
+ registrar = new Registrar(_applicationInstanceManager.Entries[1]);
+ }
+ }
+ else
+ {
+ _applicationInstanceManager.Entries[0] = new ApplicationInstance();
+
+ registrar = new Registrar(_applicationInstanceManager.Entries[0]);
+ }
+
+ return Result.Success;
+ }
+
+ [CmifCommand(1)]
+ public Result UnregisterApplicationInstance(ulong applicationInstanceId)
+ {
+ if (_applicationInstanceManager.Entries[applicationInstanceId] != null)
+ {
+ _applicationInstanceManager.Entries[applicationInstanceId] = null;
+ }
+
+ Os.SignalSystemEvent(ref _applicationInstanceManager.SystemEvent);
+
+ return Result.Success;
+ }
+
+ [CmifCommand(2)]
+ public Result AcquireApplicationProcessPropertyUpdater(out IUpdater updater, ulong applicationInstanceId)
+ {
+ updater = new Updater(_applicationInstanceManager, applicationInstanceId, false);
+
+ return Result.Success;
+ }
+
+ [CmifCommand(3)]
+ public Result AcquireApplicationCertificateUpdater(out IUpdater updater, ulong applicationInstanceId)
+ {
+ updater = new Updater(_applicationInstanceManager, applicationInstanceId, true);
+
+ return Result.Success;
+ }
+ }
+}