Files
ryujinx/src/Ryujinx.HLE/HOS/Services/Fatal/IService.cs
Babib3l b62c58c2fe River : HLE: Make process identity explicit for service metadata resolution (#100)
This PR is the first in a batch of structural changes to Ryujinx.

**Changes**

- Added `ProcessIdentity` and `ProcessKind` to describe loaded programs by:
  - PID, program ID, application ID, program index, display version, process kind
- Stored identity metadata on `ProcessResult`.
- Added PID-based process lookup helpers to `ProcessLoader`.
- Updated HLE services to resolve application metadata through the caller PID instead of `Processes.ActiveApplication`.
- Added PTC/JIT disk cache initialization logging with PID, title ID, display version, selector, and enabled state.
- Added `ClientProcessId` property to ServiceCtx (/src/Ryujinx.HLE/HOS/ServiceCtx.cs) that uses the handle descriptor PId when available, falling back to `Process.Pid`.
- Updated 15 HLE service files to use `context.ClientProcessId` instead of `context.Process.Pid` for client process access, ensuring services correctly identify the calling process even when invoked via IPC with handle descriptors.

These changes make service metadata resolution more explicit and prepare the emulator for other structural changes later on.

Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/100
2026-05-25 12:08:31 +00:00

158 lines
7.0 KiB
C#

using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Fatal.Types;
using Ryujinx.HLE.Loaders.Processes;
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Ryujinx.HLE.HOS.Services.Fatal
{
[Service("fatal:u")]
class IService : IpcService
{
public IService(ServiceCtx context) { }
[CommandCmif(0)]
// ThrowFatal(u64 result_code, u64 pid)
public ResultCode ThrowFatal(ServiceCtx context)
{
ResultCode resultCode = (ResultCode)context.RequestData.ReadUInt64();
ulong pid = context.Request.HandleDesc.PId;
return ThrowFatalWithCpuContextImpl(context, resultCode, pid, FatalPolicy.ErrorReportAndErrorScreen, null);
}
[CommandCmif(1)]
// ThrowFatalWithPolicy(u64 result_code, u32 fatal_policy, u64 pid)
public ResultCode ThrowFatalWithPolicy(ServiceCtx context)
{
ResultCode resultCode = (ResultCode)context.RequestData.ReadUInt64();
FatalPolicy fatalPolicy = (FatalPolicy)context.RequestData.ReadUInt32();
ulong pid = context.Request.HandleDesc.PId;
return ThrowFatalWithCpuContextImpl(context, resultCode, pid, fatalPolicy, null);
}
[CommandCmif(2)]
// ThrowFatalWithCpuContext(u64 result_code, u32 fatal_policy, u64 pid, buffer<bytes, 0x15> cpu_context)
public ResultCode ThrowFatalWithCpuContext(ServiceCtx context)
{
ResultCode resultCode = (ResultCode)context.RequestData.ReadUInt64();
FatalPolicy fatalPolicy = (FatalPolicy)context.RequestData.ReadUInt32();
ulong pid = context.Request.HandleDesc.PId;
ulong cpuContextPosition = context.Request.SendBuff[0].Position;
ulong cpuContextSize = context.Request.SendBuff[0].Size;
ReadOnlySpan<byte> cpuContextData = context.Memory.GetSpan(cpuContextPosition, (int)cpuContextSize);
return ThrowFatalWithCpuContextImpl(context, resultCode, pid, fatalPolicy, cpuContextData);
}
private ResultCode ThrowFatalWithCpuContextImpl(ServiceCtx context, ResultCode resultCode, ulong pid, FatalPolicy fatalPolicy, ReadOnlySpan<byte> cpuContext)
{
ProcessResult process = context.Device.Processes.GetProcess(pid);
StringBuilder errorReport = new();
errorReport.AppendLine();
errorReport.AppendLine("ErrorReport log:");
errorReport.AppendLine($"\tTitleId: {process.ProgramIdText}");
errorReport.AppendLine($"\tPid: {pid}");
errorReport.AppendLine($"\tResultCode: {((int)resultCode & 0x1FF) + 2000}-{((int)resultCode >> 9) & 0x3FFF:d4}");
errorReport.AppendLine($"\tFatalPolicy: {fatalPolicy}");
if (!cpuContext.IsEmpty)
{
errorReport.AppendLine("CPU Context:");
if (process.Is64Bit)
{
CpuContext64 cpuContext64 = MemoryMarshal.Cast<byte, CpuContext64>(cpuContext)[0];
errorReport.AppendLine($"\tStartAddress: 0x{cpuContext64.StartAddress:x16}");
errorReport.AppendLine($"\tRegisterSetFlags: {cpuContext64.RegisterSetFlags}");
if (cpuContext64.StackTraceSize > 0)
{
errorReport.AppendLine("\tStackTrace:");
Span<ulong> stackTraceSpan = cpuContext64.StackTrace.AsSpan();
for (int i = 0; i < cpuContext64.StackTraceSize; i++)
{
errorReport.AppendLine($"\t\t0x{stackTraceSpan[i]:x16}");
}
}
errorReport.AppendLine("\tRegisters:");
Span<ulong> xSpan = cpuContext64.X.AsSpan();
for (int i = 0; i < xSpan.Length; i++)
{
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{xSpan[i]:x16}");
}
errorReport.AppendLine();
errorReport.AppendLine($"\t\tFP:\t0x{cpuContext64.FP:x16}");
errorReport.AppendLine($"\t\tLR:\t0x{cpuContext64.LR:x16}");
errorReport.AppendLine($"\t\tSP:\t0x{cpuContext64.SP:x16}");
errorReport.AppendLine($"\t\tPC:\t0x{cpuContext64.PC:x16}");
errorReport.AppendLine($"\t\tPState:\t0x{cpuContext64.PState:x16}");
errorReport.AppendLine($"\t\tAfsr0:\t0x{cpuContext64.Afsr0:x16}");
errorReport.AppendLine($"\t\tAfsr1:\t0x{cpuContext64.Afsr1:x16}");
errorReport.AppendLine($"\t\tEsr:\t0x{cpuContext64.Esr:x16}");
errorReport.AppendLine($"\t\tFar:\t0x{cpuContext64.Far:x16}");
}
else
{
CpuContext32 cpuContext32 = MemoryMarshal.Cast<byte, CpuContext32>(cpuContext)[0];
errorReport.AppendLine($"\tStartAddress: 0x{cpuContext32.StartAddress:16}");
errorReport.AppendLine($"\tRegisterSetFlags: {cpuContext32.RegisterSetFlags}");
if (cpuContext32.StackTraceSize > 0)
{
errorReport.AppendLine("\tStackTrace:");
Span<uint> stackTraceSpan = cpuContext32.StackTrace.AsSpan();
for (int i = 0; i < cpuContext32.StackTraceSize; i++)
{
errorReport.AppendLine($"\t\t0x{stackTraceSpan[i]:x16}");
}
}
errorReport.AppendLine("\tRegisters:");
Span<uint> xSpan = cpuContext32.X.AsSpan();
for (int i = 0; i < xSpan.Length; i++)
{
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{xSpan[i]:x16}");
}
errorReport.AppendLine();
errorReport.AppendLine($"\t\tFP:\t0x{cpuContext32.FP:x16}");
errorReport.AppendLine($"\t\tFP:\t0x{cpuContext32.IP:x16}");
errorReport.AppendLine($"\t\tSP:\t0x{cpuContext32.SP:x16}");
errorReport.AppendLine($"\t\tLR:\t0x{cpuContext32.LR:x16}");
errorReport.AppendLine($"\t\tPC:\t0x{cpuContext32.PC:x16}");
errorReport.AppendLine($"\t\tPState:\t0x{cpuContext32.PState:x16}");
errorReport.AppendLine($"\t\tAfsr0:\t0x{cpuContext32.Afsr0:x16}");
errorReport.AppendLine($"\t\tAfsr1:\t0x{cpuContext32.Afsr1:x16}");
errorReport.AppendLine($"\t\tEsr:\t0x{cpuContext32.Esr:x16}");
errorReport.AppendLine($"\t\tFar:\t0x{cpuContext32.Far:x16}");
}
}
Logger.Info?.Print(LogClass.ServiceFatal, errorReport.ToString());
context.Device.System.KernelContext.Syscall.Break((ulong)resultCode);
return ResultCode.Success;
}
}
}