diff options
| author | Ac_K <Acoustik666@gmail.com> | 2024-01-25 23:06:53 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-25 23:06:53 +0100 |
| commit | cd37c75b82f97ad5d3bf6317ffcde62c06a6e920 (patch) | |
| tree | db4f6e9630878a4b32c8880ef95f7c877e20aab0 /src/Ryujinx.Horizon/Sdk/Arp | |
| parent | 43705c2320c2ff7c8f6dca1141f3bf56033966d4 (diff) | |
Horizon: Implement arp:r and arp:w services (#5802)
* Horizon: Implement arp:r and arp:w services
* Fix formatting
* Remove HLE arp services
* Revert "Remove HLE arp services"
This reverts commit c576fcccadb963db56b96bacabd1c1ac7abfb1ab.
* Keep LibHac impl since it's used in bcat
* Addresses gdkchan's feedback
* ArpApi in PrepoIpcServer and remove LmApi
* Fix 2
* Fixes ArpApi init
* Fix encoding
* Update PrepoService.cs
* Fix prepo
Diffstat (limited to 'src/Ryujinx.Horizon/Sdk/Arp')
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs | 9 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs | 8 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs | 14 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs | 10 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs | 130 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs | 17 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs | 13 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs | 31 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/IReader.cs | 18 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs | 12 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs | 9 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs | 12 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs | 12 |
13 files changed, 295 insertions, 0 deletions
diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs new file mode 100644 index 00000000..d60d337d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + [StructLayout(LayoutKind.Sequential, Size = 0x528)] + public struct ApplicationCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs new file mode 100644 index 00000000..586e6a98 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sdk.Arp +{ + public enum ApplicationKind : byte + { + Application, + MicroApplication, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs new file mode 100644 index 00000000..00b81832 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs @@ -0,0 +1,14 @@ +using Ryujinx.Horizon.Sdk.Ncm; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public struct ApplicationLaunchProperty + { + public ApplicationId ApplicationId; + public uint Version; + public StorageId Storage; + public StorageId PatchStorage; + public ApplicationKind ApplicationKind; + public byte Padding; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs new file mode 100644 index 00000000..13d222a1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs @@ -0,0 +1,10 @@ +using Ryujinx.Common.Memory; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public struct ApplicationProcessProperty + { + public byte ProgramIndex; + public Array15<byte> Unknown; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs b/src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs new file mode 100644 index 00000000..b0acc006 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs @@ -0,0 +1,130 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Ns; +using Ryujinx.Horizon.Sdk.Sf.Cmif; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; +using System; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + class ArpApi : IDisposable + { + private const string ArpRName = "arp:r"; + + private readonly HeapAllocator _allocator; + private int _sessionHandle; + + public ArpApi(HeapAllocator allocator) + { + _allocator = allocator; + } + + private void InitializeArpRService() + { + if (_sessionHandle == 0) + { + using var smApi = new SmApi(); + + smApi.Initialize(); + smApi.GetServiceHandle(out _sessionHandle, ServiceName.Encode(ArpRName)).AbortOnFailure(); + } + } + + public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong applicationPid) + { + Span<byte> data = stackalloc byte[8]; + SpanWriter writer = new(data); + + writer.Write(applicationPid); + + InitializeArpRService(); + + Result result = ServiceUtil.SendRequest(out CmifResponse response, _sessionHandle, 3, sendPid: false, data); + if (result.IsFailure) + { + applicationInstanceId = 0; + + return result; + } + + SpanReader reader = new(response.Data); + + applicationInstanceId = reader.Read<ulong>(); + + return Result.Success; + } + + public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId) + { + applicationLaunchProperty = default; + + Span<byte> data = stackalloc byte[8]; + SpanWriter writer = new(data); + + writer.Write(applicationInstanceId); + + InitializeArpRService(); + + Result result = ServiceUtil.SendRequest(out CmifResponse response, _sessionHandle, 0, sendPid: false, data); + if (result.IsFailure) + { + return result; + } + + SpanReader reader = new(response.Data); + + applicationLaunchProperty = reader.Read<ApplicationLaunchProperty>(); + + return Result.Success; + } + + public Result GetApplicationControlProperty(out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId) + { + applicationControlProperty = default; + + Span<byte> data = stackalloc byte[8]; + SpanWriter writer = new(data); + + writer.Write(applicationInstanceId); + + ulong bufferSize = (ulong)Unsafe.SizeOf<ApplicationControlProperty>(); + ulong bufferAddress = _allocator.Allocate(bufferSize); + + InitializeArpRService(); + + Result result = ServiceUtil.SendRequest( + out CmifResponse response, + _sessionHandle, + 1, + sendPid: false, + data, + stackalloc[] { HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize }, + stackalloc[] { new PointerAndSize(bufferAddress, bufferSize) }); + + if (result.IsFailure) + { + return result; + } + + applicationControlProperty = HorizonStatic.AddressSpace.Read<ApplicationControlProperty>(bufferAddress); + + _allocator.Free(bufferAddress, bufferSize); + + return Result.Success; + } + + public void Dispose() + { + if (_sessionHandle != 0) + { + HorizonStatic.Syscall.CloseHandle(_sessionHandle); + + _sessionHandle = 0; + } + + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs b/src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs new file mode 100644 index 00000000..5de07871 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs @@ -0,0 +1,17 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + static class ArpResult + { + private const int ModuleId = 157; + + public static Result InvalidArgument => new(ModuleId, 30); + public static Result InvalidPid => new(ModuleId, 31); + public static Result InvalidPointer => new(ModuleId, 32); + public static Result DataAlreadyBound => new(ModuleId, 42); + public static Result AllocationFailed => new(ModuleId, 63); + public static Result NoFreeInstance => new(ModuleId, 101); + public static Result InvalidInstanceId => new(ModuleId, 102); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs new file mode 100644 index 00000000..5eb0ab18 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs @@ -0,0 +1,13 @@ +using Ryujinx.Horizon.Sdk.Ns; + +namespace Ryujinx.Horizon.Sdk.Arp.Detail +{ + class ApplicationInstance + { + public ulong Pid { get; set; } + public ApplicationLaunchProperty? LaunchProperty { get; set; } + public ApplicationProcessProperty? ProcessProperty { get; set; } + public ApplicationControlProperty? ControlProperty { get; set; } + public ApplicationCertificate? Certificate { get; set; } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs new file mode 100644 index 00000000..18c993ce --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs @@ -0,0 +1,31 @@ +using Ryujinx.Horizon.Sdk.OsTypes; +using System; +using System.Threading; + +namespace Ryujinx.Horizon.Sdk.Arp.Detail +{ + class ApplicationInstanceManager : IDisposable + { + private int _disposalState; + + public SystemEventType SystemEvent; + public int EventHandle; + + public readonly ApplicationInstance[] Entries = new ApplicationInstance[2]; + + public ApplicationInstanceManager() + { + Os.CreateSystemEvent(out SystemEvent, EventClearMode.ManualClear, true).AbortOnFailure(); + + EventHandle = Os.GetReadableHandleOfSystemEvent(ref SystemEvent); + } + + public void Dispose() + { + if (EventHandle != 0 && Interlocked.Exchange(ref _disposalState, 1) == 0) + { + Os.DestroySystemEvent(ref SystemEvent); + } + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IReader.cs b/src/Ryujinx.Horizon/Sdk/Arp/IReader.cs new file mode 100644 index 00000000..ef78f7fd --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IReader.cs @@ -0,0 +1,18 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Ns; +using System; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IReader + { + public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId); + public Result GetApplicationControlProperty(out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId); + public Result GetApplicationProcessProperty(out ApplicationProcessProperty applicationControlProperty, ulong applicationInstanceId); + public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong pid); + public Result GetApplicationInstanceUnregistrationNotifier(out IUnregistrationNotifier unregistrationNotifier); + public Result ListApplicationInstanceId(out int count, Span<ulong> applicationInstanceIdList); + public Result GetMicroApplicationInstanceId(out ulong MicroApplicationInstanceId, ulong pid); + public Result GetApplicationCertificate(out ApplicationCertificate applicationCertificate, ulong applicationInstanceId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs b/src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs new file mode 100644 index 00000000..467f3dbd --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Ns; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IRegistrar + { + public Result Issue(out ulong applicationInstanceId); + public Result SetApplicationLaunchProperty(ApplicationLaunchProperty applicationLaunchProperty); + public Result SetApplicationControlProperty(in ApplicationControlProperty applicationControlProperty); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs b/src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs new file mode 100644 index 00000000..24b9807d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs @@ -0,0 +1,9 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IUnregistrationNotifier + { + public Result GetReadableHandle(out int readableHandle); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs b/src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs new file mode 100644 index 00000000..f9beeb69 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IUpdater + { + public Result Issue(); + public Result SetApplicationProcessProperty(ulong pid, ApplicationProcessProperty applicationProcessProperty); + public Result DeleteApplicationProcessProperty(); + public Result SetApplicationCertificate(ApplicationCertificate applicationCertificate); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs b/src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs new file mode 100644 index 00000000..b3e000e1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IWriter + { + public Result AcquireRegistrar(out IRegistrar registrar); + public Result UnregisterApplicationInstance(ulong applicationInstanceId); + public Result AcquireApplicationProcessPropertyUpdater(out IUpdater updater, ulong applicationInstanceId); + public Result AcquireApplicationCertificateUpdater(out IUpdater updater, ulong applicationInstanceId); + } +} |
