mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-11-18 10:16:40 +00:00
fatal: Implement Service (#3573)
* 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
This commit is contained in:
parent
9c2500de5f
commit
33e673ceb8
5 changed files with 199 additions and 1 deletions
|
@ -30,6 +30,7 @@ namespace Ryujinx.Common.Logging
|
||||||
ServiceBsd,
|
ServiceBsd,
|
||||||
ServiceBtm,
|
ServiceBtm,
|
||||||
ServiceCaps,
|
ServiceCaps,
|
||||||
|
ServiceFatal,
|
||||||
ServiceFriend,
|
ServiceFriend,
|
||||||
ServiceFs,
|
ServiceFs,
|
||||||
ServiceHid,
|
ServiceHid,
|
||||||
|
|
|
@ -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")]
|
[Service("fatal:u")]
|
||||||
class IService : IpcService
|
class IService : IpcService
|
||||||
{
|
{
|
||||||
public IService(ServiceCtx context) { }
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
25
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext32.cs
Normal file
25
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext32.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
24
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext64.cs
Normal file
24
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext64.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
9
Ryujinx.HLE/HOS/Services/Fatal/Types/FatalPolicy.cs
Normal file
9
Ryujinx.HLE/HOS/Services/Fatal/Types/FatalPolicy.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Fatal.Types
|
||||||
|
{
|
||||||
|
enum FatalPolicy
|
||||||
|
{
|
||||||
|
ErrorReportAndErrorScreen,
|
||||||
|
ErrorReport,
|
||||||
|
ErrorScreen
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue