diff --git a/Ryujinx.Common/Logging/LogClass.cs b/Ryujinx.Common/Logging/LogClass.cs
index 20c8da3f81..2e936fc724 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 692d2b0b7d..6d663a4dec 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 0000000000..5c0b116bc3
--- /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 0000000000..24829a78af
--- /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 0000000000..fe55cf12b7
--- /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