1
1
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:
Ac_K
2024-01-25 23:06:53 +01:00
committed by GitHub
parent 43705c2320
commit cd37c75b82
40 changed files with 1415 additions and 37 deletions

View File

@@ -0,0 +1,9 @@
using System.Runtime.InteropServices;
namespace Ryujinx.Horizon.Sdk.Arp
{
[StructLayout(LayoutKind.Sequential, Size = 0x528)]
public struct ApplicationCertificate
{
}
}

View File

@@ -0,0 +1,8 @@
namespace Ryujinx.Horizon.Sdk.Arp
{
public enum ApplicationKind : byte
{
Application,
MicroApplication,
}
}

View 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;
}
}

View File

@@ -0,0 +1,10 @@
using Ryujinx.Common.Memory;
namespace Ryujinx.Horizon.Sdk.Arp
{
public struct ApplicationProcessProperty
{
public byte ProgramIndex;
public Array15<byte> Unknown;
}
}

View 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);
}
}
}

View 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);
}
}

View 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; }
}
}

View File

@@ -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);
}
}
}
}

View 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);
}
}

View 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);
}
}

View File

@@ -0,0 +1,9 @@
using Ryujinx.Horizon.Common;
namespace Ryujinx.Horizon.Sdk.Arp
{
public interface IUnregistrationNotifier
{
public Result GetReadableHandle(out int readableHandle);
}
}

View 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);
}
}

View 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);
}
}

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Horizon.Sdk.Ncm
{
readonly struct ApplicationId
public readonly struct ApplicationId
{
public readonly ulong Id;

View File

@@ -0,0 +1,13 @@
namespace Ryujinx.Horizon.Sdk.Ncm
{
public enum StorageId : byte
{
None,
Host,
GameCard,
BuiltInSystem,
BuiltInUser,
SdCard,
Any,
}
}

View 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,
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}