aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Common/Logging/LogClass.cs1
-rw-r--r--Ryujinx.HLE/HOS/Services/Fatal/IService.cs141
-rw-r--r--Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext32.cs25
-rw-r--r--Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext64.cs24
-rw-r--r--Ryujinx.HLE/HOS/Services/Fatal/Types/FatalPolicy.cs9
5 files changed, 199 insertions, 1 deletions
diff --git a/Ryujinx.Common/Logging/LogClass.cs b/Ryujinx.Common/Logging/LogClass.cs
index 20c8da3f..2e936fc7 100644
--- a/Ryujinx.Common/Logging/LogClass.cs
+++ b/Ryujinx.Common/Logging/LogClass.cs
@@ -30,6 +30,7 @@ namespace Ryujinx.Common.Logging
ServiceBsd,
ServiceBtm,
ServiceCaps,
+ ServiceFatal,
ServiceFriend,
ServiceFs,
ServiceHid,
diff --git a/Ryujinx.HLE/HOS/Services/Fatal/IService.cs b/Ryujinx.HLE/HOS/Services/Fatal/IService.cs
index 692d2b0b..6d663a4d 100644
--- a/Ryujinx.HLE/HOS/Services/Fatal/IService.cs
+++ b/Ryujinx.HLE/HOS/Services/Fatal/IService.cs
@@ -1,8 +1,147 @@
-namespace Ryujinx.HLE.HOS.Services.Fatal
+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;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext32.cs b/Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext32.cs
new file mode 100644
index 00000000..5c0b116b
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext32.cs
@@ -0,0 +1,25 @@
+using Ryujinx.Common.Memory;
+
+namespace Ryujinx.HLE.HOS.Services.Fatal.Types
+{
+ public struct CpuContext32
+ {
+ public Array11<uint> X;
+ public uint FP;
+ public uint IP;
+ public uint SP;
+ public uint LR;
+ public uint PC;
+
+ public uint PState;
+ public uint Afsr0;
+ public uint Afsr1;
+ public uint Esr;
+ public uint Far;
+
+ public Array32<uint> StackTrace;
+ public uint StackTraceSize;
+ public uint StartAddress;
+ public uint RegisterSetFlags;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext64.cs b/Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext64.cs
new file mode 100644
index 00000000..24829a78
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext64.cs
@@ -0,0 +1,24 @@
+using Ryujinx.Common.Memory;
+
+namespace Ryujinx.HLE.HOS.Services.Fatal.Types
+{
+ public struct CpuContext64
+ {
+ public Array29<ulong> X;
+ public ulong FP;
+ public ulong LR;
+ public ulong SP;
+ public ulong PC;
+
+ public ulong PState;
+ public ulong Afsr0;
+ public ulong Afsr1;
+ public ulong Esr;
+ public ulong Far;
+
+ public Array32<ulong> StackTrace;
+ public ulong StartAddress;
+ public ulong RegisterSetFlags;
+ public uint StackTraceSize;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Fatal/Types/FatalPolicy.cs b/Ryujinx.HLE/HOS/Services/Fatal/Types/FatalPolicy.cs
new file mode 100644
index 00000000..fe55cf12
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Fatal/Types/FatalPolicy.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.HLE.HOS.Services.Fatal.Types
+{
+ enum FatalPolicy
+ {
+ ErrorReportAndErrorScreen,
+ ErrorReport,
+ ErrorScreen
+ }
+} \ No newline at end of file