33e673ceb8
* fatal: Implement Service This PR adds a basic implementation of fatal service, guest processes call it when there is something wrong. But since we can already have all informations by debugging it's not really useful. In any case, that's avoid an unimplemented service exception. Structs/Enum are based on Atmosphère source code. After logs the error report, I call SvcBreak. Feedbacks are welcome on this, since some guests calls it right after fatal service so I can remove it if needed. * Addresses gdkchan feedback
147 lines
No EOL
6.7 KiB
C#
147 lines
No EOL
6.7 KiB
C#
using Ryujinx.Common.Logging;
|
|
using Ryujinx.HLE.HOS.Services.Fatal.Types;
|
|
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) { }
|
|
|
|
[CommandHipc(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);
|
|
}
|
|
|
|
[CommandHipc(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);
|
|
}
|
|
|
|
[CommandHipc(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)
|
|
{
|
|
StringBuilder errorReport = new StringBuilder();
|
|
|
|
errorReport.AppendLine();
|
|
errorReport.AppendLine("ErrorReport log:");
|
|
|
|
errorReport.AppendLine($"\tTitleId: {context.Device.Application.TitleId:x16}");
|
|
errorReport.AppendLine($"\tPid: {pid}");
|
|
errorReport.AppendLine($"\tResultCode: {((int)resultCode & 0x1FF) + 2000}-{((int)resultCode >> 9) & 0x3FFF:d4}");
|
|
errorReport.AppendLine($"\tFatalPolicy: {fatalPolicy}");
|
|
|
|
if (cpuContext != null)
|
|
{
|
|
errorReport.AppendLine("CPU Context:");
|
|
|
|
if (context.Device.Application.TitleIs64Bit)
|
|
{
|
|
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:");
|
|
|
|
for (int i = 0; i < cpuContext64.StackTraceSize; i++)
|
|
{
|
|
errorReport.AppendLine($"\t\t0x{cpuContext64.StackTrace[i]:x16}");
|
|
}
|
|
}
|
|
|
|
errorReport.AppendLine("\tRegisters:");
|
|
|
|
for (int i = 0; i < cpuContext64.X.Length; i++)
|
|
{
|
|
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{cpuContext64.X[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:");
|
|
|
|
for (int i = 0; i < cpuContext32.StackTraceSize; i++)
|
|
{
|
|
errorReport.AppendLine($"\t\t0x{cpuContext32.StackTrace[i]:x16}");
|
|
}
|
|
}
|
|
|
|
errorReport.AppendLine("\tRegisters:");
|
|
|
|
for (int i = 0; i < cpuContext32.X.Length; i++)
|
|
{
|
|
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{cpuContext32.X[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;
|
|
}
|
|
}
|
|
} |