mirror of
https://github.com/ryujinx-mirror/ryujinx.git
synced 2025-10-03 07:55:51 -05:00
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
This commit is contained in:
9
src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs
Normal file
9
src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Arp
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x528)]
|
||||
public struct ApplicationCertificate
|
||||
{
|
||||
}
|
||||
}
|
8
src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs
Normal file
8
src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Ryujinx.Horizon.Sdk.Arp
|
||||
{
|
||||
public enum ApplicationKind : byte
|
||||
{
|
||||
Application,
|
||||
MicroApplication,
|
||||
}
|
||||
}
|
14
src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs
Normal file
14
src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
10
src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs
Normal file
10
src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Arp
|
||||
{
|
||||
public struct ApplicationProcessProperty
|
||||
{
|
||||
public byte ProgramIndex;
|
||||
public Array15<byte> Unknown;
|
||||
}
|
||||
}
|
130
src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs
Normal file
130
src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
17
src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs
Normal file
17
src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
13
src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs
Normal file
13
src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs
Normal file
@@ -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; }
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
src/Ryujinx.Horizon/Sdk/Arp/IReader.cs
Normal file
18
src/Ryujinx.Horizon/Sdk/Arp/IReader.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
12
src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs
Normal file
12
src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
9
src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs
Normal file
9
src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Ryujinx.Horizon.Common;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Arp
|
||||
{
|
||||
public interface IUnregistrationNotifier
|
||||
{
|
||||
public Result GetReadableHandle(out int readableHandle);
|
||||
}
|
||||
}
|
12
src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs
Normal file
12
src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
12
src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs
Normal file
12
src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Horizon.Sdk.Ncm
|
||||
{
|
||||
readonly struct ApplicationId
|
||||
public readonly struct ApplicationId
|
||||
{
|
||||
public readonly ulong Id;
|
||||
|
||||
|
13
src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs
Normal file
13
src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Ryujinx.Horizon.Sdk.Ncm
|
||||
{
|
||||
public enum StorageId : byte
|
||||
{
|
||||
None,
|
||||
Host,
|
||||
GameCard,
|
||||
BuiltInSystem,
|
||||
BuiltInUser,
|
||||
SdCard,
|
||||
Any,
|
||||
}
|
||||
}
|
309
src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs
Normal file
309
src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs
Normal file
@@ -0,0 +1,309 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Horizon.Sdk.Arp.Detail;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Ns
|
||||
{
|
||||
public struct ApplicationControlProperty
|
||||
{
|
||||
public Array16<ApplicationTitle> Title;
|
||||
public Array37<byte> Isbn;
|
||||
public StartupUserAccountValue StartupUserAccount;
|
||||
public UserAccountSwitchLockValue UserAccountSwitchLock;
|
||||
public AddOnContentRegistrationTypeValue AddOnContentRegistrationType;
|
||||
public AttributeFlagValue AttributeFlag;
|
||||
public uint SupportedLanguageFlag;
|
||||
public ParentalControlFlagValue ParentalControlFlag;
|
||||
public ScreenshotValue Screenshot;
|
||||
public VideoCaptureValue VideoCapture;
|
||||
public DataLossConfirmationValue DataLossConfirmation;
|
||||
public PlayLogPolicyValue PlayLogPolicy;
|
||||
public ulong PresenceGroupId;
|
||||
public Array32<sbyte> RatingAge;
|
||||
public Array16<byte> DisplayVersion;
|
||||
public ulong AddOnContentBaseId;
|
||||
public ulong SaveDataOwnerId;
|
||||
public long UserAccountSaveDataSize;
|
||||
public long UserAccountSaveDataJournalSize;
|
||||
public long DeviceSaveDataSize;
|
||||
public long DeviceSaveDataJournalSize;
|
||||
public long BcatDeliveryCacheStorageSize;
|
||||
public Array8<byte> ApplicationErrorCodeCategory;
|
||||
public Array8<ulong> LocalCommunicationId;
|
||||
public LogoTypeValue LogoType;
|
||||
public LogoHandlingValue LogoHandling;
|
||||
public RuntimeAddOnContentInstallValue RuntimeAddOnContentInstall;
|
||||
public RuntimeParameterDeliveryValue RuntimeParameterDelivery;
|
||||
public Array2<byte> Reserved30F4;
|
||||
public CrashReportValue CrashReport;
|
||||
public HdcpValue Hdcp;
|
||||
public ulong SeedForPseudoDeviceId;
|
||||
public Array65<byte> BcatPassphrase;
|
||||
public StartupUserAccountOptionFlagValue StartupUserAccountOption;
|
||||
public Array6<byte> ReservedForUserAccountSaveDataOperation;
|
||||
public long UserAccountSaveDataSizeMax;
|
||||
public long UserAccountSaveDataJournalSizeMax;
|
||||
public long DeviceSaveDataSizeMax;
|
||||
public long DeviceSaveDataJournalSizeMax;
|
||||
public long TemporaryStorageSize;
|
||||
public long CacheStorageSize;
|
||||
public long CacheStorageJournalSize;
|
||||
public long CacheStorageDataAndJournalSizeMax;
|
||||
public ushort CacheStorageIndexMax;
|
||||
public byte Reserved318A;
|
||||
public byte RuntimeUpgrade;
|
||||
public uint SupportingLimitedLicenses;
|
||||
public Array16<ulong> PlayLogQueryableApplicationId;
|
||||
public PlayLogQueryCapabilityValue PlayLogQueryCapability;
|
||||
public RepairFlagValue RepairFlag;
|
||||
public byte ProgramIndex;
|
||||
public RequiredNetworkServiceLicenseOnLaunchValue RequiredNetworkServiceLicenseOnLaunchFlag;
|
||||
public Array4<byte> Reserved3214;
|
||||
public ApplicationNeighborDetectionClientConfiguration NeighborDetectionClientConfiguration;
|
||||
public ApplicationJitConfiguration JitConfiguration;
|
||||
public RequiredAddOnContentsSetBinaryDescriptor RequiredAddOnContentsSetBinaryDescriptors;
|
||||
public PlayReportPermissionValue PlayReportPermission;
|
||||
public CrashScreenshotForProdValue CrashScreenshotForProd;
|
||||
public CrashScreenshotForDevValue CrashScreenshotForDev;
|
||||
public byte ContentsAvailabilityTransitionPolicy;
|
||||
public Array4<byte> Reserved3404;
|
||||
public AccessibleLaunchRequiredVersionValue AccessibleLaunchRequiredVersion;
|
||||
public ByteArray3000 Reserved3448;
|
||||
|
||||
public readonly string IsbnString => Encoding.UTF8.GetString(Isbn.AsSpan()).TrimEnd('\0');
|
||||
public readonly string DisplayVersionString => Encoding.UTF8.GetString(DisplayVersion.AsSpan()).TrimEnd('\0');
|
||||
public readonly string ApplicationErrorCodeCategoryString => Encoding.UTF8.GetString(ApplicationErrorCodeCategory.AsSpan()).TrimEnd('\0');
|
||||
public readonly string BcatPassphraseString => Encoding.UTF8.GetString(BcatPassphrase.AsSpan()).TrimEnd('\0');
|
||||
|
||||
public struct ApplicationTitle
|
||||
{
|
||||
public ByteArray512 Name;
|
||||
public Array256<byte> Publisher;
|
||||
|
||||
public readonly string NameString => Encoding.UTF8.GetString(Name.AsSpan()).TrimEnd('\0');
|
||||
public readonly string PublisherString => Encoding.UTF8.GetString(Publisher.AsSpan()).TrimEnd('\0');
|
||||
}
|
||||
|
||||
public struct ApplicationNeighborDetectionClientConfiguration
|
||||
{
|
||||
public ApplicationNeighborDetectionGroupConfiguration SendGroupConfiguration;
|
||||
public Array16<ApplicationNeighborDetectionGroupConfiguration> ReceivableGroupConfigurations;
|
||||
}
|
||||
|
||||
public struct ApplicationNeighborDetectionGroupConfiguration
|
||||
{
|
||||
public ulong GroupId;
|
||||
public Array16<byte> Key;
|
||||
}
|
||||
|
||||
public struct ApplicationJitConfiguration
|
||||
{
|
||||
public JitConfigurationFlag Flags;
|
||||
public long MemorySize;
|
||||
}
|
||||
|
||||
public struct RequiredAddOnContentsSetBinaryDescriptor
|
||||
{
|
||||
public Array32<ushort> Descriptors;
|
||||
}
|
||||
|
||||
public struct AccessibleLaunchRequiredVersionValue
|
||||
{
|
||||
public Array8<ulong> ApplicationId;
|
||||
}
|
||||
|
||||
public enum Language
|
||||
{
|
||||
AmericanEnglish = 0,
|
||||
BritishEnglish = 1,
|
||||
Japanese = 2,
|
||||
French = 3,
|
||||
German = 4,
|
||||
LatinAmericanSpanish = 5,
|
||||
Spanish = 6,
|
||||
Italian = 7,
|
||||
Dutch = 8,
|
||||
CanadianFrench = 9,
|
||||
Portuguese = 10,
|
||||
Russian = 11,
|
||||
Korean = 12,
|
||||
TraditionalChinese = 13,
|
||||
SimplifiedChinese = 14,
|
||||
BrazilianPortuguese = 15,
|
||||
}
|
||||
|
||||
public enum Organization
|
||||
{
|
||||
CERO = 0,
|
||||
GRACGCRB = 1,
|
||||
GSRMR = 2,
|
||||
ESRB = 3,
|
||||
ClassInd = 4,
|
||||
USK = 5,
|
||||
PEGI = 6,
|
||||
PEGIPortugal = 7,
|
||||
PEGIBBFC = 8,
|
||||
Russian = 9,
|
||||
ACB = 10,
|
||||
OFLC = 11,
|
||||
IARCGeneric = 12,
|
||||
}
|
||||
|
||||
public enum StartupUserAccountValue : byte
|
||||
{
|
||||
None = 0,
|
||||
Required = 1,
|
||||
RequiredWithNetworkServiceAccountAvailable = 2,
|
||||
}
|
||||
|
||||
public enum UserAccountSwitchLockValue : byte
|
||||
{
|
||||
Disable = 0,
|
||||
Enable = 1,
|
||||
}
|
||||
|
||||
public enum AddOnContentRegistrationTypeValue : byte
|
||||
{
|
||||
AllOnLaunch = 0,
|
||||
OnDemand = 1,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum AttributeFlagValue
|
||||
{
|
||||
None = 0,
|
||||
Demo = 1 << 0,
|
||||
RetailInteractiveDisplay = 1 << 1,
|
||||
}
|
||||
|
||||
public enum ParentalControlFlagValue
|
||||
{
|
||||
None = 0,
|
||||
FreeCommunication = 1,
|
||||
}
|
||||
|
||||
public enum ScreenshotValue : byte
|
||||
{
|
||||
Allow = 0,
|
||||
Deny = 1,
|
||||
}
|
||||
|
||||
public enum VideoCaptureValue : byte
|
||||
{
|
||||
Disable = 0,
|
||||
Manual = 1,
|
||||
Enable = 2,
|
||||
}
|
||||
|
||||
public enum DataLossConfirmationValue : byte
|
||||
{
|
||||
None = 0,
|
||||
Required = 1,
|
||||
}
|
||||
|
||||
public enum PlayLogPolicyValue : byte
|
||||
{
|
||||
Open = 0,
|
||||
LogOnly = 1,
|
||||
None = 2,
|
||||
Closed = 3,
|
||||
All = Open,
|
||||
}
|
||||
|
||||
public enum LogoTypeValue : byte
|
||||
{
|
||||
LicensedByNintendo = 0,
|
||||
DistributedByNintendo = 1,
|
||||
Nintendo = 2,
|
||||
}
|
||||
|
||||
public enum LogoHandlingValue : byte
|
||||
{
|
||||
Auto = 0,
|
||||
Manual = 1,
|
||||
}
|
||||
|
||||
public enum RuntimeAddOnContentInstallValue : byte
|
||||
{
|
||||
Deny = 0,
|
||||
AllowAppend = 1,
|
||||
AllowAppendButDontDownloadWhenUsingNetwork = 2,
|
||||
}
|
||||
|
||||
public enum RuntimeParameterDeliveryValue : byte
|
||||
{
|
||||
Always = 0,
|
||||
AlwaysIfUserStateMatched = 1,
|
||||
OnRestart = 2,
|
||||
}
|
||||
|
||||
public enum CrashReportValue : byte
|
||||
{
|
||||
Deny = 0,
|
||||
Allow = 1,
|
||||
}
|
||||
|
||||
public enum HdcpValue : byte
|
||||
{
|
||||
None = 0,
|
||||
Required = 1,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum StartupUserAccountOptionFlagValue : byte
|
||||
{
|
||||
None = 0,
|
||||
IsOptional = 1 << 0,
|
||||
}
|
||||
|
||||
public enum PlayLogQueryCapabilityValue : byte
|
||||
{
|
||||
None = 0,
|
||||
WhiteList = 1,
|
||||
All = 2,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum RepairFlagValue : byte
|
||||
{
|
||||
None = 0,
|
||||
SuppressGameCardAccess = 1 << 0,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum RequiredNetworkServiceLicenseOnLaunchValue : byte
|
||||
{
|
||||
None = 0,
|
||||
Common = 1 << 0,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum JitConfigurationFlag : ulong
|
||||
{
|
||||
None = 0,
|
||||
Enabled = 1 << 0,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum PlayReportPermissionValue : byte
|
||||
{
|
||||
None = 0,
|
||||
TargetMarketing = 1 << 0,
|
||||
}
|
||||
|
||||
public enum CrashScreenshotForProdValue : byte
|
||||
{
|
||||
Deny = 0,
|
||||
Allow = 1,
|
||||
}
|
||||
|
||||
public enum CrashScreenshotForDevValue : byte
|
||||
{
|
||||
Deny = 0,
|
||||
Allow = 1,
|
||||
}
|
||||
}
|
||||
}
|
@@ -35,5 +35,254 @@ namespace Ryujinx.Horizon.Sdk
|
||||
|
||||
return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0);
|
||||
}
|
||||
|
||||
public static Result SendRequest(
|
||||
out CmifResponse response,
|
||||
int sessionHandle,
|
||||
uint requestId,
|
||||
bool sendPid,
|
||||
scoped ReadOnlySpan<byte> data,
|
||||
ReadOnlySpan<HipcBufferFlags> bufferFlags,
|
||||
ReadOnlySpan<PointerAndSize> buffers)
|
||||
{
|
||||
ulong tlsAddress = HorizonStatic.ThreadContext.TlsAddress;
|
||||
int tlsSize = Api.TlsMessageBufferSize;
|
||||
|
||||
using (var tlsRegion = HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize))
|
||||
{
|
||||
CmifRequestFormat format = new()
|
||||
{
|
||||
DataSize = data.Length,
|
||||
RequestId = requestId,
|
||||
SendPid = sendPid,
|
||||
};
|
||||
|
||||
for (int index = 0; index < bufferFlags.Length; index++)
|
||||
{
|
||||
FormatProcessBuffer(ref format, bufferFlags[index]);
|
||||
}
|
||||
|
||||
CmifRequest request = CmifMessage.CreateRequest(tlsRegion.Memory.Span, format);
|
||||
|
||||
for (int index = 0; index < buffers.Length; index++)
|
||||
{
|
||||
RequestProcessBuffer(ref request, buffers[index], bufferFlags[index]);
|
||||
}
|
||||
|
||||
data.CopyTo(request.Data);
|
||||
}
|
||||
|
||||
Result result = HorizonStatic.Syscall.SendSyncRequest(sessionHandle);
|
||||
|
||||
if (result.IsFailure)
|
||||
{
|
||||
response = default;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0);
|
||||
}
|
||||
|
||||
private static void FormatProcessBuffer(ref CmifRequestFormat format, HipcBufferFlags flags)
|
||||
{
|
||||
if (flags == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool isIn = flags.HasFlag(HipcBufferFlags.In);
|
||||
bool isOut = flags.HasFlag(HipcBufferFlags.Out);
|
||||
|
||||
if (flags.HasFlag(HipcBufferFlags.AutoSelect))
|
||||
{
|
||||
if (isIn)
|
||||
{
|
||||
format.InAutoBuffersCount++;
|
||||
}
|
||||
|
||||
if (isOut)
|
||||
{
|
||||
format.OutAutoBuffersCount++;
|
||||
}
|
||||
}
|
||||
else if (flags.HasFlag(HipcBufferFlags.Pointer))
|
||||
{
|
||||
if (isIn)
|
||||
{
|
||||
format.InPointersCount++;
|
||||
}
|
||||
|
||||
if (isOut)
|
||||
{
|
||||
if (flags.HasFlag(HipcBufferFlags.FixedSize))
|
||||
{
|
||||
format.OutFixedPointersCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
format.OutPointersCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (flags.HasFlag(HipcBufferFlags.MapAlias))
|
||||
{
|
||||
if (isIn && isOut)
|
||||
{
|
||||
format.InOutBuffersCount++;
|
||||
}
|
||||
else if (isIn)
|
||||
{
|
||||
format.InBuffersCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
format.OutBuffersCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RequestProcessBuffer(ref CmifRequest request, PointerAndSize buffer, HipcBufferFlags flags)
|
||||
{
|
||||
if (flags == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool isIn = flags.HasFlag(HipcBufferFlags.In);
|
||||
bool isOut = flags.HasFlag(HipcBufferFlags.Out);
|
||||
|
||||
if (flags.HasFlag(HipcBufferFlags.AutoSelect))
|
||||
{
|
||||
HipcBufferMode mode = HipcBufferMode.Normal;
|
||||
|
||||
if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure))
|
||||
{
|
||||
mode = HipcBufferMode.NonSecure;
|
||||
}
|
||||
|
||||
if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
|
||||
{
|
||||
mode = HipcBufferMode.NonDevice;
|
||||
}
|
||||
|
||||
if (isIn)
|
||||
{
|
||||
RequestInAutoBuffer(ref request, buffer.Address, buffer.Size, mode);
|
||||
}
|
||||
|
||||
if (isOut)
|
||||
{
|
||||
RequestOutAutoBuffer(ref request, buffer.Address, buffer.Size, mode);
|
||||
}
|
||||
}
|
||||
else if (flags.HasFlag(HipcBufferFlags.Pointer))
|
||||
{
|
||||
if (isIn)
|
||||
{
|
||||
RequestInPointer(ref request, buffer.Address, buffer.Size);
|
||||
}
|
||||
|
||||
if (isOut)
|
||||
{
|
||||
if (flags.HasFlag(HipcBufferFlags.FixedSize))
|
||||
{
|
||||
RequestOutFixedPointer(ref request, buffer.Address, buffer.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
RequestOutPointer(ref request, buffer.Address, buffer.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (flags.HasFlag(HipcBufferFlags.MapAlias))
|
||||
{
|
||||
HipcBufferMode mode = HipcBufferMode.Normal;
|
||||
|
||||
if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure))
|
||||
{
|
||||
mode = HipcBufferMode.NonSecure;
|
||||
}
|
||||
|
||||
if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
|
||||
{
|
||||
mode = HipcBufferMode.NonDevice;
|
||||
}
|
||||
|
||||
if (isIn && isOut)
|
||||
{
|
||||
RequestInOutBuffer(ref request, buffer.Address, buffer.Size, mode);
|
||||
}
|
||||
else if (isIn)
|
||||
{
|
||||
RequestInBuffer(ref request, buffer.Address, buffer.Size, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
RequestOutBuffer(ref request, buffer.Address, buffer.Size, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RequestInAutoBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
|
||||
{
|
||||
if (request.ServerPointerSize != 0 && bufferSize <= (ulong)request.ServerPointerSize)
|
||||
{
|
||||
RequestInPointer(ref request, bufferAddress, bufferSize);
|
||||
RequestInBuffer(ref request, 0UL, 0UL, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
RequestInPointer(ref request, 0UL, 0UL);
|
||||
RequestInBuffer(ref request, bufferAddress, bufferSize, mode);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RequestOutAutoBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
|
||||
{
|
||||
if (request.ServerPointerSize != 0 && bufferSize <= (ulong)request.ServerPointerSize)
|
||||
{
|
||||
RequestOutPointer(ref request, bufferAddress, bufferSize);
|
||||
RequestOutBuffer(ref request, 0UL, 0UL, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
RequestOutPointer(ref request, 0UL, 0UL);
|
||||
RequestOutBuffer(ref request, bufferAddress, bufferSize, mode);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RequestInBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
|
||||
{
|
||||
request.Hipc.SendBuffers[request.SendBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode);
|
||||
}
|
||||
|
||||
private static void RequestOutBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
|
||||
{
|
||||
request.Hipc.ReceiveBuffers[request.RecvBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode);
|
||||
}
|
||||
|
||||
private static void RequestInOutBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
|
||||
{
|
||||
request.Hipc.ExchangeBuffers[request.ExchBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode);
|
||||
}
|
||||
|
||||
private static void RequestInPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize)
|
||||
{
|
||||
request.Hipc.SendStatics[request.SendStaticIndex++] = new HipcStaticDescriptor(bufferAddress, (ushort)bufferSize, request.CurrentInPointerId++);
|
||||
request.ServerPointerSize -= (int)bufferSize;
|
||||
}
|
||||
|
||||
private static void RequestOutFixedPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize)
|
||||
{
|
||||
request.Hipc.ReceiveList[request.RecvListIndex++] = new HipcReceiveListEntry(bufferAddress, (ushort)bufferSize);
|
||||
request.ServerPointerSize -= (int)bufferSize;
|
||||
}
|
||||
|
||||
private static void RequestOutPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize)
|
||||
{
|
||||
RequestOutFixedPointer(ref request, bufferAddress, bufferSize);
|
||||
request.OutPointerSizes[request.OutPointerSizeIndex++] = (ushort)bufferSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,5 +10,12 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
|
||||
public Span<ushort> OutPointerSizes;
|
||||
public Span<uint> Objects;
|
||||
public int ServerPointerSize;
|
||||
public int CurrentInPointerId;
|
||||
public int SendBufferIndex;
|
||||
public int RecvBufferIndex;
|
||||
public int ExchBufferIndex;
|
||||
public int SendStaticIndex;
|
||||
public int RecvListIndex;
|
||||
public int OutPointerSizeIndex;
|
||||
}
|
||||
}
|
||||
|
@@ -11,5 +11,12 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc
|
||||
public ulong Address => _addressLow | (((ulong)_word2 << 4) & 0xf00000000UL) | (((ulong)_word2 << 34) & 0x7000000000UL);
|
||||
public ulong Size => _sizeLow | ((ulong)_word2 << 8) & 0xf00000000UL;
|
||||
public HipcBufferMode Mode => (HipcBufferMode)(_word2 & 3);
|
||||
|
||||
public HipcBufferDescriptor(ulong address, ulong size, HipcBufferMode mode)
|
||||
{
|
||||
_sizeLow = (uint)size;
|
||||
_addressLow = (uint)address;
|
||||
_word2 = (uint)mode | ((uint)(address >> 34) & 0x1c) | ((uint)(size >> 32) << 24) | ((uint)(address >> 4) & 0xf0000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user