diff --git a/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs b/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs index 332e04d1..8f4c37f7 100644 --- a/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs +++ b/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs @@ -267,6 +267,8 @@ namespace Ryujinx.Horizon.Generators.Hipc } int index = 0; + int inArgIndex = 0; + int outArgIndex = 0; int inCopyHandleIndex = 0; int inMoveHandleIndex = 0; int inObjectIndex = 0; @@ -284,7 +286,7 @@ namespace Ryujinx.Horizon.Generators.Hipc { if (IsNonSpanOutBuffer(compilation, parameter)) { - generator.AppendLine($"using var {argName} = CommandSerialization.GetWritableRegion(processor.GetBufferRange({index}));"); + generator.AppendLine($"using var {argName} = CommandSerialization.GetWritableRegion(processor.GetBufferRange({outArgIndex++}));"); argName = $"out {GenerateSpanCastElement0(canonicalTypeName, $"{argName}.Memory.Span")}"; } @@ -302,7 +304,7 @@ namespace Ryujinx.Horizon.Generators.Hipc switch (argType) { case CommandArgType.InArgument: - value = $"CommandSerialization.DeserializeArg<{canonicalTypeName}>(inRawData, processor.GetInArgOffset({index}))"; + value = $"CommandSerialization.DeserializeArg<{canonicalTypeName}>(inRawData, processor.GetInArgOffset({inArgIndex++}))"; break; case CommandArgType.InCopyHandle: value = $"CommandSerialization.DeserializeCopyHandle(ref context, {inCopyHandleIndex++})"; diff --git a/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs b/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs index 672bba4e..e157fa56 100644 --- a/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs +++ b/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs @@ -42,7 +42,7 @@ namespace Ryujinx.Horizon.Prepo.Ipc return PrepoResult.PermissionDenied; } - ProcessPlayReport(PlayReportKind.Normal, pid, gameRoomBuffer, reportBuffer, Uid.Null); + ProcessPlayReport(PlayReportKind.Normal, gameRoomBuffer, reportBuffer, pid, Uid.Null); return Result.Success; } @@ -57,7 +57,7 @@ namespace Ryujinx.Horizon.Prepo.Ipc return PrepoResult.PermissionDenied; } - ProcessPlayReport(PlayReportKind.Normal, pid, gameRoomBuffer, reportBuffer, userId, true); + ProcessPlayReport(PlayReportKind.Normal, gameRoomBuffer, reportBuffer, pid, userId, true); return Result.Success; } @@ -107,25 +107,25 @@ namespace Ryujinx.Horizon.Prepo.Ipc } [CmifCommand(20100)] - public Result SaveSystemReport([Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan gameRoomBuffer, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan reportBuffer, [ClientProcessId] ulong pid) + public Result SaveSystemReport([Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan gameRoomBuffer, Sdk.Ncm.ApplicationId applicationId, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan reportBuffer) { if ((_permissionLevel & PrepoServicePermissionLevel.System) != 0) { return PrepoResult.PermissionDenied; } - return ProcessPlayReport(PlayReportKind.System, pid, gameRoomBuffer, reportBuffer, Uid.Null); + return ProcessPlayReport(PlayReportKind.System, gameRoomBuffer, reportBuffer, 0, Uid.Null, false, applicationId); } [CmifCommand(20101)] - public Result SaveSystemReportWithUser(Uid userId, [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan gameRoomBuffer, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan reportBuffer, [ClientProcessId] ulong pid) + public Result SaveSystemReportWithUser(Uid userId, [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan gameRoomBuffer, Sdk.Ncm.ApplicationId applicationId, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan reportBuffer) { if ((_permissionLevel & PrepoServicePermissionLevel.System) != 0) { return PrepoResult.PermissionDenied; } - return ProcessPlayReport(PlayReportKind.System, pid, gameRoomBuffer, reportBuffer, userId, true); + return ProcessPlayReport(PlayReportKind.System, gameRoomBuffer, reportBuffer, 0, userId, true, applicationId); } [CmifCommand(40100)] // 2.0.0+ @@ -164,7 +164,7 @@ namespace Ryujinx.Horizon.Prepo.Ipc return PrepoResult.PermissionDenied; } - private static Result ProcessPlayReport(PlayReportKind playReportKind, ulong pid, ReadOnlySpan gameRoomBuffer, ReadOnlySpan reportBuffer, Uid userId, bool withUserId = false) + private static Result ProcessPlayReport(PlayReportKind playReportKind, ReadOnlySpan gameRoomBuffer, ReadOnlySpan reportBuffer, ulong pid, Uid userId, bool withUserId = false, Sdk.Ncm.ApplicationId applicationId = default) { if (withUserId) { @@ -191,16 +191,23 @@ namespace Ryujinx.Horizon.Prepo.Ipc return PrepoResult.InvalidBufferSize; } - // NOTE: The service calls arp:r using the pid to get the application id, if it fails PrepoResult.InvalidPid is returned. - // Reports are stored internally and an event is signaled to transmit them. - StringBuilder builder = new(); MessagePackObject deserializedReport = MessagePackSerializer.UnpackMessagePackObject(reportBuffer.ToArray()); builder.AppendLine(); builder.AppendLine("PlayReport log:"); builder.AppendLine($" Kind: {playReportKind}"); - builder.AppendLine($" Pid: {pid}"); + + // NOTE: The service calls arp:r using the pid to get the application id, if it fails PrepoResult.InvalidPid is returned. + // Reports are stored internally and an event is signaled to transmit them. + if (pid != 0) + { + builder.AppendLine($" Pid: {pid}"); + } + else + { + builder.AppendLine($" ApplicationId: {applicationId}"); + } if (!userId.IsNull) { diff --git a/Ryujinx.Horizon/Sdk/Account/Uid.cs b/Ryujinx.Horizon/Sdk/Account/Uid.cs index a0a39978..5aad0463 100644 --- a/Ryujinx.Horizon/Sdk/Account/Uid.cs +++ b/Ryujinx.Horizon/Sdk/Account/Uid.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; namespace Ryujinx.Horizon.Sdk.Account { [StructLayout(LayoutKind.Sequential)] - public readonly record struct Uid + readonly record struct Uid { public readonly long High; public readonly long Low; diff --git a/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs b/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs new file mode 100644 index 00000000..37b4cbfb --- /dev/null +++ b/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs @@ -0,0 +1,52 @@ +namespace Ryujinx.Horizon.Sdk.Ncm +{ + readonly struct ApplicationId + { + public readonly ulong Id; + + public static int Length => sizeof(ulong); + + public static ApplicationId First => new(0x0100000000010000); + + public static ApplicationId Last => new(0x01FFFFFFFFFFFFFF); + + public static ApplicationId Invalid => new(0); + + public bool IsValid => Id >= First.Id && Id <= Last.Id; + + public ApplicationId(ulong id) + { + Id = id; + } + + public override bool Equals(object obj) + { + return obj is ApplicationId applicationId && applicationId.Equals(this); + } + + public bool Equals(ApplicationId other) + { + return other.Id == Id; + } + + public override int GetHashCode() + { + return Id.GetHashCode(); + } + + public static bool operator ==(ApplicationId lhs, ApplicationId rhs) + { + return lhs.Equals(rhs); + } + + public static bool operator !=(ApplicationId lhs, ApplicationId rhs) + { + return !lhs.Equals(rhs); + } + + public override string ToString() + { + return $"0x{Id:x}"; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Horizon/Sdk/Prepo/IPrepoService.cs b/Ryujinx.Horizon/Sdk/Prepo/IPrepoService.cs index f61ee61b..042cb400 100644 --- a/Ryujinx.Horizon/Sdk/Prepo/IPrepoService.cs +++ b/Ryujinx.Horizon/Sdk/Prepo/IPrepoService.cs @@ -12,8 +12,8 @@ namespace Ryujinx.Horizon.Sdk.Prepo Result RequestImmediateTransmission(); Result GetTransmissionStatus(out int status); Result GetSystemSessionId(out ulong systemSessionId); - Result SaveSystemReport(ReadOnlySpan gameRoomBuffer, ReadOnlySpan reportBuffer, ulong pid); - Result SaveSystemReportWithUser(Uid userId, ReadOnlySpan gameRoomBuffer, ReadOnlySpan reportBuffer, ulong pid); + Result SaveSystemReport(ReadOnlySpan gameRoomBuffer, Ncm.ApplicationId applicationId, ReadOnlySpan reportBuffer); + Result SaveSystemReportWithUser(Uid userId, ReadOnlySpan gameRoomBuffer, Ncm.ApplicationId applicationId, ReadOnlySpan reportBuffer); Result IsUserAgreementCheckEnabled(out bool enabled); Result SetUserAgreementCheckEnabled(bool enabled); } diff --git a/Ryujinx.Horizon/Sdk/Sm/ServiceName.cs b/Ryujinx.Horizon/Sdk/Sm/ServiceName.cs index dbb30078..9b7fae3f 100644 --- a/Ryujinx.Horizon/Sdk/Sm/ServiceName.cs +++ b/Ryujinx.Horizon/Sdk/Sm/ServiceName.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Horizon.Sdk.Sm { public static ServiceName Invalid { get; } = new ServiceName(0); - public bool IsInvalid => Packed == 0; + public bool IsValid => Packed != 0; public int Length => sizeof(ulong);