diff --git a/Ryujinx.Common/Memory/SpanReader.cs b/Ryujinx.Common/Memory/SpanReader.cs
new file mode 100644
index 0000000000..e46649e1c3
--- /dev/null
+++ b/Ryujinx.Common/Memory/SpanReader.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Common.Memory
+{
+    public ref struct SpanReader
+    {
+        private ReadOnlySpan<byte> _input;
+
+        public int Length => _input.Length;
+
+        public SpanReader(ReadOnlySpan<byte> input)
+        {
+            _input = input;
+        }
+
+        public T Read<T>() where T : unmanaged
+        {
+            T value = MemoryMarshal.Cast<byte, T>(_input)[0];
+
+            _input = _input.Slice(Unsafe.SizeOf<T>());
+
+            return value;
+        }
+
+        public ReadOnlySpan<byte> GetSpan(int size)
+        {
+            ReadOnlySpan<byte> data = _input.Slice(0, size);
+
+            _input = _input.Slice(size);
+
+            return data;
+        }
+
+        public T ReadAt<T>(int offset) where T : unmanaged
+        {
+            return MemoryMarshal.Cast<byte, T>(_input.Slice(offset))[0];
+        }
+
+        public ReadOnlySpan<byte> GetSpanAt(int offset, int size)
+        {
+            return _input.Slice(offset, size);
+        }
+
+        public void Skip(int size)
+        {
+            _input = _input.Slice(size);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Common/Memory/SpanWriter.cs b/Ryujinx.Common/Memory/SpanWriter.cs
new file mode 100644
index 0000000000..5c35569dd4
--- /dev/null
+++ b/Ryujinx.Common/Memory/SpanWriter.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Common.Memory
+{
+    public ref struct SpanWriter
+    {
+        private Span<byte> _output;
+
+        public int Length => _output.Length;
+
+        public SpanWriter(Span<byte> output)
+        {
+            _output = output;
+        }
+
+        public void Write<T>(T value) where T : unmanaged
+        {
+            MemoryMarshal.Cast<byte, T>(_output)[0] = value;
+            _output = _output.Slice(Unsafe.SizeOf<T>());
+        }
+
+        public void Write(ReadOnlySpan<byte> data)
+        {
+            data.CopyTo(_output.Slice(0, data.Length));
+            _output = _output.Slice(data.Length);
+        }
+
+        public void WriteAt<T>(int offset, T value) where T : unmanaged
+        {
+            MemoryMarshal.Cast<byte, T>(_output.Slice(offset))[0] = value;
+        }
+
+        public void WriteAt(int offset, ReadOnlySpan<byte> data)
+        {
+            data.CopyTo(_output.Slice(offset, data.Length));
+        }
+
+        public void Skip(int size)
+        {
+            _output = _output.Slice(size);
+        }
+    }
+}
diff --git a/Ryujinx.Common/Utilities/BitfieldExtensions.cs b/Ryujinx.Common/Utilities/BitfieldExtensions.cs
new file mode 100644
index 0000000000..ca429944f6
--- /dev/null
+++ b/Ryujinx.Common/Utilities/BitfieldExtensions.cs
@@ -0,0 +1,57 @@
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Common.Utilities
+{
+    public static class BitfieldExtensions
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool Extract<T>(this T value, int lsb) where T : IBinaryInteger<T>
+        {
+            int bitSize = Unsafe.SizeOf<T>() * 8;
+            lsb &= bitSize - 1;
+
+            return !T.IsZero((value >>> lsb) & T.One);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static T Extract<T>(this T value, int lsb, int length) where T : IBinaryInteger<T>
+        {
+            int bitSize = Unsafe.SizeOf<T>() * 8;
+            lsb &= bitSize - 1;
+
+            return (value >>> lsb) & (~T.Zero >>> (bitSize - length));
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static T ExtractSx<T>(this T value, int lsb, int length) where T : IBinaryInteger<T>
+        {
+            int bitSize = Unsafe.SizeOf<T>() * 8;
+            int shift = lsb & (bitSize - 1);
+
+            return (value << (bitSize - (shift + length))) >> (bitSize - length);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static T Insert<T>(this T value, int lsb, bool toInsert) where T : IBinaryInteger<T>
+        {
+            int bitSize = Unsafe.SizeOf<T>() * 8;
+            lsb &= bitSize - 1;
+
+            T mask = T.One << lsb;
+
+            return (value & ~mask) | (toInsert ? mask : T.Zero);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static T Insert<T>(this T value, int lsb, int length, T toInsert) where T : IBinaryInteger<T>
+        {
+            int bitSize = Unsafe.SizeOf<T>() * 8;
+            lsb &= bitSize - 1;
+
+            T mask = (~T.Zero >>> (bitSize - length)) << lsb;
+
+            return (value & ~mask) | ((toInsert << lsb) & mask);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs b/Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs
deleted file mode 100644
index 79e0a5c0e9..0000000000
--- a/Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace Ryujinx.Graphics.Shader.Decoders
-{
-    static class BitfieldExtensions
-    {
-        public static bool Extract(this int value, int lsb)
-        {
-            return ((value >> lsb) & 1) != 0;
-        }
-
-        public static int Extract(this int value, int lsb, int length)
-        {
-            return (value >> lsb) & (int)(uint.MaxValue >> (32 - length));
-        }
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
index ab33da195b..6729f07702 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Graphics.Shader.Decoders;
+using Ryujinx.Common.Utilities;
 using Ryujinx.Graphics.Shader.IntermediateRepresentation;
 using System;
 
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
index b643262fcf..01f7f08add 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Graphics.Shader.Decoders;
+using Ryujinx.Common.Utilities;
 using System;
 using System.Runtime.InteropServices;
 
diff --git a/Ryujinx.Graphics.Vic/Types/BitfieldExtensions.cs b/Ryujinx.Graphics.Vic/Types/BitfieldExtensions.cs
deleted file mode 100644
index 06d0f00661..0000000000
--- a/Ryujinx.Graphics.Vic/Types/BitfieldExtensions.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System.Runtime.CompilerServices;
-
-namespace Ryujinx.Graphics.Vic.Types
-{
-    static class BitfieldExtensions
-    {
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool Extract(this int value, int lsb)
-        {
-            return ((value >> (lsb & 0x1f)) & 1) != 0;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static int Extract(this int value, int lsb, int length)
-        {
-            return (value >> (lsb & 0x1f)) & (int)(uint.MaxValue >> (32 - length));
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool Extract(this long value, int lsb)
-        {
-            return ((int)(value >> (lsb & 0x3f)) & 1) != 0;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static int Extract(this long value, int lsb, int length)
-        {
-            return (int)(value >> (lsb & 0x3f)) & (int)(uint.MaxValue >> (32 - length));
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static int ExtractSx(this long value, int lsb, int length)
-        {
-            int shift = lsb & 0x3f;
-
-            return (int)((value << (64 - (shift + length))) >> (64 - length));
-        }
-    }
-}
diff --git a/Ryujinx.Graphics.Vic/Types/BlendingSlotStruct.cs b/Ryujinx.Graphics.Vic/Types/BlendingSlotStruct.cs
index fc5d315e12..86da41d292 100644
--- a/Ryujinx.Graphics.Vic/Types/BlendingSlotStruct.cs
+++ b/Ryujinx.Graphics.Vic/Types/BlendingSlotStruct.cs
@@ -1,20 +1,22 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
 {
     struct BlendingSlotStruct
     {
         private long _word0;
         private long _word1;
 
-        public int AlphaK1 => _word0.Extract(0, 10);
-        public int AlphaK2 => _word0.Extract(16, 10);
-        public int SrcFactCMatchSelect => _word0.Extract(32, 3);
-        public int DstFactCMatchSelect => _word0.Extract(36, 3);
-        public int SrcFactAMatchSelect => _word0.Extract(40, 3);
-        public int DstFactAMatchSelect => _word0.Extract(44, 3);
-        public int OverrideR => _word1.Extract(66, 10);
-        public int OverrideG => _word1.Extract(76, 10);
-        public int OverrideB => _word1.Extract(86, 10);
-        public int OverrideA => _word1.Extract(96, 10);
+        public int AlphaK1 => (int)_word0.Extract(0, 10);
+        public int AlphaK2 => (int)_word0.Extract(16, 10);
+        public int SrcFactCMatchSelect => (int)_word0.Extract(32, 3);
+        public int DstFactCMatchSelect => (int)_word0.Extract(36, 3);
+        public int SrcFactAMatchSelect => (int)_word0.Extract(40, 3);
+        public int DstFactAMatchSelect => (int)_word0.Extract(44, 3);
+        public int OverrideR => (int)_word1.Extract(66, 10);
+        public int OverrideG => (int)_word1.Extract(76, 10);
+        public int OverrideB => (int)_word1.Extract(86, 10);
+        public int OverrideA => (int)_word1.Extract(96, 10);
         public bool UseOverrideR => _word1.Extract(108);
         public bool UseOverrideG => _word1.Extract(109);
         public bool UseOverrideB => _word1.Extract(110);
diff --git a/Ryujinx.Graphics.Vic/Types/ClearRectStruct.cs b/Ryujinx.Graphics.Vic/Types/ClearRectStruct.cs
index 2915404f6a..ae582a9200 100644
--- a/Ryujinx.Graphics.Vic/Types/ClearRectStruct.cs
+++ b/Ryujinx.Graphics.Vic/Types/ClearRectStruct.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
 {
     struct ClearRectStruct
     {
@@ -7,13 +9,13 @@
         private long _word1;
 #pragma warning restore CS0649
 
-        public int ClearRect0Left => _word0.Extract(0, 14);
-        public int ClearRect0Right => _word0.Extract(16, 14);
-        public int ClearRect0Top => _word0.Extract(32, 14);
-        public int ClearRect0Bottom => _word0.Extract(48, 14);
-        public int ClearRect1Left => _word1.Extract(64, 14);
-        public int ClearRect1Right => _word1.Extract(80, 14);
-        public int ClearRect1Top => _word1.Extract(96, 14);
-        public int ClearRect1Bottom => _word1.Extract(112, 14);
+        public int ClearRect0Left => (int)_word0.Extract(0, 14);
+        public int ClearRect0Right => (int)_word0.Extract(16, 14);
+        public int ClearRect0Top => (int)_word0.Extract(32, 14);
+        public int ClearRect0Bottom => (int)_word0.Extract(48, 14);
+        public int ClearRect1Left => (int)_word1.Extract(64, 14);
+        public int ClearRect1Right => (int)_word1.Extract(80, 14);
+        public int ClearRect1Top => (int)_word1.Extract(96, 14);
+        public int ClearRect1Bottom => (int)_word1.Extract(112, 14);
     }
 }
diff --git a/Ryujinx.Graphics.Vic/Types/LumaKeyStruct.cs b/Ryujinx.Graphics.Vic/Types/LumaKeyStruct.cs
index df5e647ed9..5d83bd7116 100644
--- a/Ryujinx.Graphics.Vic/Types/LumaKeyStruct.cs
+++ b/Ryujinx.Graphics.Vic/Types/LumaKeyStruct.cs
@@ -1,17 +1,19 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
 {
     struct LumaKeyStruct
     {
         private long _word0;
         private long _word1;
 
-        public int LumaCoeff0 => _word0.Extract(0, 20);
-        public int LumaCoeff1 => _word0.Extract(20, 20);
-        public int LumaCoeff2 => _word0.Extract(40, 20);
-        public int LumaRShift => _word0.Extract(60, 4);
-        public int LumaCoeff3 => _word1.Extract(64, 20);
-        public int LumaKeyLower => _word1.Extract(84, 10);
-        public int LumaKeyUpper => _word1.Extract(94, 10);
+        public int LumaCoeff0 => (int)_word0.Extract(0, 20);
+        public int LumaCoeff1 => (int)_word0.Extract(20, 20);
+        public int LumaCoeff2 => (int)_word0.Extract(40, 20);
+        public int LumaRShift => (int)_word0.Extract(60, 4);
+        public int LumaCoeff3 => (int)_word1.Extract(64, 20);
+        public int LumaKeyLower => (int)_word1.Extract(84, 10);
+        public int LumaKeyUpper => (int)_word1.Extract(94, 10);
         public bool LumaKeyEnabled => _word1.Extract(104);
     }
 }
diff --git a/Ryujinx.Graphics.Vic/Types/MatrixStruct.cs b/Ryujinx.Graphics.Vic/Types/MatrixStruct.cs
index b9dcd8ff43..c0a4c34eea 100644
--- a/Ryujinx.Graphics.Vic/Types/MatrixStruct.cs
+++ b/Ryujinx.Graphics.Vic/Types/MatrixStruct.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
 {
     struct MatrixStruct
     {
@@ -7,19 +9,19 @@
         private long _word2;
         private long _word3;
 
-        public int MatrixCoeff00 => _word0.ExtractSx(0, 20);
-        public int MatrixCoeff10 => _word0.ExtractSx(20, 20);
-        public int MatrixCoeff20 => _word0.ExtractSx(40, 20);
-        public int MatrixRShift => _word0.Extract(60, 4);
-        public int MatrixCoeff01 => _word1.ExtractSx(64, 20);
-        public int MatrixCoeff11 => _word1.ExtractSx(84, 20);
-        public int MatrixCoeff21 => _word1.ExtractSx(104, 20);
+        public int MatrixCoeff00 => (int)_word0.ExtractSx(0, 20);
+        public int MatrixCoeff10 => (int)_word0.ExtractSx(20, 20);
+        public int MatrixCoeff20 => (int)_word0.ExtractSx(40, 20);
+        public int MatrixRShift => (int)_word0.Extract(60, 4);
+        public int MatrixCoeff01 => (int)_word1.ExtractSx(64, 20);
+        public int MatrixCoeff11 => (int)_word1.ExtractSx(84, 20);
+        public int MatrixCoeff21 => (int)_word1.ExtractSx(104, 20);
         public bool MatrixEnable => _word1.Extract(127);
-        public int MatrixCoeff02 => _word2.ExtractSx(128, 20);
-        public int MatrixCoeff12 => _word2.ExtractSx(148, 20);
-        public int MatrixCoeff22 => _word2.ExtractSx(168, 20);
-        public int MatrixCoeff03 => _word3.ExtractSx(192, 20);
-        public int MatrixCoeff13 => _word3.ExtractSx(212, 20);
-        public int MatrixCoeff23 => _word3.ExtractSx(232, 20);
+        public int MatrixCoeff02 => (int)_word2.ExtractSx(128, 20);
+        public int MatrixCoeff12 => (int)_word2.ExtractSx(148, 20);
+        public int MatrixCoeff22 => (int)_word2.ExtractSx(168, 20);
+        public int MatrixCoeff03 => (int)_word3.ExtractSx(192, 20);
+        public int MatrixCoeff13 => (int)_word3.ExtractSx(212, 20);
+        public int MatrixCoeff23 => (int)_word3.ExtractSx(232, 20);
     }
 }
diff --git a/Ryujinx.Graphics.Vic/Types/OutputConfig.cs b/Ryujinx.Graphics.Vic/Types/OutputConfig.cs
index 29633297d7..7b86699420 100644
--- a/Ryujinx.Graphics.Vic/Types/OutputConfig.cs
+++ b/Ryujinx.Graphics.Vic/Types/OutputConfig.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
 {
     struct OutputConfig
     {
@@ -7,19 +9,19 @@
         private long _word1;
 #pragma warning restore CS0649
 
-        public int AlphaFillMode => _word0.Extract(0, 3);
-        public int AlphaFillSlot => _word0.Extract(3, 3);
-        public int BackgroundAlpha => _word0.Extract(6, 10);
-        public int BackgroundR => _word0.Extract(16, 10);
-        public int BackgroundG => _word0.Extract(26, 10);
-        public int BackgroundB => _word0.Extract(36, 10);
-        public int RegammaMode => _word0.Extract(46, 2);
+        public int AlphaFillMode => (int)_word0.Extract(0, 3);
+        public int AlphaFillSlot => (int)_word0.Extract(3, 3);
+        public int BackgroundAlpha => (int)_word0.Extract(6, 10);
+        public int BackgroundR => (int)_word0.Extract(16, 10);
+        public int BackgroundG => (int)_word0.Extract(26, 10);
+        public int BackgroundB => (int)_word0.Extract(36, 10);
+        public int RegammaMode => (int)_word0.Extract(46, 2);
         public bool OutputFlipX => _word0.Extract(48);
         public bool OutputFlipY => _word0.Extract(49);
         public bool OutputTranspose => _word0.Extract(50);
-        public int TargetRectLeft => _word1.Extract(64, 14);
-        public int TargetRectRight => _word1.Extract(80, 14);
-        public int TargetRectTop => _word1.Extract(96, 14);
-        public int TargetRectBottom => _word1.Extract(112, 14);
+        public int TargetRectLeft => (int)_word1.Extract(64, 14);
+        public int TargetRectRight => (int)_word1.Extract(80, 14);
+        public int TargetRectTop => (int)_word1.Extract(96, 14);
+        public int TargetRectBottom => (int)_word1.Extract(112, 14);
     }
 }
diff --git a/Ryujinx.Graphics.Vic/Types/OutputSurfaceConfig.cs b/Ryujinx.Graphics.Vic/Types/OutputSurfaceConfig.cs
index 0a29b7b83a..6a8b21e139 100644
--- a/Ryujinx.Graphics.Vic/Types/OutputSurfaceConfig.cs
+++ b/Ryujinx.Graphics.Vic/Types/OutputSurfaceConfig.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
 {
     struct OutputSurfaceConfig
     {
@@ -8,15 +10,15 @@
 #pragma warning restore CS0649
 
         public PixelFormat OutPixelFormat => (PixelFormat)_word0.Extract(0, 7);
-        public int OutChromaLocHoriz => _word0.Extract(7, 2);
-        public int OutChromaLocVert => _word0.Extract(9, 2);
-        public int OutBlkKind => _word0.Extract(11, 4);
-        public int OutBlkHeight => _word0.Extract(15, 4);
-        public int OutSurfaceWidth => _word0.Extract(32, 14);
-        public int OutSurfaceHeight => _word0.Extract(46, 14);
-        public int OutLumaWidth => _word1.Extract(64, 14);
-        public int OutLumaHeight => _word1.Extract(78, 14);
-        public int OutChromaWidth => _word1.Extract(96, 14);
-        public int OutChromaHeight => _word1.Extract(110, 14);
+        public int OutChromaLocHoriz => (int)_word0.Extract(7, 2);
+        public int OutChromaLocVert => (int)_word0.Extract(9, 2);
+        public int OutBlkKind => (int)_word0.Extract(11, 4);
+        public int OutBlkHeight => (int)_word0.Extract(15, 4);
+        public int OutSurfaceWidth => (int)_word0.Extract(32, 14);
+        public int OutSurfaceHeight => (int)_word0.Extract(46, 14);
+        public int OutLumaWidth => (int)_word1.Extract(64, 14);
+        public int OutLumaHeight => (int)_word1.Extract(78, 14);
+        public int OutChromaWidth => (int)_word1.Extract(96, 14);
+        public int OutChromaHeight => (int)_word1.Extract(110, 14);
     }
 }
diff --git a/Ryujinx.Graphics.Vic/Types/PipeConfig.cs b/Ryujinx.Graphics.Vic/Types/PipeConfig.cs
index cae04536f3..76720eb1c1 100644
--- a/Ryujinx.Graphics.Vic/Types/PipeConfig.cs
+++ b/Ryujinx.Graphics.Vic/Types/PipeConfig.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
 {
     struct PipeConfig
     {
@@ -7,7 +9,7 @@
         private long _word1;
 #pragma warning restore CS0169, CS0649
 
-        public int DownsampleHoriz => _word0.Extract(0, 11);
-        public int DownsampleVert => _word0.Extract(16, 11);
+        public int DownsampleHoriz => (int)_word0.Extract(0, 11);
+        public int DownsampleVert => (int)_word0.Extract(16, 11);
     }
 }
diff --git a/Ryujinx.Graphics.Vic/Types/SlotConfig.cs b/Ryujinx.Graphics.Vic/Types/SlotConfig.cs
index 373e76f697..aba61add3f 100644
--- a/Ryujinx.Graphics.Vic/Types/SlotConfig.cs
+++ b/Ryujinx.Graphics.Vic/Types/SlotConfig.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
 {
     struct SlotConfig
     {
@@ -28,36 +30,36 @@
         public bool PpMotionFieldEnable => _word0.Extract(14);
         public bool CombMotionFieldEnable => _word0.Extract(15);
         public FrameFormat FrameFormat => (FrameFormat)_word0.Extract(16, 4);
-        public int FilterLengthY => _word0.Extract(20, 2);
-        public int FilterLengthX => _word0.Extract(22, 2);
-        public int Panoramic => _word0.Extract(24, 12);
-        public int DetailFltClamp => _word0.Extract(58, 6);
-        public int FilterNoise => _word1.Extract(64, 10);
-        public int FilterDetail => _word1.Extract(74, 10);
-        public int ChromaNoise => _word1.Extract(84, 10);
-        public int ChromaDetail => _word1.Extract(94, 10);
+        public int FilterLengthY => (int)_word0.Extract(20, 2);
+        public int FilterLengthX => (int)_word0.Extract(22, 2);
+        public int Panoramic => (int)_word0.Extract(24, 12);
+        public int DetailFltClamp => (int)_word0.Extract(58, 6);
+        public int FilterNoise => (int)_word1.Extract(64, 10);
+        public int FilterDetail => (int)_word1.Extract(74, 10);
+        public int ChromaNoise => (int)_word1.Extract(84, 10);
+        public int ChromaDetail => (int)_word1.Extract(94, 10);
         public DeinterlaceMode DeinterlaceMode => (DeinterlaceMode)_word1.Extract(104, 4);
-        public int MotionAccumWeight => _word1.Extract(108, 3);
-        public int NoiseIir => _word1.Extract(111, 11);
-        public int LightLevel => _word1.Extract(122, 4);
-        public int SoftClampLow => _word2.Extract(128, 10);
-        public int SoftClampHigh => _word2.Extract(138, 10);
-        public int PlanarAlpha => _word2.Extract(160, 10);
+        public int MotionAccumWeight => (int)_word1.Extract(108, 3);
+        public int NoiseIir => (int)_word1.Extract(111, 11);
+        public int LightLevel => (int)_word1.Extract(122, 4);
+        public int SoftClampLow => (int)_word2.Extract(128, 10);
+        public int SoftClampHigh => (int)_word2.Extract(138, 10);
+        public int PlanarAlpha => (int)_word2.Extract(160, 10);
         public bool ConstantAlpha => _word2.Extract(170);
-        public int StereoInterleave => _word2.Extract(171, 3);
+        public int StereoInterleave => (int)_word2.Extract(171, 3);
         public bool ClipEnabled => _word2.Extract(174);
-        public int ClearRectMask => _word2.Extract(175, 8);
-        public int DegammaMode => _word2.Extract(183, 2);
+        public int ClearRectMask => (int)_word2.Extract(175, 8);
+        public int DegammaMode => (int)_word2.Extract(183, 2);
         public bool DecompressEnable => _word2.Extract(186);
-        public int DecompressCtbCount => _word3.Extract(192, 8);
-        public int DecompressZbcColor => _word3.Extract(200, 32);
-        public int SourceRectLeft => _word4.Extract(256, 30);
-        public int SourceRectRight => _word4.Extract(288, 30);
-        public int SourceRectTop => _word5.Extract(320, 30);
-        public int SourceRectBottom => _word5.Extract(352, 30);
-        public int DstRectLeft => _word6.Extract(384, 14);
-        public int DstRectRight => _word6.Extract(400, 14);
-        public int DstRectTop => _word6.Extract(416, 14);
-        public int DstRectBottom => _word6.Extract(432, 14);
+        public int DecompressCtbCount => (int)_word3.Extract(192, 8);
+        public int DecompressZbcColor => (int)_word3.Extract(200, 32);
+        public int SourceRectLeft => (int)_word4.Extract(256, 30);
+        public int SourceRectRight => (int)_word4.Extract(288, 30);
+        public int SourceRectTop => (int)_word5.Extract(320, 30);
+        public int SourceRectBottom => (int)_word5.Extract(352, 30);
+        public int DstRectLeft => (int)_word6.Extract(384, 14);
+        public int DstRectRight => (int)_word6.Extract(400, 14);
+        public int DstRectTop => (int)_word6.Extract(416, 14);
+        public int DstRectBottom => (int)_word6.Extract(432, 14);
     }
 }
diff --git a/Ryujinx.Graphics.Vic/Types/SlotSurfaceConfig.cs b/Ryujinx.Graphics.Vic/Types/SlotSurfaceConfig.cs
index 7396afa1d4..4492c85f98 100644
--- a/Ryujinx.Graphics.Vic/Types/SlotSurfaceConfig.cs
+++ b/Ryujinx.Graphics.Vic/Types/SlotSurfaceConfig.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
 {
     struct SlotSurfaceConfig
     {
@@ -6,16 +8,16 @@
         private long _word1;
 
         public PixelFormat SlotPixelFormat => (PixelFormat)_word0.Extract(0, 7);
-        public int SlotChromaLocHoriz => _word0.Extract(7, 2);
-        public int SlotChromaLocVert => _word0.Extract(9, 2);
-        public int SlotBlkKind => _word0.Extract(11, 4);
-        public int SlotBlkHeight => _word0.Extract(15, 4);
-        public int SlotCacheWidth => _word0.Extract(19, 3);
-        public int SlotSurfaceWidth => _word0.Extract(32, 14);
-        public int SlotSurfaceHeight => _word0.Extract(46, 14);
-        public int SlotLumaWidth => _word1.Extract(64, 14);
-        public int SlotLumaHeight => _word1.Extract(78, 14);
-        public int SlotChromaWidth => _word1.Extract(96, 14);
-        public int SlotChromaHeight => _word1.Extract(110, 14);
+        public int SlotChromaLocHoriz => (int)_word0.Extract(7, 2);
+        public int SlotChromaLocVert => (int)_word0.Extract(9, 2);
+        public int SlotBlkKind => (int)_word0.Extract(11, 4);
+        public int SlotBlkHeight => (int)_word0.Extract(15, 4);
+        public int SlotCacheWidth => (int)_word0.Extract(19, 3);
+        public int SlotSurfaceWidth => (int)_word0.Extract(32, 14);
+        public int SlotSurfaceHeight => (int)_word0.Extract(46, 14);
+        public int SlotLumaWidth => (int)_word1.Extract(64, 14);
+        public int SlotLumaHeight => (int)_word1.Extract(78, 14);
+        public int SlotChromaWidth => (int)_word1.Extract(96, 14);
+        public int SlotChromaHeight => (int)_word1.Extract(110, 14);
     }
 }
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index 288c308a08..a8b5be33d8 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -36,6 +36,7 @@ using Ryujinx.HLE.HOS.Services.SurfaceFlinger;
 using Ryujinx.HLE.HOS.Services.Time.Clock;
 using Ryujinx.HLE.HOS.SystemState;
 using Ryujinx.HLE.Loaders.Executables;
+using Ryujinx.Horizon;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -319,6 +320,42 @@ namespace Ryujinx.HLE.HOS
             ViServer = new ServerBase(KernelContext, "ViServerU");
             ViServerM = new ServerBase(KernelContext, "ViServerM");
             ViServerS = new ServerBase(KernelContext, "ViServerS");
+
+            StartNewServices();
+        }
+
+        private void StartNewServices()
+        {
+            var services = ServiceTable.GetServices(new HorizonOptions(Device.Configuration.IgnoreMissingServices));
+
+            foreach (var service in services)
+            {
+                const ProcessCreationFlags flags =
+                    ProcessCreationFlags.EnableAslr |
+                    ProcessCreationFlags.AddressSpace64Bit |
+                    ProcessCreationFlags.Is64Bit |
+                    ProcessCreationFlags.PoolPartitionSystem;
+
+                ProcessCreationInfo creationInfo = new ProcessCreationInfo("Service", 1, 0, 0x8000000, 1, flags, 0, 0);
+
+                int[] defaultCapabilities = new int[]
+                {
+                    0x030363F7,
+                    0x1FFFFFCF,
+                    0x207FFFEF,
+                    0x47E0060F,
+                    0x0048BFFF,
+                    0x01007FFF
+                };
+
+                // TODO:
+                // - Pass enough information (capabilities, process creation info, etc) on ServiceEntry for proper initialization.
+                // - Have the ThreadStart function take the syscall, address space and thread context parameters instead of passing them here.
+                KernelStatic.StartInitialProcess(KernelContext, creationInfo, defaultCapabilities, 44, () =>
+                {
+                    service.Start(KernelContext.Syscall, KernelStatic.GetCurrentProcess().CpuMemory, KernelStatic.GetCurrentThread().ThreadContext);
+                });
+            }
         }
 
         public void LoadKip(string kipPath)
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs b/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs
index a94b280f34..424bf788b1 100644
--- a/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Horizon.Common;
 using System.Diagnostics;
 using System.Threading;
 
@@ -16,24 +17,24 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
             _referenceCount = 1;
         }
 
-        public virtual KernelResult SetName(string name)
+        public virtual Result SetName(string name)
         {
             if (!KernelContext.AutoObjectNames.TryAdd(name, this))
             {
                 return KernelResult.InvalidState;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public static KernelResult RemoveName(KernelContext context, string name)
+        public static Result RemoveName(KernelContext context, string name)
         {
             if (!context.AutoObjectNames.TryRemove(name, out _))
             {
                 return KernelResult.NotFound;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         public static KAutoObject FindNamedObject(KernelContext context, string name)
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs b/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs
index 7caff21a0d..b1a602f189 100644
--- a/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs
@@ -1,5 +1,6 @@
 using Ryujinx.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Kernel.Common
@@ -159,7 +160,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
             }
         }
 
-        public KernelResult SetLimitValue(LimitableResource resource, long limit)
+        public Result SetLimitValue(LimitableResource resource, long limit)
         {
             int index = GetIndex(resource);
 
@@ -170,7 +171,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
                     _limit[index] = limit;
                     _peak[index] = _current[index];
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KernelInit.cs b/Ryujinx.HLE/HOS/Kernel/Common/KernelInit.cs
index 9829ae0379..efa2a480d8 100644
--- a/Ryujinx.HLE/HOS/Kernel/Common/KernelInit.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Common/KernelInit.cs
@@ -1,4 +1,5 @@
 using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Kernel.Common
@@ -21,9 +22,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
 
         public static void InitializeResourceLimit(KResourceLimit resourceLimit, MemorySize size)
         {
-            void EnsureSuccess(KernelResult result)
+            void EnsureSuccess(Result result)
             {
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     throw new InvalidOperationException($"Unexpected result \"{result}\".");
                 }
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KernelResult.cs b/Ryujinx.HLE/HOS/Kernel/Common/KernelResult.cs
deleted file mode 100644
index 357b01ea5d..0000000000
--- a/Ryujinx.HLE/HOS/Kernel/Common/KernelResult.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-namespace Ryujinx.HLE.HOS.Kernel.Common
-{
-    enum KernelResult
-    {
-        Success              = 0,
-        SessionCountExceeded = 0xe01,
-        InvalidCapability    = 0x1c01,
-        ThreadNotStarted     = 0x7201,
-        ThreadTerminating    = 0x7601,
-        InvalidSize          = 0xca01,
-        InvalidAddress       = 0xcc01,
-        OutOfResource        = 0xce01,
-        OutOfMemory          = 0xd001,
-        HandleTableFull      = 0xd201,
-        InvalidMemState      = 0xd401,
-        InvalidPermission    = 0xd801,
-        InvalidMemRange      = 0xdc01,
-        InvalidPriority      = 0xe001,
-        InvalidCpuCore       = 0xe201,
-        InvalidHandle        = 0xe401,
-        UserCopyFailed       = 0xe601,
-        InvalidCombination   = 0xe801,
-        TimedOut             = 0xea01,
-        Cancelled            = 0xec01,
-        MaximumExceeded      = 0xee01,
-        InvalidEnumValue     = 0xf001,
-        NotFound             = 0xf201,
-        InvalidThread        = 0xf401,
-        PortRemoteClosed     = 0xf601,
-        InvalidState         = 0xfa01,
-        ReservedValue        = 0xfc01,
-        PortClosed           = 0x10601,
-        ResLimitExceeded     = 0x10801,
-        OutOfVaSpace         = 0x20601,
-        CmdBufferTooSmall    = 0x20801
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs b/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
deleted file mode 100644
index d805a4e17f..0000000000
--- a/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.HOS.Kernel.Common
-{
-    readonly struct OnScopeExit : IDisposable
-    {
-        private readonly Action _action;
-        public OnScopeExit(Action action) => _action = action;
-        public void Dispose() => _action();
-    }
-}
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
index 5726299ba3..593d2c9d55 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
@@ -1,6 +1,6 @@
 using Ryujinx.Common;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.Horizon.Common;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Kernel.Ipc
@@ -20,38 +20,38 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             _exchangeBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
         }
 
-        public KernelResult AddSendBuffer(ulong src, ulong dst, ulong size, MemoryState state)
+        public Result AddSendBuffer(ulong src, ulong dst, ulong size, MemoryState state)
         {
             return Add(_sendBufferDescriptors, src, dst, size, state);
         }
 
-        public KernelResult AddReceiveBuffer(ulong src, ulong dst, ulong size, MemoryState state)
+        public Result AddReceiveBuffer(ulong src, ulong dst, ulong size, MemoryState state)
         {
             return Add(_receiveBufferDescriptors, src, dst, size, state);
         }
 
-        public KernelResult AddExchangeBuffer(ulong src, ulong dst, ulong size, MemoryState state)
+        public Result AddExchangeBuffer(ulong src, ulong dst, ulong size, MemoryState state)
         {
             return Add(_exchangeBufferDescriptors, src, dst, size, state);
         }
 
-        private KernelResult Add(List<KBufferDescriptor> list, ulong src, ulong dst, ulong size, MemoryState state)
+        private Result Add(List<KBufferDescriptor> list, ulong src, ulong dst, ulong size, MemoryState state)
         {
             if (list.Count < MaxInternalBuffersCount)
             {
                 list.Add(new KBufferDescriptor(src, dst, size, state));
 
-                return KernelResult.Success;
+                return Result.Success;
             }
 
             return KernelResult.OutOfMemory;
         }
 
-        public KernelResult CopyBuffersToClient(KPageTableBase memoryManager)
+        public Result CopyBuffersToClient(KPageTableBase memoryManager)
         {
-            KernelResult result = CopyToClient(memoryManager, _receiveBufferDescriptors);
+            Result result = CopyToClient(memoryManager, _receiveBufferDescriptors);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             return CopyToClient(memoryManager, _exchangeBufferDescriptors);
         }
 
-        private KernelResult CopyToClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
+        private Result CopyToClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
         {
             foreach (KBufferDescriptor desc in list)
             {
@@ -94,7 +94,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                         copySize = desc.Size;
                     }
 
-                    KernelResult result = memoryManager.CopyDataFromCurrentProcess(
+                    Result result = memoryManager.CopyDataFromCurrentProcess(
                         desc.ClientAddress,
                         copySize,
                         stateMask,
@@ -104,7 +104,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                         MemoryAttribute.None,
                         desc.ServerAddress);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         return result;
                     }
@@ -120,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                 if (clientEndAddrTruncated < clientEndAddrRounded &&
                     (clientAddrTruncated == clientAddrRounded || clientAddrTruncated < clientEndAddrTruncated))
                 {
-                    KernelResult result = memoryManager.CopyDataFromCurrentProcess(
+                    Result result = memoryManager.CopyDataFromCurrentProcess(
                         clientEndAddrTruncated,
                         clientEndAddr - clientEndAddrTruncated,
                         stateMask,
@@ -130,28 +130,28 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                         MemoryAttribute.None,
                         serverEndAddrTruncated);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         return result;
                     }
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult UnmapServerBuffers(KPageTableBase memoryManager)
+        public Result UnmapServerBuffers(KPageTableBase memoryManager)
         {
-            KernelResult result = UnmapServer(memoryManager, _sendBufferDescriptors);
+            Result result = UnmapServer(memoryManager, _sendBufferDescriptors);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             result = UnmapServer(memoryManager, _receiveBufferDescriptors);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -159,36 +159,36 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             return UnmapServer(memoryManager, _exchangeBufferDescriptors);
         }
 
-        private KernelResult UnmapServer(KPageTableBase memoryManager, List<KBufferDescriptor> list)
+        private Result UnmapServer(KPageTableBase memoryManager, List<KBufferDescriptor> list)
         {
             foreach (KBufferDescriptor descriptor in list)
             {
-                KernelResult result = memoryManager.UnmapNoAttributeIfStateEquals(
+                Result result = memoryManager.UnmapNoAttributeIfStateEquals(
                     descriptor.ServerAddress,
                     descriptor.Size,
                     descriptor.State);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     return result;
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult RestoreClientBuffers(KPageTableBase memoryManager)
+        public Result RestoreClientBuffers(KPageTableBase memoryManager)
         {
-            KernelResult result = RestoreClient(memoryManager, _sendBufferDescriptors);
+            Result result = RestoreClient(memoryManager, _sendBufferDescriptors);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             result = RestoreClient(memoryManager, _receiveBufferDescriptors);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -196,22 +196,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             return RestoreClient(memoryManager, _exchangeBufferDescriptors);
         }
 
-        private KernelResult RestoreClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
+        private Result RestoreClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
         {
             foreach (KBufferDescriptor descriptor in list)
             {
-                KernelResult result = memoryManager.UnmapIpcRestorePermission(
+                Result result = memoryManager.UnmapIpcRestorePermission(
                     descriptor.ClientAddress,
                     descriptor.Size,
                     descriptor.State);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     return result;
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
index 6e935077f6..eb7c5a4188 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
@@ -1,5 +1,6 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
 using System.Threading;
 
 namespace Ryujinx.HLE.HOS.Kernel.Ipc
@@ -19,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             _parent      = parent;
         }
 
-        public KernelResult Connect(out KClientSession clientSession)
+        public Result Connect(out KClientSession clientSession)
         {
             clientSession = null;
 
@@ -40,9 +41,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
 
             KSession session = new KSession(KernelContext, this);
 
-            KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession);
+            Result result = _parent.EnqueueIncomingSession(session.ServerSession);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 session.ClientSession.DecrementReferenceCount();
                 session.ServerSession.DecrementReferenceCount();
@@ -55,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             return result;
         }
 
-        public KernelResult ConnectLight(out KLightClientSession clientSession)
+        public Result ConnectLight(out KLightClientSession clientSession)
         {
             clientSession = null;
 
@@ -76,9 +77,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
 
             KLightSession session = new KLightSession(KernelContext);
 
-            KernelResult result = _parent.EnqueueIncomingLightSession(session.ServerSession);
+            Result result = _parent.EnqueueIncomingLightSession(session.ServerSession);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 session.ClientSession.DecrementReferenceCount();
                 session.ServerSession.DecrementReferenceCount();
@@ -128,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             }
         }
 
-        public new static KernelResult RemoveName(KernelContext context, string name)
+        public new static Result RemoveName(KernelContext context, string name)
         {
             KAutoObject foundObj = FindNamedObject(context, name);
 
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
index 7bbc3ba2cb..a24bcc3116 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
@@ -1,6 +1,7 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 
 namespace Ryujinx.HLE.HOS.Kernel.Ipc
 {
@@ -27,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             CreatorProcess.IncrementReferenceCount();
         }
 
-        public KernelResult SendSyncRequest(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
+        public Result SendSyncRequest(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
         {
             KThread currentThread = KernelStatic.GetCurrentThread();
 
@@ -36,13 +37,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             KernelContext.CriticalSection.Enter();
 
             currentThread.SignaledObj   = null;
-            currentThread.ObjSyncResult = KernelResult.Success;
+            currentThread.ObjSyncResult = Result.Success;
 
-            KernelResult result = _parent.ServerSession.EnqueueRequest(request);
+            Result result = _parent.ServerSession.EnqueueRequest(request);
 
             KernelContext.CriticalSection.Leave();
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 result = currentThread.ObjSyncResult;
             }
@@ -50,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             return result;
         }
 
-        public KernelResult SendAsyncRequest(KWritableEvent asyncEvent, ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
+        public Result SendAsyncRequest(KWritableEvent asyncEvent, ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
         {
             KThread currentThread = KernelStatic.GetCurrentThread();
 
@@ -58,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
 
             KernelContext.CriticalSection.Enter();
 
-            KernelResult result = _parent.ServerSession.EnqueueRequest(request);
+            Result result = _parent.ServerSession.EnqueueRequest(request);
 
             KernelContext.CriticalSection.Leave();
 
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KPort.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KPort.cs
index 2f67aeaec8..93f0f34cd0 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KPort.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KPort.cs
@@ -1,4 +1,5 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
 
 namespace Ryujinx.HLE.HOS.Kernel.Ipc
 {
@@ -7,26 +8,26 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
         public KServerPort ServerPort { get; }
         public KClientPort ClientPort { get; }
 
-        private long _nameAddress;
+        private string _name;
 
         private ChannelState _state;
 
         public bool IsLight { get; private set; }
 
-        public KPort(KernelContext context, int maxSessions, bool isLight, long nameAddress) : base(context)
+        public KPort(KernelContext context, int maxSessions, bool isLight, string name) : base(context)
         {
             ServerPort = new KServerPort(context, this);
             ClientPort = new KClientPort(context, this, maxSessions);
 
-            IsLight      = isLight;
-            _nameAddress = nameAddress;
+            IsLight = isLight;
+            _name = name;
 
             _state = ChannelState.Open;
         }
 
-        public KernelResult EnqueueIncomingSession(KServerSession session)
+        public Result EnqueueIncomingSession(KServerSession session)
         {
-            KernelResult result;
+            Result result;
 
             KernelContext.CriticalSection.Enter();
 
@@ -34,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             {
                 ServerPort.EnqueueIncomingSession(session);
 
-                result = KernelResult.Success;
+                result = Result.Success;
             }
             else
             {
@@ -46,9 +47,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             return result;
         }
 
-        public KernelResult EnqueueIncomingLightSession(KLightServerSession session)
+        public Result EnqueueIncomingLightSession(KLightServerSession session)
         {
-            KernelResult result;
+            Result result;
 
             KernelContext.CriticalSection.Enter();
 
@@ -56,7 +57,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             {
                 ServerPort.EnqueueIncomingLightSession(session);
 
-                result = KernelResult.Success;
+                result = Result.Success;
             }
             else
             {
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
index 199e78dc6a..9c2184d923 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
@@ -3,6 +3,7 @@ using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Memory;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Kernel.Ipc
@@ -178,7 +179,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             _requests = new LinkedList<KSessionRequest>();
         }
 
-        public KernelResult EnqueueRequest(KSessionRequest request)
+        public Result EnqueueRequest(KSessionRequest request)
         {
             if (_parent.ClientSession.State != ChannelState.Open)
             {
@@ -203,10 +204,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                 Signal();
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult Receive(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
+        public Result Receive(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
         {
             KThread  serverThread  = KernelStatic.GetCurrentThread();
             KProcess serverProcess = serverThread.Owner;
@@ -249,12 +250,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             MessageHeader clientHeader = GetClientMessageHeader(clientProcess, clientMsg);
             MessageHeader serverHeader = GetServerMessageHeader(serverMsg);
 
-            KernelResult serverResult = KernelResult.NotFound;
-            KernelResult clientResult = KernelResult.Success;
+            Result serverResult = KernelResult.NotFound;
+            Result clientResult = Result.Success;
 
             void CleanUpForError()
             {
-                if (request.BufferDescriptorTable.UnmapServerBuffers(serverProcess.MemoryManager) == KernelResult.Success)
+                if (request.BufferDescriptorTable.UnmapServerBuffers(serverProcess.MemoryManager) == Result.Success)
                 {
                     request.BufferDescriptorTable.RestoreClientBuffers(clientProcess.MemoryManager);
                 }
@@ -348,7 +349,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                     int newHandle = 0;
                     int handle = clientProcess.CpuMemory.Read<int>(clientMsg.Address + offset * 4);
 
-                    if (clientResult == KernelResult.Success && handle != 0)
+                    if (clientResult == Result.Success && handle != 0)
                     {
                         clientResult = GetCopyObjectHandle(clientThread, serverProcess, handle, out newHandle);
                     }
@@ -365,7 +366,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
 
                     if (handle != 0)
                     {
-                        if (clientResult == KernelResult.Success)
+                        if (clientResult == Result.Success)
                         {
                             clientResult = GetMoveObjectHandle(clientProcess, serverProcess, handle, out newHandle);
                         }
@@ -380,7 +381,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                     offset++;
                 }
 
-                if (clientResult != KernelResult.Success)
+                if (clientResult != Result.Success)
                 {
                     CleanUpForError();
 
@@ -412,7 +413,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                         ref       recvListDstOffset,
                         out ulong recvListBufferAddress);
 
-                    if (clientResult != KernelResult.Success)
+                    if (clientResult != Result.Success)
                     {
                         CleanUpForError();
 
@@ -429,7 +430,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                         MemoryAttribute.Uncached,
                         MemoryAttribute.None);
 
-                    if (clientResult != KernelResult.Success)
+                    if (clientResult != Result.Success)
                     {
                         CleanUpForError();
 
@@ -498,7 +499,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                         notReceiveDesc,
                         out dstAddress);
 
-                    if (clientResult != KernelResult.Success)
+                    if (clientResult != Result.Success)
                     {
                         CleanUpForError();
 
@@ -518,7 +519,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                         clientResult = request.BufferDescriptorTable.AddExchangeBuffer(bufferAddress, dstAddress, bufferSize, state);
                     }
 
-                    if (clientResult != KernelResult.Success)
+                    if (clientResult != Result.Success)
                     {
                         CleanUpForError();
 
@@ -573,7 +574,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                     serverProcess.CpuMemory.Write(copyDst, clientProcess.CpuMemory.GetSpan(copySrc, (int)copySize));
                 }
 
-                if (clientResult != KernelResult.Success)
+                if (clientResult != Result.Success)
                 {
                     CleanUpForError();
 
@@ -581,10 +582,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult Reply(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
+        public Result Reply(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
         {
             KThread  serverThread  = KernelStatic.GetCurrentThread();
             KProcess serverProcess = serverThread.Owner;
@@ -618,8 +619,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             MessageHeader clientHeader = GetClientMessageHeader(clientProcess, clientMsg);
             MessageHeader serverHeader = GetServerMessageHeader(serverMsg);
 
-            KernelResult clientResult = KernelResult.Success;
-            KernelResult serverResult = KernelResult.Success;
+            Result clientResult = Result.Success;
+            Result serverResult = Result.Success;
 
             void CleanUpForError()
             {
@@ -683,7 +684,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             // Copy receive and exchange buffers.
             clientResult = request.BufferDescriptorTable.CopyBuffersToClient(clientProcess.MemoryManager);
 
-            if (clientResult != KernelResult.Success)
+            if (clientResult != Result.Success)
             {
                 CleanUpForError();
 
@@ -734,7 +735,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
 
                     if (handle != 0)
                     {
-                        if (clientResult == KernelResult.Success)
+                        if (clientResult == Result.Success)
                         {
                             clientResult = GetMoveObjectHandle(serverProcess, clientProcess, handle, out newHandle);
                         }
@@ -776,7 +777,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                         ref recvListDstOffset,
                         out recvListBufferAddress);
 
-                    if (clientResult != KernelResult.Success)
+                    if (clientResult != Result.Success)
                     {
                         CleanUpForError();
 
@@ -793,7 +794,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
                         MemoryAttribute.None,
                         descriptor.BufferAddress);
 
-                    if (clientResult != KernelResult.Success)
+                    if (clientResult != Result.Success)
                     {
                         CleanUpForError();
 
@@ -888,7 +889,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             return new MessageHeader(word0, word1, word2);
         }
 
-        private KernelResult GetCopyObjectHandle(KThread srcThread, KProcess dstProcess, int srcHandle, out int dstHandle)
+        private Result GetCopyObjectHandle(KThread srcThread, KProcess dstProcess, int srcHandle, out int dstHandle)
         {
             dstHandle = 0;
 
@@ -919,7 +920,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             }
         }
 
-        private KernelResult GetMoveObjectHandle(KProcess srcProcess, KProcess dstProcess, int srcHandle, out int dstHandle)
+        private Result GetMoveObjectHandle(KProcess srcProcess, KProcess dstProcess, int srcHandle, out int dstHandle)
         {
             dstHandle = 0;
 
@@ -927,7 +928,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
 
             if (obj != null)
             {
-                KernelResult result = dstProcess.HandleTable.GenerateHandle(obj, out dstHandle);
+                Result result = dstProcess.HandleTable.GenerateHandle(obj, out dstHandle);
 
                 srcProcess.HandleTable.CloseHandle(srcHandle);
 
@@ -964,7 +965,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             return receiveList;
         }
 
-        private KernelResult GetReceiveListAddress(
+        private Result GetReceiveListAddress(
             PointerBufferDesc descriptor,
             Message           message,
             uint              recvListType,
@@ -1038,7 +1039,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
 
             address = recvListBufferAddress;
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         private void CloseAllHandles(Message message, MessageHeader header, KProcess process)
@@ -1166,19 +1167,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             return hasRequest;
         }
 
-        private void FinishRequest(KSessionRequest request, KernelResult result)
+        private void FinishRequest(KSessionRequest request, Result result)
         {
             KProcess clientProcess = request.ClientThread.Owner;
             KProcess serverProcess = request.ServerProcess;
 
-            KernelResult unmapResult = KernelResult.Success;
+            Result unmapResult = Result.Success;
 
             if (serverProcess != null)
             {
                 unmapResult = request.BufferDescriptorTable.UnmapServerBuffers(serverProcess.MemoryManager);
             }
 
-            if (unmapResult == KernelResult.Success)
+            if (unmapResult == Result.Success)
             {
                 request.BufferDescriptorTable.RestoreClientBuffers(clientProcess.MemoryManager);
             }
@@ -1186,7 +1187,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             WakeClientThread(request, result);
         }
 
-        private void WakeClientThread(KSessionRequest request, KernelResult result)
+        private void WakeClientThread(KSessionRequest request, Result result)
         {
             // Wait client thread waiting for a response for the given request.
             if (request.AsyncEvent != null)
@@ -1203,16 +1204,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             }
         }
 
-        private void SendResultToAsyncRequestClient(KSessionRequest request, KernelResult result)
+        private void SendResultToAsyncRequestClient(KSessionRequest request, Result result)
         {
             KProcess clientProcess = request.ClientThread.Owner;
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 ulong address = request.CustomCmdBuffAddr;
 
                 clientProcess.CpuMemory.Write<ulong>(address, 0);
-                clientProcess.CpuMemory.Write(address + 8, (int)result);
+                clientProcess.CpuMemory.Write(address + 8, result.ErrorCode);
             }
 
             clientProcess.MemoryManager.UnborrowIpcBuffer(request.CustomCmdBuffAddr, request.CustomCmdBuffSize);
@@ -1220,24 +1221,24 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
             request.AsyncEvent.Signal();
         }
 
-        private void WakeServerThreads(KernelResult result)
+        private void WakeServerThreads(Result result)
         {
             // Wake all server threads waiting for requests.
             KernelContext.CriticalSection.Enter();
 
             foreach (KThread thread in WaitingThreads)
             {
-                WakeAndSetResult(thread, result);
+                WakeAndSetResult(thread, result, this);
             }
 
             KernelContext.CriticalSection.Leave();
         }
 
-        private void WakeAndSetResult(KThread thread, KernelResult result)
+        private void WakeAndSetResult(KThread thread, Result result, KSynchronizationObject signaledObj = null)
         {
             if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
             {
-                thread.SignaledObj   = null;
+                thread.SignaledObj   = signaledObj;
                 thread.ObjSyncResult = result;
 
                 thread.Reschedule(ThreadSchedState.Running);
diff --git a/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
index 625a007dda..18cf212a9e 100644
--- a/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
@@ -2,6 +2,7 @@
 using Ryujinx.HLE.HOS.Kernel.Memory;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Threading;
 
@@ -15,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Kernel
         [ThreadStatic]
         private static KThread CurrentThread;
 
-        public static KernelResult StartInitialProcess(
+        public static Result StartInitialProcess(
             KernelContext context,
             ProcessCreationInfo creationInfo,
             ReadOnlySpan<int> capabilities,
@@ -24,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Kernel
         {
             KProcess process = new KProcess(context);
 
-            KernelResult result = process.Initialize(
+            Result result = process.Initialize(
                 creationInfo,
                 capabilities,
                 context.ResourceLimit,
@@ -32,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel
                 null,
                 customThreadStart);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KCodeMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KCodeMemory.cs
index 05cf4a4f97..11474e4938 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KCodeMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KCodeMemory.cs
@@ -1,6 +1,7 @@
 using Ryujinx.Common;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Diagnostics;
 
@@ -21,13 +22,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             _lock = new object();
         }
 
-        public KernelResult Initialize(ulong address, ulong size)
+        public Result Initialize(ulong address, ulong size)
         {
             Owner = KernelStatic.GetCurrentProcess();
 
-            KernelResult result = Owner.MemoryManager.BorrowCodeMemory(_pageList, address, size);
+            Result result = Owner.MemoryManager.BorrowCodeMemory(_pageList, address, size);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -39,10 +40,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             _isMapped = false;
             _isOwnerMapped = false;
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult Map(ulong address, ulong size, KMemoryPermission perm)
+        public Result Map(ulong address, ulong size, KMemoryPermission perm)
         {
             if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize))
             {
@@ -58,9 +59,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                 KProcess process = KernelStatic.GetCurrentProcess();
 
-                KernelResult result = process.MemoryManager.MapPages(address, _pageList, MemoryState.CodeWritable, KMemoryPermission.ReadAndWrite);
+                Result result = process.MemoryManager.MapPages(address, _pageList, MemoryState.CodeWritable, KMemoryPermission.ReadAndWrite);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     return result;
                 }
@@ -68,10 +69,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 _isMapped = true;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult MapToOwner(ulong address, ulong size, KMemoryPermission permission)
+        public Result MapToOwner(ulong address, ulong size, KMemoryPermission permission)
         {
             if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize))
             {
@@ -87,9 +88,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                 Debug.Assert(permission == KMemoryPermission.Read || permission == KMemoryPermission.ReadAndExecute);
 
-                KernelResult result = Owner.MemoryManager.MapPages(address, _pageList, MemoryState.CodeReadOnly, permission);
+                Result result = Owner.MemoryManager.MapPages(address, _pageList, MemoryState.CodeReadOnly, permission);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     return result;
                 }
@@ -97,10 +98,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 _isOwnerMapped = true;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult Unmap(ulong address, ulong size)
+        public Result Unmap(ulong address, ulong size)
         {
             if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize))
             {
@@ -111,9 +112,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             {
                 KProcess process = KernelStatic.GetCurrentProcess();
 
-                KernelResult result = process.MemoryManager.UnmapPages(address, _pageList, MemoryState.CodeWritable);
+                Result result = process.MemoryManager.UnmapPages(address, _pageList, MemoryState.CodeWritable);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     return result;
                 }
@@ -123,10 +124,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 _isMapped = false;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult UnmapFromOwner(ulong address, ulong size)
+        public Result UnmapFromOwner(ulong address, ulong size)
         {
             if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, KPageTableBase.PageSize))
             {
@@ -135,9 +136,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
             lock (_lock)
             {
-                KernelResult result = Owner.MemoryManager.UnmapPages(address, _pageList, MemoryState.CodeReadOnly);
+                Result result = Owner.MemoryManager.UnmapPages(address, _pageList, MemoryState.CodeReadOnly);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     return result;
                 }
@@ -147,7 +148,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 _isOwnerMapped = false;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         protected override void Destroy()
@@ -156,7 +157,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             {
                 ulong size = _pageList.GetPagesCount() * KPageTableBase.PageSize;
 
-                if (Owner.MemoryManager.UnborrowCodeMemory(_address, size, _pageList) != KernelResult.Success)
+                if (Owner.MemoryManager.UnborrowCodeMemory(_address, size, _pageList) != Result.Success)
                 {
                     throw new InvalidOperationException("Unexpected failure restoring transfer memory attributes.");
                 }
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlockManager.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlockManager.cs
index 9cfdfda37a..e9146aeb81 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlockManager.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlockManager.cs
@@ -1,5 +1,5 @@
 using Ryujinx.Common.Collections;
-using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
 using System.Diagnostics;
 
 namespace Ryujinx.HLE.HOS.Kernel.Memory
@@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             _blockTree = new IntrusiveRedBlackTree<KMemoryBlock>();
         }
 
-        public KernelResult Initialize(ulong addrSpaceStart, ulong addrSpaceEnd, KMemoryBlockSlabManager slabManager)
+        public Result Initialize(ulong addrSpaceStart, ulong addrSpaceEnd, KMemoryBlockSlabManager slabManager)
         {
             _slabManager = slabManager;
             _addrSpaceStart = addrSpaceStart;
@@ -43,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 KMemoryPermission.None,
                 MemoryAttribute.None));
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         public void InsertBlock(
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs
index 43d48946d9..5e6273b864 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs
@@ -1,4 +1,4 @@
-using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
 using System.Diagnostics;
 
 namespace Ryujinx.HLE.HOS.Kernel.Memory
@@ -25,20 +25,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             _pageHeap.UpdateUsedSize();
         }
 
-        public KernelResult AllocatePages(out KPageList pageList, ulong pagesCount)
+        public Result AllocatePages(out KPageList pageList, ulong pagesCount)
         {
             if (pagesCount == 0)
             {
                 pageList = new KPageList();
 
-                return KernelResult.Success;
+                return Result.Success;
             }
 
             lock (_pageHeap)
             {
-                KernelResult result = AllocatePagesImpl(out pageList, pagesCount, false);
+                Result result = AllocatePagesImpl(out pageList, pagesCount, false);
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     foreach (var node in pageList)
                     {
@@ -71,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        private KernelResult AllocatePagesImpl(out KPageList pageList, ulong pagesCount, bool random)
+        private Result AllocatePagesImpl(out KPageList pageList, ulong pagesCount, bool random)
         {
             pageList = new KPageList();
 
@@ -95,9 +95,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                         break;
                     }
 
-                    KernelResult result = pageList.AddRange(allocatedBlock, pagesPerAlloc);
+                    Result result = pageList.AddRange(allocatedBlock, pagesPerAlloc);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         FreePages(pageList);
                         _pageHeap.Free(allocatedBlock, pagesPerAlloc);
@@ -116,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 return KernelResult.OutOfMemory;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         private ulong AllocatePagesContiguousImpl(ulong pagesCount, ulong alignPages, bool random)
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KPageList.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KPageList.cs
index 7f2f1ba67b..3149faa97a 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageList.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageList.cs
@@ -1,4 +1,4 @@
-using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
 using System.Collections;
 using System.Collections.Generic;
 
@@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             Nodes = new LinkedList<KPageNode>();
         }
 
-        public KernelResult AddRange(ulong address, ulong pagesCount)
+        public Result AddRange(ulong address, ulong pagesCount)
         {
             if (pagesCount != 0)
             {
@@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 Nodes.AddLast(new KPageNode(address, pagesCount));
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         public ulong GetPagesCount()
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs
index 9d5212315f..9b7c99ba19 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs
@@ -1,4 +1,4 @@
-using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
 using Ryujinx.Memory;
 using System;
 using System.Diagnostics;
@@ -31,31 +31,31 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
         }
 
         /// <inheritdoc/>
-        protected override KernelResult MapMemory(ulong src, ulong dst, ulong pagesCount, KMemoryPermission oldSrcPermission, KMemoryPermission newDstPermission)
+        protected override Result MapMemory(ulong src, ulong dst, ulong pagesCount, KMemoryPermission oldSrcPermission, KMemoryPermission newDstPermission)
         {
             KPageList pageList = new KPageList();
             GetPhysicalRegions(src, pagesCount * PageSize, pageList);
 
-            KernelResult result = Reprotect(src, pagesCount, KMemoryPermission.None);
+            Result result = Reprotect(src, pagesCount, KMemoryPermission.None);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             result = MapPages(dst, pageList, newDstPermission, false, 0);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
-                KernelResult reprotectResult = Reprotect(src, pagesCount, oldSrcPermission);
-                Debug.Assert(reprotectResult == KernelResult.Success);
+                Result reprotectResult = Reprotect(src, pagesCount, oldSrcPermission);
+                Debug.Assert(reprotectResult == Result.Success);
             }
 
             return result;
         }
 
         /// <inheritdoc/>
-        protected override KernelResult UnmapMemory(ulong dst, ulong src, ulong pagesCount, KMemoryPermission oldDstPermission, KMemoryPermission newSrcPermission)
+        protected override Result UnmapMemory(ulong dst, ulong src, ulong pagesCount, KMemoryPermission oldDstPermission, KMemoryPermission newSrcPermission)
         {
             ulong size = pagesCount * PageSize;
 
@@ -70,26 +70,26 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 return KernelResult.InvalidMemRange;
             }
 
-            KernelResult result = Unmap(dst, pagesCount);
+            Result result = Unmap(dst, pagesCount);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             result = Reprotect(src, pagesCount, newSrcPermission);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
-                KernelResult mapResult = MapPages(dst, dstPageList, oldDstPermission, false, 0);
-                Debug.Assert(mapResult == KernelResult.Success);
+                Result mapResult = MapPages(dst, dstPageList, oldDstPermission, false, 0);
+                Debug.Assert(mapResult == Result.Success);
             }
 
             return result;
         }
 
         /// <inheritdoc/>
-        protected override KernelResult MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
+        protected override Result MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
         {
             ulong size = pagesCount * PageSize;
 
@@ -107,11 +107,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 _cpuMemory.Fill(dstVa, size, fillValue);
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         /// <inheritdoc/>
-        protected override KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
+        protected override Result MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
         {
             using var scopedPageList = new KScopedPageList(Context.MemoryManager, pageList);
 
@@ -136,11 +136,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
             scopedPageList.SignalSuccess();
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         /// <inheritdoc/>
-        protected override KernelResult Unmap(ulong address, ulong pagesCount)
+        protected override Result Unmap(ulong address, ulong pagesCount)
         {
             KPageList pagesToClose = new KPageList();
 
@@ -159,21 +159,21 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
             pagesToClose.DecrementPagesReferenceCount(Context.MemoryManager);
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         /// <inheritdoc/>
-        protected override KernelResult Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission)
+        protected override Result Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission)
         {
             // TODO.
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         /// <inheritdoc/>
-        protected override KernelResult ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission)
+        protected override Result ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission)
         {
             // TODO.
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         /// <inheritdoc/>
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
index 2c94cba221..e19e22c87e 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
@@ -1,6 +1,7 @@
 using Ryujinx.Common;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -88,7 +89,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
         private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
 
-        public KernelResult InitializeForProcess(
+        public Result InitializeForProcess(
             AddressSpaceType addrSpaceType,
             bool aslrEnabled,
             bool aslrDisabled,
@@ -107,7 +108,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             ulong addrSpaceBase = 0;
             ulong addrSpaceSize = 1UL << AddrSpaceSizes[(int)addrSpaceType];
 
-            KernelResult result = CreateUserAddressSpace(
+            Result result = CreateUserAddressSpace(
                 addrSpaceType,
                 aslrEnabled,
                 aslrDisabled,
@@ -118,7 +119,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 size,
                 slabManager);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 Context.ContextIdManager.PutId(_contextId);
             }
@@ -134,7 +135,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             public ulong AslrOffset;
         }
 
-        private KernelResult CreateUserAddressSpace(
+        private Result CreateUserAddressSpace(
             AddressSpaceType addrSpaceType,
             bool aslrEnabled,
             bool aslrDisabled,
@@ -342,7 +343,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult MapPages(ulong address, KPageList pageList, MemoryState state, KMemoryPermission permission)
+        public Result MapPages(ulong address, KPageList pageList, MemoryState state, KMemoryPermission permission)
         {
             ulong pagesCount = pageList.GetPagesCount();
 
@@ -365,9 +366,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     return KernelResult.OutOfResource;
                 }
 
-                KernelResult result = MapPages(address, pageList, permission);
+                Result result = MapPages(address, pageList, permission);
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     _blockManager.InsertBlock(address, pagesCount, state, permission);
                 }
@@ -376,7 +377,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult UnmapPages(ulong address, KPageList pageList, MemoryState stateExpected)
+        public Result UnmapPages(ulong address, KPageList pageList, MemoryState stateExpected)
         {
             ulong pagesCount = pageList.GetPagesCount();
             ulong size = pagesCount * PageSize;
@@ -430,9 +431,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                         return KernelResult.OutOfResource;
                     }
 
-                    KernelResult result = Unmap(address, pagesCount);
+                    Result result = Unmap(address, pagesCount);
 
-                    if (result == KernelResult.Success)
+                    if (result == Result.Success)
                     {
                         _blockManager.InsertBlock(address, pagesCount, MemoryState.Unmapped);
                     }
@@ -446,19 +447,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult MapNormalMemory(long address, long size, KMemoryPermission permission)
+        public Result MapNormalMemory(long address, long size, KMemoryPermission permission)
         {
             // TODO.
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult MapIoMemory(long address, long size, KMemoryPermission permission)
+        public Result MapIoMemory(long address, long size, KMemoryPermission permission)
         {
             // TODO.
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult MapPages(
+        public Result MapPages(
             ulong pagesCount,
             int alignment,
             ulong srcPa,
@@ -497,7 +498,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     return KernelResult.OutOfResource;
                 }
 
-                KernelResult result;
+                Result result;
 
                 if (paIsValid)
                 {
@@ -508,7 +509,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     result = AllocateAndMapPages(address, pagesCount, permission);
                 }
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     return result;
                 }
@@ -516,10 +517,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 _blockManager.InsertBlock(address, pagesCount, state, permission);
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult MapPages(ulong address, ulong pagesCount, MemoryState state, KMemoryPermission permission)
+        public Result MapPages(ulong address, ulong pagesCount, MemoryState state, KMemoryPermission permission)
         {
             ulong size = pagesCount * PageSize;
 
@@ -540,9 +541,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     return KernelResult.OutOfResource;
                 }
 
-                KernelResult result = AllocateAndMapPages(address, pagesCount, permission);
+                Result result = AllocateAndMapPages(address, pagesCount, permission);
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     _blockManager.InsertBlock(address, pagesCount, state, permission);
                 }
@@ -551,13 +552,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        private KernelResult AllocateAndMapPages(ulong address, ulong pagesCount, KMemoryPermission permission)
+        private Result AllocateAndMapPages(ulong address, ulong pagesCount, KMemoryPermission permission)
         {
             KMemoryRegionManager region = GetMemoryRegionManager();
 
-            KernelResult result = region.AllocatePages(out KPageList pageList, pagesCount);
+            Result result = region.AllocatePages(out KPageList pageList, pagesCount);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -567,7 +568,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             return MapPages(address, pageList, permission);
         }
 
-        public KernelResult MapProcessCodeMemory(ulong dst, ulong src, ulong size)
+        public Result MapProcessCodeMemory(ulong dst, ulong src, ulong size)
         {
             lock (_blockManager)
             {
@@ -596,12 +597,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     ulong pagesCount = size / PageSize;
 
-                    KernelResult result = MapMemory(src, dst, pagesCount, permission, KMemoryPermission.None);
+                    Result result = MapMemory(src, dst, pagesCount, permission, KMemoryPermission.None);
 
                     _blockManager.InsertBlock(src, pagesCount, state, KMemoryPermission.None, MemoryAttribute.Borrowed);
                     _blockManager.InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic);
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -610,7 +611,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult UnmapProcessCodeMemory(ulong dst, ulong src, ulong size)
+        public Result UnmapProcessCodeMemory(ulong dst, ulong src, ulong size)
         {
             lock (_blockManager)
             {
@@ -656,9 +657,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 {
                     ulong pagesCount = size / PageSize;
 
-                    KernelResult result = Unmap(dst, pagesCount);
+                    Result result = Unmap(dst, pagesCount);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         return result;
                     }
@@ -673,7 +674,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     _blockManager.InsertBlock(dst, pagesCount, MemoryState.Unmapped);
                     _blockManager.InsertBlock(src, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -682,7 +683,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult SetHeapSize(ulong size, out ulong address)
+        public Result SetHeapSize(ulong size, out ulong address)
         {
             address = 0;
 
@@ -712,7 +713,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     KMemoryRegionManager region = GetMemoryRegionManager();
 
-                    KernelResult result = region.AllocatePages(out KPageList pageList, pagesCount);
+                    Result result = region.AllocatePages(out KPageList pageList, pagesCount);
 
                     using var _ = new OnScopeExit(() => pageList.DecrementPagesReferenceCount(Context.MemoryManager));
 
@@ -724,7 +725,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                         }
                     }
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         CleanUpForError();
 
@@ -747,7 +748,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     result = MapPages(_currentHeapAddr, pageList, KMemoryPermission.ReadAndWrite, true, (byte)_heapFillValue);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         CleanUpForError();
 
@@ -786,9 +787,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     ulong pagesCount = sizeDelta / PageSize;
 
-                    KernelResult result = Unmap(freeAddr, pagesCount);
+                    Result result = Unmap(freeAddr, pagesCount);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         return result;
                     }
@@ -803,10 +804,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
             address = HeapRegionStart;
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult SetMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
+        public Result SetMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
         {
             lock (_blockManager)
             {
@@ -833,9 +834,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                         ulong pagesCount = size / PageSize;
 
-                        KernelResult result = Reprotect(address, pagesCount, permission);
+                        Result result = Reprotect(address, pagesCount, permission);
 
-                        if (result != KernelResult.Success)
+                        if (result != Result.Success)
                         {
                             return result;
                         }
@@ -843,7 +844,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                         _blockManager.InsertBlock(address, pagesCount, oldState, permission);
                     }
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -865,17 +866,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             return _currentHeapAddr - HeapRegionStart;
         }
 
-        public KernelResult SetHeapCapacity(ulong capacity)
+        public Result SetHeapCapacity(ulong capacity)
         {
             lock (_blockManager)
             {
                 _heapCapacity = capacity;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult SetMemoryAttribute(
+        public Result SetMemoryAttribute(
             ulong address,
             ulong size,
             MemoryAttribute attributeMask,
@@ -909,7 +910,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     _blockManager.InsertBlock(address, pagesCount, state, permission, attribute);
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -942,7 +943,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult Map(ulong dst, ulong src, ulong size)
+        public Result Map(ulong dst, ulong src, ulong size)
         {
             bool success;
 
@@ -973,9 +974,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     ulong pagesCount = size / PageSize;
 
-                    KernelResult result = MapMemory(src, dst, pagesCount, KMemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite);
+                    Result result = MapMemory(src, dst, pagesCount, KMemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         return result;
                     }
@@ -983,7 +984,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     _blockManager.InsertBlock(src, pagesCount, srcState, KMemoryPermission.None, MemoryAttribute.Borrowed);
                     _blockManager.InsertBlock(dst, pagesCount, MemoryState.Stack, KMemoryPermission.ReadAndWrite);
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -992,7 +993,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult UnmapForKernel(ulong address, ulong pagesCount, MemoryState stateExpected)
+        public Result UnmapForKernel(ulong address, ulong pagesCount, MemoryState stateExpected)
         {
             ulong size = pagesCount * PageSize;
 
@@ -1017,14 +1018,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                         return KernelResult.OutOfResource;
                     }
 
-                    KernelResult result = Unmap(address, pagesCount);
+                    Result result = Unmap(address, pagesCount);
 
-                    if (result == KernelResult.Success)
+                    if (result == Result.Success)
                     {
                         _blockManager.InsertBlock(address, pagesCount, MemoryState.Unmapped);
                     }
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -1033,7 +1034,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult Unmap(ulong dst, ulong src, ulong size)
+        public Result Unmap(ulong dst, ulong src, ulong size)
         {
             bool success;
 
@@ -1076,9 +1077,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     ulong pagesCount = size / PageSize;
 
-                    KernelResult result = UnmapMemory(dst, src, pagesCount, dstPermission, KMemoryPermission.ReadAndWrite);
+                    Result result = UnmapMemory(dst, src, pagesCount, dstPermission, KMemoryPermission.ReadAndWrite);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         return result;
                     }
@@ -1086,7 +1087,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     _blockManager.InsertBlock(src, pagesCount, srcState, KMemoryPermission.ReadAndWrite);
                     _blockManager.InsertBlock(dst, pagesCount, MemoryState.Unmapped);
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -1095,7 +1096,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult UnmapProcessMemory(ulong dst, ulong size, KPageTableBase srcPageTable, ulong src)
+        public Result UnmapProcessMemory(ulong dst, ulong size, KPageTableBase srcPageTable, ulong src)
         {
             lock (_blockManager)
             {
@@ -1153,20 +1154,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                 ulong pagesCount = size / PageSize;
 
-                KernelResult result = Unmap(dst, pagesCount);
+                Result result = Unmap(dst, pagesCount);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     return result;
                 }
 
                 _blockManager.InsertBlock(dst, pagesCount, MemoryState.Unmapped);
 
-                return KernelResult.Success;
+                return Result.Success;
             }
         }
 
-        public KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
+        public Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
         {
             lock (_blockManager)
             {
@@ -1213,7 +1214,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                         ulong pagesCount = size / PageSize;
 
-                        KernelResult result;
+                        Result result;
 
                         if ((oldPermission & KMemoryPermission.Execute) != 0)
                         {
@@ -1224,7 +1225,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                             result = Reprotect(address, pagesCount, permission);
                         }
 
-                        if (result != KernelResult.Success)
+                        if (result != Result.Success)
                         {
                             return result;
                         }
@@ -1232,7 +1233,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                         _blockManager.InsertBlock(address, pagesCount, newState, permission);
                     }
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -1241,7 +1242,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult MapPhysicalMemory(ulong address, ulong size)
+        public Result MapPhysicalMemory(ulong address, ulong size)
         {
             ulong endAddr = address + size;
 
@@ -1259,7 +1260,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                 if (mappedSize == size)
                 {
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
 
                 ulong remainingSize = size - mappedSize;
@@ -1276,7 +1277,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                 KMemoryRegionManager region = GetMemoryRegionManager();
 
-                KernelResult result = region.AllocatePages(out KPageList pageList, remainingPages);
+                Result result = region.AllocatePages(out KPageList pageList, remainingPages);
 
                 using var _ = new OnScopeExit(() => pageList.DecrementPagesReferenceCount(Context.MemoryManager));
 
@@ -1285,7 +1286,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     currentProcess.ResourceLimit?.Release(LimitableResource.Memory, remainingSize);
                 }
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     CleanUpForError();
 
@@ -1357,10 +1358,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     MemoryAttribute.None);
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult UnmapPhysicalMemory(ulong address, ulong size)
+        public Result UnmapPhysicalMemory(ulong address, ulong size)
         {
             ulong endAddr = address + size;
 
@@ -1391,7 +1392,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                 if (heapMappedSize == 0)
                 {
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
 
                 if (!_slabManager.CanAllocate(MaxBlocksNeededForInsertion))
@@ -1400,7 +1401,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 }
 
                 // Try to unmap all the heap mapped memory inside range.
-                KernelResult result = KernelResult.Success;
+                Result result = Result.Success;
 
                 foreach (KMemoryInfo info in IterateOverRange(address, endAddr))
                 {
@@ -1416,11 +1417,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                         // The kernel would attempt to remap if this fails, but we don't because:
                         // - The implementation may not support remapping if memory aliasing is not supported on the platform.
                         // - Unmap can't ever fail here anyway.
-                        Debug.Assert(result == KernelResult.Success);
+                        Debug.Assert(result == Result.Success);
                     }
                 }
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     PhysicalMemoryUsage -= heapMappedSize;
 
@@ -1437,7 +1438,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult CopyDataToCurrentProcess(
+        public Result CopyDataToCurrentProcess(
             ulong dst,
             ulong size,
             ulong src,
@@ -1460,7 +1461,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 toServer: true);
         }
 
-        public KernelResult CopyDataFromCurrentProcess(
+        public Result CopyDataFromCurrentProcess(
             ulong dst,
             ulong size,
             MemoryState stateMask,
@@ -1483,7 +1484,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 toServer: false);
         }
 
-        private KernelResult CopyDataFromOrToCurrentProcess(
+        private Result CopyDataFromOrToCurrentProcess(
             ulong size,
             ulong clientAddress,
             ulong serverAddress,
@@ -1543,7 +1544,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                         size -= copySize;
                     }
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -1552,7 +1553,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult MapBufferFromClientProcess(
+        public Result MapBufferFromClientProcess(
             ulong size,
             ulong src,
             KPageTableBase srcPageTable,
@@ -1567,14 +1568,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             {
                 lock (_blockManager)
                 {
-                    KernelResult result = srcPageTable.ReprotectClientProcess(
+                    Result result = srcPageTable.ReprotectClientProcess(
                         src,
                         size,
                         permission,
                         state,
                         out int blocksNeeded);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         return result;
                     }
@@ -1590,7 +1591,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     result = MapPagesFromClientProcess(size, src, permission, state, srcPageTable, send, out ulong va);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         if (srcMapEndAddr > srcMapAddress)
                         {
@@ -1613,10 +1614,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        private KernelResult ReprotectClientProcess(
+        private Result ReprotectClientProcess(
             ulong address,
             ulong size,
             KMemoryPermission permission,
@@ -1689,8 +1690,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                         ulong blockPagesCount = blockSize / PageSize;
 
-                        KernelResult reprotectResult = Reprotect(blockAddress, blockPagesCount, info.Permission);
-                        Debug.Assert(reprotectResult == KernelResult.Success);
+                        Result reprotectResult = Reprotect(blockAddress, blockPagesCount, info.Permission);
+                        Debug.Assert(reprotectResult == Result.Success);
                     }
                 }
             }
@@ -1699,7 +1700,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             SignalMemoryTracking(addressTruncated, endAddrRounded - addressTruncated, false);
 
             // Reprotect the aligned pages range on the client to make them inaccessible from the client process.
-            KernelResult result;
+            Result result;
 
             if (addressRounded < endAddrTruncated)
             {
@@ -1736,7 +1737,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     {
                         result = Reprotect(blockAddress, blockPagesCount, permissionMask);
 
-                        if (result != KernelResult.Success)
+                        if (result != Result.Success)
                         {
                             CleanUpForError();
 
@@ -1748,10 +1749,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        private KernelResult MapPagesFromClientProcess(
+        private Result MapPagesFromClientProcess(
             ulong size,
             ulong address,
             KMemoryPermission permission,
@@ -1877,9 +1878,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                     Context.Memory.Fill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter, (byte)_ipcFillValue);
                 }
 
-                KernelResult result = MapPages(currentVa, 1, dstFirstPagePa, permission);
+                Result result = MapPages(currentVa, 1, dstFirstPagePa, permission);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     CleanUpForError();
 
@@ -1896,9 +1897,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 KPageList pageList = new KPageList();
                 srcPageTable.GetPhysicalRegions(addressRounded, alignedSize, pageList);
 
-                KernelResult result = MapPages(currentVa, pageList, permission);
+                Result result = MapPages(currentVa, pageList, permission);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     CleanUpForError();
 
@@ -1931,9 +1932,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                 Context.Memory.Fill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter, (byte)_ipcFillValue);
 
-                KernelResult result = MapPages(currentVa, 1, dstLastPagePa, permission);
+                Result result = MapPages(currentVa, 1, dstLastPagePa, permission);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     CleanUpForError();
 
@@ -1945,10 +1946,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
             dst = va + (address - addressTruncated);
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult UnmapNoAttributeIfStateEquals(ulong address, ulong size, MemoryState state)
+        public Result UnmapNoAttributeIfStateEquals(ulong address, ulong size, MemoryState state)
         {
             if (AddrSpaceStart > address)
             {
@@ -1990,9 +1991,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     ulong pagesCount = (endAddrRounded - addressTruncated) / PageSize;
 
-                    KernelResult result = Unmap(addressTruncated, pagesCount);
+                    Result result = Unmap(addressTruncated, pagesCount);
 
-                    if (result == KernelResult.Success)
+                    if (result == Result.Success)
                     {
                         _blockManager.InsertBlock(addressTruncated, pagesCount, MemoryState.Unmapped);
                     }
@@ -2006,7 +2007,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult UnmapIpcRestorePermission(ulong address, ulong size, MemoryState state)
+        public Result UnmapIpcRestorePermission(ulong address, ulong size, MemoryState state)
         {
             ulong endAddr = address + size;
 
@@ -2019,7 +2020,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
             if (pagesCount == 0)
             {
-                return KernelResult.Success;
+                return Result.Success;
             }
 
             MemoryState stateMask;
@@ -2069,9 +2070,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                         ulong blockPagesCount = blockSize / PageSize;
 
-                        KernelResult result = Reprotect(blockAddress, blockPagesCount, info.SourcePermission);
+                        Result result = Reprotect(blockAddress, blockPagesCount, info.SourcePermission);
 
-                        if (result != KernelResult.Success)
+                        if (result != Result.Success)
                         {
                             return result;
                         }
@@ -2080,7 +2081,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                 _blockManager.InsertBlock(addressRounded, pagesCount, RestoreIpcMappingPermissions);
 
-                return KernelResult.Success;
+                return Result.Success;
             }
         }
 
@@ -2094,7 +2095,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             block.RestoreIpcMappingPermission();
         }
 
-        public KernelResult GetPagesIfStateEquals(
+        public Result GetPagesIfStateEquals(
             ulong address,
             ulong size,
             MemoryState stateMask,
@@ -2128,7 +2129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 {
                     GetPhysicalRegions(address, size, pageList);
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -2137,7 +2138,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult BorrowIpcBuffer(ulong address, ulong size)
+        public Result BorrowIpcBuffer(ulong address, ulong size)
         {
             return SetAttributesAndChangePermission(
                 address,
@@ -2152,7 +2153,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 MemoryAttribute.Borrowed);
         }
 
-        public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, KMemoryPermission permission)
+        public Result BorrowTransferMemory(KPageList pageList, ulong address, ulong size, KMemoryPermission permission)
         {
             return SetAttributesAndChangePermission(
                 address,
@@ -2168,7 +2169,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 pageList);
         }
 
-        public KernelResult BorrowCodeMemory(KPageList pageList, ulong address, ulong size)
+        public Result BorrowCodeMemory(KPageList pageList, ulong address, ulong size)
         {
             return SetAttributesAndChangePermission(
                 address,
@@ -2184,7 +2185,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 pageList);
         }
 
-        private KernelResult SetAttributesAndChangePermission(
+        private Result SetAttributesAndChangePermission(
             ulong address,
             ulong size,
             MemoryState stateMask,
@@ -2237,9 +2238,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     if (newPermission != oldPermission)
                     {
-                        KernelResult result = Reprotect(address, pagesCount, newPermission);
+                        Result result = Reprotect(address, pagesCount, newPermission);
 
-                        if (result != KernelResult.Success)
+                        if (result != Result.Success)
                         {
                             return result;
                         }
@@ -2249,7 +2250,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     _blockManager.InsertBlock(address, pagesCount, oldState, newPermission, newAttribute);
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -2258,7 +2259,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
-        public KernelResult UnborrowIpcBuffer(ulong address, ulong size)
+        public Result UnborrowIpcBuffer(ulong address, ulong size)
         {
             return ClearAttributesAndChangePermission(
                 address,
@@ -2273,7 +2274,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 MemoryAttribute.Borrowed);
         }
 
-        public KernelResult UnborrowTransferMemory(ulong address, ulong size, KPageList pageList)
+        public Result UnborrowTransferMemory(ulong address, ulong size, KPageList pageList)
         {
             return ClearAttributesAndChangePermission(
                 address,
@@ -2289,7 +2290,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 pageList);
         }
 
-        public KernelResult UnborrowCodeMemory(ulong address, ulong size, KPageList pageList)
+        public Result UnborrowCodeMemory(ulong address, ulong size, KPageList pageList)
         {
             return ClearAttributesAndChangePermission(
                 address,
@@ -2305,7 +2306,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 pageList);
         }
 
-        private KernelResult ClearAttributesAndChangePermission(
+        private Result ClearAttributesAndChangePermission(
             ulong address,
             ulong size,
             MemoryState stateMask,
@@ -2365,9 +2366,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     if (newPermission != oldPermission)
                     {
-                        KernelResult result = Reprotect(address, pagesCount, newPermission);
+                        Result result = Reprotect(address, pagesCount, newPermission);
 
-                        if (result != KernelResult.Success)
+                        if (result != Result.Success)
                         {
                             return result;
                         }
@@ -2377,7 +2378,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
                     _blockManager.InsertBlock(address, pagesCount, oldState, newPermission, newAttribute);
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
                 else
                 {
@@ -2915,7 +2916,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
         /// <param name="oldSrcPermission">Current protection of the source memory region</param>
         /// <param name="newDstPermission">Desired protection for the destination memory region</param>
         /// <returns>Result of the mapping operation</returns>
-        protected abstract KernelResult MapMemory(ulong src, ulong dst, ulong pagesCount, KMemoryPermission oldSrcPermission, KMemoryPermission newDstPermission);
+        protected abstract Result MapMemory(ulong src, ulong dst, ulong pagesCount, KMemoryPermission oldSrcPermission, KMemoryPermission newDstPermission);
 
         /// <summary>
         /// Unmaps a region of memory that was previously mapped with <see cref="MapMemory"/>.
@@ -2926,7 +2927,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
         /// <param name="oldDstPermission">Current protection of the destination memory region</param>
         /// <param name="newSrcPermission">Desired protection of the source memory region</param>
         /// <returns>Result of the unmapping operation</returns>
-        protected abstract KernelResult UnmapMemory(ulong dst, ulong src, ulong pagesCount, KMemoryPermission oldDstPermission, KMemoryPermission newSrcPermission);
+        protected abstract Result UnmapMemory(ulong dst, ulong src, ulong pagesCount, KMemoryPermission oldDstPermission, KMemoryPermission newSrcPermission);
 
         /// <summary>
         /// Maps a region of memory into the specified physical memory region.
@@ -2938,7 +2939,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
         /// <param name="shouldFillPages">Indicate if the pages should be filled with the <paramref name="fillValue"/> value</param>
         /// <param name="fillValue">The value used to fill pages when <paramref name="shouldFillPages"/> is set to true</param>
         /// <returns>Result of the mapping operation</returns>
-        protected abstract KernelResult MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
+        protected abstract Result MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
 
         /// <summary>
         /// Maps a region of memory into the specified physical memory region.
@@ -2949,7 +2950,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
         /// <param name="shouldFillPages">Indicate if the pages should be filled with the <paramref name="fillValue"/> value</param>
         /// <param name="fillValue">The value used to fill pages when <paramref name="shouldFillPages"/> is set to true</param>
         /// <returns>Result of the mapping operation</returns>
-        protected abstract KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
+        protected abstract Result MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
 
         /// <summary>
         /// Unmaps a region of memory that was previously mapped with one of the page mapping methods.
@@ -2957,7 +2958,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
         /// <param name="address">Virtual address of the region to unmap</param>
         /// <param name="pagesCount">Number of pages to unmap</param>
         /// <returns>Result of the unmapping operation</returns>
-        protected abstract KernelResult Unmap(ulong address, ulong pagesCount);
+        protected abstract Result Unmap(ulong address, ulong pagesCount);
 
         /// <summary>
         /// Changes the permissions of a given virtual memory region.
@@ -2966,7 +2967,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
         /// <param name="pagesCount">Number of pages to have their permissions changed</param>
         /// <param name="permission">New permission</param>
         /// <returns>Result of the permission change operation</returns>
-        protected abstract KernelResult Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission);
+        protected abstract Result Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission);
 
         /// <summary>
         /// Changes the permissions of a given virtual memory region.
@@ -2975,7 +2976,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
         /// <param name="pagesCount">Number of pages to have their permissions changed</param>
         /// <param name="permission">New permission</param>
         /// <returns>Result of the permission change operation</returns>
-        protected abstract KernelResult ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission);
+        protected abstract Result ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission);
 
         /// <summary>
         /// Alerts the memory tracking that a given region has been read from or written to.
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
index 3af6275051..2dbaf3cd84 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
@@ -1,6 +1,7 @@
 using Ryujinx.Common;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
 
 namespace Ryujinx.HLE.HOS.Kernel.Memory
 {
@@ -26,7 +27,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             _userPermission = userPermission;
         }
 
-        public KernelResult MapIntoProcess(
+        public Result MapIntoProcess(
             KPageTableBase memoryManager,
             ulong address,
             ulong size,
@@ -50,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             return memoryManager.MapPages(address, _pageList, MemoryState.SharedMemory, permission);
         }
 
-        public KernelResult UnmapFromProcess(KPageTableBase memoryManager, ulong address, ulong size, KProcess process)
+        public Result UnmapFromProcess(KPageTableBase memoryManager, ulong address, ulong size, KProcess process)
         {
             if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, KPageTableBase.PageSize))
             {
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
index 2888efb83e..b244959800 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
@@ -1,6 +1,7 @@
 using Ryujinx.Common;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Kernel.Memory
@@ -36,15 +37,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             _isMapped = false;
         }
 
-        public KernelResult Initialize(ulong address, ulong size, KMemoryPermission permission)
+        public Result Initialize(ulong address, ulong size, KMemoryPermission permission)
         {
             KProcess creator = KernelStatic.GetCurrentProcess();
 
             _creator = creator;
 
-            KernelResult result = creator.MemoryManager.BorrowTransferMemory(_pageList, address, size, permission);
+            Result result = creator.MemoryManager.BorrowTransferMemory(_pageList, address, size, permission);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -60,7 +61,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             return result;
         }
 
-        public KernelResult MapIntoProcess(
+        public Result MapIntoProcess(
             KPageTableBase memoryManager,
             ulong address,
             ulong size,
@@ -79,9 +80,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
             MemoryState state = Permission == KMemoryPermission.None ? MemoryState.TransferMemoryIsolated : MemoryState.TransferMemory;
 
-            KernelResult result = memoryManager.MapPages(address, _pageList, state, KMemoryPermission.ReadAndWrite);
+            Result result = memoryManager.MapPages(address, _pageList, state, KMemoryPermission.ReadAndWrite);
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 _isMapped = true;
             }
@@ -89,7 +90,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             return result;
         }
 
-        public KernelResult UnmapFromProcess(
+        public Result UnmapFromProcess(
             KPageTableBase memoryManager,
             ulong address,
             ulong size,
@@ -102,9 +103,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
 
             MemoryState state = Permission == KMemoryPermission.None ? MemoryState.TransferMemoryIsolated : MemoryState.TransferMemory;
 
-            KernelResult result = memoryManager.UnmapPages(address, _pageList, state);
+            Result result = memoryManager.UnmapPages(address, _pageList, state);
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 _isMapped = false;
             }
@@ -116,7 +117,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
         {
             if (_hasBeenInitialized)
             {
-                if (!_isMapped && _creator.MemoryManager.UnborrowTransferMemory(Address, Size, _pageList) != KernelResult.Success)
+                if (!_isMapped && _creator.MemoryManager.UnborrowTransferMemory(Address, Size, _pageList) != Result.Success)
                 {
                     throw new InvalidOperationException("Unexpected failure restoring transfer memory attributes.");
                 }
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs b/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs
index bcbb3b03aa..c15ebef5cb 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs
@@ -1,5 +1,6 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Kernel.Process
@@ -27,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             _context = context;
         }
 
-        public KernelResult Initialize(int size)
+        public Result Initialize(int size)
         {
             if ((uint)size > 1024)
             {
@@ -62,10 +63,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
             _nextFreeEntry = _tableHead;
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult GenerateHandle(KAutoObject obj, out int handle)
+        public Result GenerateHandle(KAutoObject obj, out int handle)
         {
             handle = 0;
 
@@ -99,10 +100,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult ReserveHandle(out int handle)
+        public Result ReserveHandle(out int handle)
         {
             handle = 0;
 
@@ -131,7 +132,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         public void CancelHandleReservation(int handle)
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
index 6a2d45ea48..8d9cd242f7 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
@@ -5,6 +5,7 @@ using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Memory;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using Ryujinx.Memory;
 using System;
 using System.Collections.Generic;
@@ -116,7 +117,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             Debugger = new HleProcessDebugger(this);
         }
 
-        public KernelResult InitializeKip(
+        public Result InitializeKip(
             ProcessCreationInfo creationInfo,
             ReadOnlySpan<int> capabilities,
             KPageList pageList,
@@ -151,7 +152,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 ? KernelContext.LargeMemoryBlockSlabManager
                 : KernelContext.SmallMemoryBlockSlabManager;
 
-            KernelResult result = MemoryManager.InitializeForProcess(
+            Result result = MemoryManager.InitializeForProcess(
                 addrSpaceType,
                 aslrEnabled,
                 !aslrEnabled,
@@ -160,7 +161,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 codeSize,
                 slabManager);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -172,14 +173,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
             result = MemoryManager.MapPages(codeAddress, pageList, MemoryState.CodeStatic, KMemoryPermission.None);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             result = Capabilities.InitializeForKernel(capabilities, MemoryManager);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -187,7 +188,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             return ParseProcessInfo(creationInfo);
         }
 
-        public KernelResult Initialize(
+        public Result Initialize(
             ProcessCreationInfo creationInfo,
             ReadOnlySpan<int> capabilities,
             KResourceLimit resourceLimit,
@@ -255,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
             ulong codeSize = codePagesCount * KPageTableBase.PageSize;
 
-            KernelResult result = MemoryManager.InitializeForProcess(
+            Result result = MemoryManager.InitializeForProcess(
                 addrSpaceType,
                 aslrEnabled,
                 !aslrEnabled,
@@ -264,7 +265,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 codeSize,
                 slabManager);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 CleanUpForError();
 
@@ -284,7 +285,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 MemoryState.CodeStatic,
                 KMemoryPermission.None);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 CleanUpForError();
 
@@ -293,7 +294,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
             result = Capabilities.InitializeForUser(capabilities, MemoryManager);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 CleanUpForError();
 
@@ -302,7 +303,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
             result = ParseProcessInfo(creationInfo);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 CleanUpForError();
             }
@@ -310,7 +311,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             return result;
         }
 
-        private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo)
+        private Result ParseProcessInfo(ProcessCreationInfo creationInfo)
         {
             // Ensure that the current kernel version is equal or above to the minimum required.
             uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
@@ -334,9 +335,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 }
             }
 
-            KernelResult result = AllocateThreadLocalStorage(out ulong userExceptionContextAddress);
+            Result result = AllocateThreadLocalStorage(out ulong userExceptionContextAddress);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -378,14 +379,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
             GenerateRandomEntropy();
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult AllocateThreadLocalStorage(out ulong address)
+        public Result AllocateThreadLocalStorage(out ulong address)
         {
             KernelContext.CriticalSection.Enter();
 
-            KernelResult result;
+            Result result;
 
             if (_freeTlsPages.Count > 0)
             {
@@ -404,14 +405,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                     _fullTlsPages.Add(pageInfo.PageVirtualAddress, pageInfo);
                 }
 
-                result = KernelResult.Success;
+                result = Result.Success;
             }
             else
             {
                 // Otherwise, we need to create a new one.
                 result = AllocateTlsPage(out KTlsPageInfo pageInfo);
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     if (!pageInfo.TryGetFreePage(out address))
                     {
@@ -431,7 +432,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             return result;
         }
 
-        private KernelResult AllocateTlsPage(out KTlsPageInfo pageInfo)
+        private Result AllocateTlsPage(out KTlsPageInfo pageInfo)
         {
             pageInfo = default;
 
@@ -445,7 +446,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
             ulong regionPagesCount = regionSize / KPageTableBase.PageSize;
 
-            KernelResult result = MemoryManager.MapPages(
+            Result result = MemoryManager.MapPages(
                 1,
                 KPageTableBase.PageSize,
                 tlsPagePa,
@@ -456,7 +457,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 KMemoryPermission.ReadAndWrite,
                 out ulong tlsPageVa);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 KernelContext.UserSlabHeapPages.Free(tlsPagePa);
             }
@@ -470,13 +471,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             return result;
         }
 
-        public KernelResult FreeThreadLocalStorage(ulong tlsSlotAddr)
+        public Result FreeThreadLocalStorage(ulong tlsSlotAddr)
         {
             ulong tlsPageAddr = BitUtils.AlignDown<ulong>(tlsSlotAddr, KPageTableBase.PageSize);
 
             KernelContext.CriticalSection.Enter();
 
-            KernelResult result = KernelResult.Success;
+            Result result = Result.Success;
 
             KTlsPageInfo pageInfo;
 
@@ -506,7 +507,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
                     FreeTlsPage(pageInfo);
 
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
             }
 
@@ -515,11 +516,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             return result;
         }
 
-        private KernelResult FreeTlsPage(KTlsPageInfo pageInfo)
+        private Result FreeTlsPage(KTlsPageInfo pageInfo)
         {
-            KernelResult result = MemoryManager.UnmapForKernel(pageInfo.PageVirtualAddress, 1, MemoryState.ThreadLocal);
+            Result result = MemoryManager.UnmapForKernel(pageInfo.PageVirtualAddress, 1, MemoryState.ThreadLocal);
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 KernelContext.UserSlabHeapPages.Free(pageInfo.PagePhysicalAddress);
             }
@@ -532,7 +533,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             // TODO.
         }
 
-        public KernelResult Start(int mainThreadPriority, ulong stackSize)
+        public Result Start(int mainThreadPriority, ulong stackSize)
         {
             lock (_processLock)
             {
@@ -580,7 +581,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                     }
                 }
 
-                KernelResult result;
+                Result result;
 
                 KThread mainThread = null;
 
@@ -627,7 +628,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                         KMemoryPermission.ReadAndWrite,
                         out ulong stackBottom);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         CleanUpForError();
 
@@ -643,7 +644,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
                 result = MemoryManager.SetHeapCapacity(heapCapacity);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     CleanUpForError();
 
@@ -654,7 +655,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
                 result = HandleTable.Initialize(Capabilities.HandleTableSize);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     CleanUpForError();
 
@@ -673,7 +674,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                     ThreadType.User,
                     _customThreadStart);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     CleanUpForError();
 
@@ -682,7 +683,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
                 result = HandleTable.GenerateHandle(mainThread, out int mainThreadHandle);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     CleanUpForError();
 
@@ -700,14 +701,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
                 result = mainThread.Start();
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     SetState(oldState);
 
                     CleanUpForError();
                 }
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     mainThread.IncrementReferenceCount();
                 }
@@ -729,7 +730,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             }
         }
 
-        public KernelResult InitializeThread(
+        public Result InitializeThread(
             KThread thread,
             ulong entrypoint,
             ulong argsPtr,
@@ -888,9 +889,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             return _signaled;
         }
 
-        public KernelResult Terminate()
+        public Result Terminate()
         {
-            KernelResult result;
+            Result result;
 
             bool shallTerminate = false;
 
@@ -910,7 +911,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                         shallTerminate = true;
                     }
 
-                    result = KernelResult.Success;
+                    result = Result.Success;
                 }
                 else
                 {
@@ -1044,9 +1045,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             KernelContext.CriticalSection.Leave();
         }
 
-        public KernelResult ClearIfNotExited()
+        public Result ClearIfNotExited()
         {
-            KernelResult result;
+            Result result;
 
             KernelContext.CriticalSection.Enter();
 
@@ -1056,7 +1057,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 {
                     _signaled = false;
 
-                    result = KernelResult.Success;
+                    result = Result.Success;
                 }
                 else
                 {
@@ -1107,7 +1108,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
         protected override void Destroy() => Context.Dispose();
 
-        public KernelResult SetActivity(bool pause)
+        public Result SetActivity(bool pause)
         {
             KernelContext.CriticalSection.Enter();
 
@@ -1154,7 +1155,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
                 KernelContext.CriticalSection.Leave();
 
-                return KernelResult.Success;
+                return Result.Success;
             }
 
             KernelContext.CriticalSection.Leave();
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
index a08c4b263e..ef55a165fd 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
@@ -1,6 +1,7 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Memory;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Numerics;
 
@@ -25,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             IrqAccessMask = new byte[0x80];
         }
 
-        public KernelResult InitializeForKernel(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
+        public Result InitializeForKernel(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
         {
             AllowedCpuCoresMask    = 0xf;
             AllowedThreadPriosMask = ulong.MaxValue;
@@ -35,12 +36,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             return Parse(capabilities, memoryManager);
         }
 
-        public KernelResult InitializeForUser(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
+        public Result InitializeForUser(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
         {
             return Parse(capabilities, memoryManager);
         }
 
-        private KernelResult Parse(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
+        private Result Parse(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
         {
             int mask0 = 0;
             int mask1 = 0;
@@ -51,9 +52,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
                 if (((cap + 1) & ~cap) != 0x40)
                 {
-                    KernelResult result = ParseCapability(cap, ref mask0, ref mask1, memoryManager);
+                    Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         return result;
                     }
@@ -96,7 +97,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                         ? KMemoryPermission.Read
                         : KMemoryPermission.ReadAndWrite;
 
-                    KernelResult result;
+                    Result result;
 
                     if ((cap >> 31) != 0)
                     {
@@ -107,17 +108,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                         result = memoryManager.MapIoMemory(address, size, perm);
                     }
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         return result;
                     }
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        private KernelResult ParseCapability(int cap, ref int mask0, ref int mask1, KPageTableBase memoryManager)
+        private Result ParseCapability(int cap, ref int mask0, ref int mask1, KPageTableBase memoryManager)
         {
             int code = (cap + 1) & ~cap;
 
@@ -127,7 +128,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             }
             else if (code == 0)
             {
-                return KernelResult.Success;
+                return Result.Success;
             }
 
             int codeMask = 1 << (32 - BitOperations.LeadingZeroCount((uint)code + 1));
@@ -300,7 +301,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 default: return KernelResult.InvalidCapability;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         private static ulong GetMaskFromMinMax(int min, int max)
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
index a084125291..77fcdf33be 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
@@ -7,23 +7,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
     {
         public ulong Pc => 0UL;
 
-        public ulong CntfrqEl0 { get => 0; set { } }
+        public ulong CntfrqEl0 { get; set; }
         public ulong CntpctEl0 => 0UL;
 
-        public long TpidrEl0 { get => 0; set { } }
-        public long TpidrroEl0 { get => 0; set { } }
+        public long TpidrEl0 { get; set; }
+        public long TpidrroEl0 { get; set; }
 
-        public uint Pstate { get => 0; set { } }
+        public uint Pstate { get; set; }
 
-        public uint Fpcr { get => 0; set { } }
-        public uint Fpsr { get => 0; set { } }
+        public uint Fpcr { get; set; }
+        public uint Fpsr { get; set; }
 
         public bool IsAarch32 { get => false; set { } }
 
         public bool Running { get; private set; } = true;
 
-        public ulong GetX(int index) => 0UL;
-        public void SetX(int index, ulong value) { }
+        private readonly ulong[] _x = new ulong[32];
+
+        public ulong GetX(int index) => _x[index];
+        public void SetX(int index, ulong value) => _x[index] = value;
 
         public V128 GetV(int index) => default;
         public void SetV(int index, V128 value) { }
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
index c3fb8b8ad9..e23274ebca 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
@@ -7,13 +7,14 @@ using Ryujinx.HLE.HOS.Kernel.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Memory;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Threading;
 
 namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 {
     [SvcImpl]
-    class Syscall
+    class Syscall : ISyscallApi
     {
         private readonly KernelContext _context;
 
@@ -25,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         // Process
 
         [Svc(0x24)]
-        public KernelResult GetProcessId(out ulong pid, int handle)
+        public Result GetProcessId(out ulong pid, int handle)
         {
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
@@ -46,11 +47,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             pid = process?.Pid ?? 0;
 
             return process != null
-                ? KernelResult.Success
+                ? Result.Success
                 : KernelResult.InvalidHandle;
         }
 
-        public KernelResult CreateProcess(
+        public Result CreateProcess(
             out int handle,
             ProcessCreationInfo info,
             ReadOnlySpan<int> capabilities,
@@ -118,7 +119,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 _ => MemoryRegion.NvServices
             };
 
-            KernelResult result = process.Initialize(
+            Result result = process.Initialize(
                 info,
                 capabilities,
                 resourceLimit,
@@ -126,7 +127,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 contextFactory,
                 customThreadStart);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -136,7 +137,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             return handleTable.GenerateHandle(process, out handle);
         }
 
-        public KernelResult StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
+        public Result StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
         {
             KProcess process = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
 
@@ -157,30 +158,30 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             process.DefaultCpuCore = cpuCore;
 
-            KernelResult result = process.Start(priority, mainThreadStackSize);
+            Result result = process.Start(priority, mainThreadStackSize);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             process.IncrementReferenceCount();
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x5f)]
-        public KernelResult FlushProcessDataCache(int processHandle, ulong address, ulong size)
+        public Result FlushProcessDataCache(int processHandle, ulong address, ulong size)
         {
             // FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0.
             // As we don't support (and don't actually need) to flush the cache, this is stubbed.
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         // IPC
 
         [Svc(0x1f)]
-        public KernelResult ConnectToNamedPort(out int handle, [PointerSized] ulong namePtr)
+        public Result ConnectToNamedPort(out int handle, [PointerSized] ulong namePtr)
         {
             handle = 0;
 
@@ -192,7 +193,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             return ConnectToNamedPort(out handle, name);
         }
 
-        public KernelResult ConnectToNamedPort(out int handle, string name)
+        public Result ConnectToNamedPort(out int handle, string name)
         {
             handle = 0;
 
@@ -210,16 +211,16 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
-            KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
+            Result result = currentProcess.HandleTable.ReserveHandle(out handle);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             result = clientPort.Connect(out KClientSession clientSession);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 currentProcess.HandleTable.CancelHandleReservation(handle);
 
@@ -234,7 +235,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x21)]
-        public KernelResult SendSyncRequest(int handle)
+        public Result SendSyncRequest(int handle)
         {
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
@@ -249,7 +250,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x22)]
-        public KernelResult SendSyncRequestWithUserBuffer(
+        public Result SendSyncRequestWithUserBuffer(
             [PointerSized] ulong messagePtr,
             [PointerSized] ulong messageSize,
             int handle)
@@ -271,9 +272,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
-            KernelResult result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
+            Result result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -289,9 +290,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 result = session.SendSyncRequest(messagePtr, messageSize);
             }
 
-            KernelResult result2 = currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize);
+            Result result2 = currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize);
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 result = result2;
             }
@@ -300,7 +301,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x23)]
-        public KernelResult SendAsyncRequestWithUserBuffer(
+        public Result SendAsyncRequestWithUserBuffer(
             out int doneEventHandle,
             [PointerSized] ulong messagePtr,
             [PointerSized] ulong messageSize,
@@ -325,9 +326,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
-            KernelResult result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
+            Result result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -353,18 +354,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
                 result = currentProcess.HandleTable.GenerateHandle(doneEvent.ReadableEvent, out doneEventHandle);
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     result = session.SendAsyncRequest(doneEvent.WritableEvent, messagePtr, messageSize);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         currentProcess.HandleTable.CloseHandle(doneEventHandle);
                     }
                 }
             }
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 resourceLimit?.Release(LimitableResource.Event, 1);
 
@@ -375,11 +376,20 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x40)]
-        public KernelResult CreateSession(
+        public Result CreateSession(
             out int serverSessionHandle,
             out int clientSessionHandle,
             bool isLight,
             [PointerSized] ulong namePtr)
+        {
+            return CreateSession(out serverSessionHandle, out clientSessionHandle, isLight, null);
+        }
+
+        public Result CreateSession(
+            out int serverSessionHandle,
+            out int clientSessionHandle,
+            bool isLight,
+            string name)
         {
             serverSessionHandle = 0;
             clientSessionHandle = 0;
@@ -393,7 +403,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 return KernelResult.ResLimitExceeded;
             }
 
-            KernelResult result;
+            Result result;
 
             if (isLight)
             {
@@ -401,11 +411,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
                 result = currentProcess.HandleTable.GenerateHandle(session.ServerSession, out serverSessionHandle);
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     result = currentProcess.HandleTable.GenerateHandle(session.ClientSession, out clientSessionHandle);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         currentProcess.HandleTable.CloseHandle(serverSessionHandle);
 
@@ -422,11 +432,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
                 result = currentProcess.HandleTable.GenerateHandle(session.ServerSession, out serverSessionHandle);
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     result = currentProcess.HandleTable.GenerateHandle(session.ClientSession, out clientSessionHandle);
 
-                    if (result != KernelResult.Success)
+                    if (result != Result.Success)
                     {
                         currentProcess.HandleTable.CloseHandle(serverSessionHandle);
 
@@ -442,7 +452,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x41)]
-        public KernelResult AcceptSession(out int sessionHandle, int portHandle)
+        public Result AcceptSession(out int sessionHandle, int portHandle)
         {
             sessionHandle = 0;
 
@@ -455,9 +465,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 return KernelResult.InvalidHandle;
             }
 
-            KernelResult result = currentProcess.HandleTable.ReserveHandle(out int handle);
+            Result result = currentProcess.HandleTable.ReserveHandle(out int handle);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -481,7 +491,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
                 sessionHandle = handle;
 
-                result = KernelResult.Success;
+                result = Result.Success;
             }
             else
             {
@@ -494,7 +504,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x43)]
-        public KernelResult ReplyAndReceive(
+        public Result ReplyAndReceive(
             out int handleIndex,
             [PointerSized] ulong handlesPtr,
             int handlesCount,
@@ -537,7 +547,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             return ReplyAndReceive(out handleIndex, handles, replyTargetHandle, timeout);
         }
 
-        public KernelResult ReplyAndReceive(out int handleIndex, ReadOnlySpan<int> handles, int replyTargetHandle, long timeout)
+        public Result ReplyAndReceive(out int handleIndex, ReadOnlySpan<int> handles, int replyTargetHandle, long timeout)
         {
             handleIndex = 0;
 
@@ -557,7 +567,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 syncObjs[index] = obj;
             }
 
-            KernelResult result = KernelResult.Success;
+            Result result = Result.Success;
 
             if (replyTargetHandle != 0)
             {
@@ -573,14 +583,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 }
             }
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 if (timeout > 0)
                 {
                     timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
                 }
 
-                while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success)
+                while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == Result.Success)
                 {
                     KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]);
 
@@ -600,7 +610,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x44)]
-        public KernelResult ReplyAndReceiveWithUserBuffer(
+        public Result ReplyAndReceiveWithUserBuffer(
             out int handleIndex,
             [PointerSized] ulong messagePtr,
             [PointerSized] ulong messageSize,
@@ -630,9 +640,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 return KernelResult.UserCopyFailed;
             }
 
-            KernelResult result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
+            Result result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -676,14 +686,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 }
             }
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 if (timeout > 0)
                 {
                     timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
                 }
 
-                while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success)
+                while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == Result.Success)
                 {
                     KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]);
 
@@ -705,12 +715,23 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x70)]
-        public KernelResult CreatePort(
+        public Result CreatePort(
             out int serverPortHandle,
             out int clientPortHandle,
             int maxSessions,
             bool isLight,
             [PointerSized] ulong namePtr)
+        {
+            // The kernel doesn't use the name pointer, so we can just pass null as the name.
+            return CreatePort(out serverPortHandle, out clientPortHandle, maxSessions, isLight, null);
+        }
+
+        public Result CreatePort(
+            out int serverPortHandle,
+            out int clientPortHandle,
+            int maxSessions,
+            bool isLight,
+            string name)
         {
             serverPortHandle = clientPortHandle = 0;
 
@@ -719,20 +740,20 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 return KernelResult.MaximumExceeded;
             }
 
-            KPort port = new KPort(_context, maxSessions, isLight, (long)namePtr);
+            KPort port = new KPort(_context, maxSessions, isLight, name);
 
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
-            KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ClientPort, out clientPortHandle);
+            Result result = currentProcess.HandleTable.GenerateHandle(port.ClientPort, out clientPortHandle);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out serverPortHandle);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 currentProcess.HandleTable.CloseHandle(clientPortHandle);
             }
@@ -741,7 +762,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x71)]
-        public KernelResult ManageNamedPort(out int handle, [PointerSized] ulong namePtr, int maxSessions)
+        public Result ManageNamedPort(out int handle, [PointerSized] ulong namePtr, int maxSessions)
         {
             handle = 0;
 
@@ -758,7 +779,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             return ManageNamedPort(out handle, name, maxSessions);
         }
 
-        public KernelResult ManageNamedPort(out int handle, string name, int maxSessions)
+        public Result ManageNamedPort(out int handle, string name, int maxSessions)
         {
             handle = 0;
 
@@ -772,20 +793,20 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 return KAutoObject.RemoveName(_context, name);
             }
 
-            KPort port = new KPort(_context, maxSessions, false, 0);
+            KPort port = new KPort(_context, maxSessions, false, null);
 
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
-            KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle);
+            Result result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             result = port.ClientPort.SetName(name);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 currentProcess.HandleTable.CloseHandle(handle);
             }
@@ -794,7 +815,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x72)]
-        public KernelResult ConnectToPort(out int clientSessionHandle, int clientPortHandle)
+        public Result ConnectToPort(out int clientSessionHandle, int clientPortHandle)
         {
             clientSessionHandle = 0;
 
@@ -807,9 +828,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 return KernelResult.InvalidHandle;
             }
 
-            KernelResult result = currentProcess.HandleTable.ReserveHandle(out int handle);
+            Result result = currentProcess.HandleTable.ReserveHandle(out int handle);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -829,7 +850,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 session = clientSession;
             }
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 currentProcess.HandleTable.CancelHandleReservation(handle);
 
@@ -848,7 +869,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         // Memory
 
         [Svc(1)]
-        public KernelResult SetHeapSize([PointerSized] out ulong address, [PointerSized] ulong size)
+        public Result SetHeapSize([PointerSized] out ulong address, [PointerSized] ulong size)
         {
             if ((size & 0xfffffffe001fffff) != 0)
             {
@@ -863,7 +884,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(2)]
-        public KernelResult SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
+        public Result SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
         {
             if (!PageAligned(address))
             {
@@ -896,7 +917,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(3)]
-        public KernelResult SetMemoryAttribute(
+        public Result SetMemoryAttribute(
             [PointerSized] ulong address,
             [PointerSized] ulong size,
             MemoryAttribute attributeMask,
@@ -927,7 +948,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 return KernelResult.InvalidMemState;
             }
 
-            KernelResult result = process.MemoryManager.SetMemoryAttribute(
+            Result result = process.MemoryManager.SetMemoryAttribute(
                 address,
                 size,
                 attributeMask,
@@ -937,7 +958,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(4)]
-        public KernelResult MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
+        public Result MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
         {
             if (!PageAligned(src | dst))
             {
@@ -974,7 +995,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(5)]
-        public KernelResult UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
+        public Result UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
         {
             if (!PageAligned(src | dst))
             {
@@ -1011,21 +1032,21 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(6)]
-        public KernelResult QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address)
+        public Result QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address)
         {
-            KernelResult result = QueryMemory(out MemoryInfo info, out pageInfo, address);
+            Result result = QueryMemory(out MemoryInfo info, out pageInfo, address);
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 return KernelTransfer.KernelToUser(infoPtr, info)
-                    ? KernelResult.Success
+                    ? Result.Success
                     : KernelResult.InvalidMemState;
             }
 
             return result;
         }
 
-        public KernelResult QueryMemory(out MemoryInfo info, out ulong pageInfo, ulong address)
+        public Result QueryMemory(out MemoryInfo info, out ulong pageInfo, ulong address)
         {
             KProcess process = KernelStatic.GetCurrentProcess();
 
@@ -1042,11 +1063,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             pageInfo = 0;
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x13)]
-        public KernelResult MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
+        public Result MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
         {
             if (!PageAligned(address))
             {
@@ -1093,7 +1114,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x14)]
-        public KernelResult UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
+        public Result UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
         {
             if (!PageAligned(address))
             {
@@ -1134,7 +1155,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x15)]
-        public KernelResult CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
+        public Result CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
         {
             handle = 0;
 
@@ -1181,9 +1202,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             KTransferMemory transferMemory = new KTransferMemory(_context);
 
-            KernelResult result = transferMemory.Initialize(address, size, permission);
+            Result result = transferMemory.Initialize(address, size, permission);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 CleanUpForError();
 
@@ -1198,7 +1219,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x51)]
-        public KernelResult MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
+        public Result MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
         {
             if (!PageAligned(address))
             {
@@ -1245,7 +1266,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x52)]
-        public KernelResult UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
+        public Result UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
         {
             if (!PageAligned(address))
             {
@@ -1286,7 +1307,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x2c)]
-        public KernelResult MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
+        public Result MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
         {
             if (!PageAligned(address))
             {
@@ -1322,7 +1343,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x2d)]
-        public KernelResult UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
+        public Result UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
         {
             if (!PageAligned(address))
             {
@@ -1358,7 +1379,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x4b)]
-        public KernelResult CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size)
+        public Result CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size)
         {
             handle = 0;
 
@@ -1388,9 +1409,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 return KernelResult.InvalidMemState;
             }
 
-            KernelResult result = codeMemory.Initialize(address, size);
+            Result result = codeMemory.Initialize(address, size);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -1399,7 +1420,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x4c)]
-        public KernelResult ControlCodeMemory(
+        public Result ControlCodeMemory(
             int handle,
             CodeMemoryOperation op,
             ulong address,
@@ -1477,7 +1498,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x73)]
-        public KernelResult SetProcessMemoryPermission(
+        public Result SetProcessMemoryPermission(
             int handle,
             [PointerSized] ulong src,
             [PointerSized] ulong size,
@@ -1519,7 +1540,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x74)]
-        public KernelResult MapProcessMemory(
+        public Result MapProcessMemory(
             [PointerSized] ulong dst,
             int handle,
             ulong src,
@@ -1556,7 +1577,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             KPageList pageList = new KPageList();
 
-            KernelResult result = srcProcess.MemoryManager.GetPagesIfStateEquals(
+            Result result = srcProcess.MemoryManager.GetPagesIfStateEquals(
                 src,
                 size,
                 MemoryState.MapProcessAllowed,
@@ -1567,7 +1588,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 MemoryAttribute.None,
                 pageList);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -1576,7 +1597,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x75)]
-        public KernelResult UnmapProcessMemory(
+        public Result UnmapProcessMemory(
             [PointerSized] ulong dst,
             int handle,
             ulong src,
@@ -1611,18 +1632,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 return KernelResult.InvalidMemRange;
             }
 
-            KernelResult result = dstProcess.MemoryManager.UnmapProcessMemory(dst, size, srcProcess.MemoryManager, src);
+            Result result = dstProcess.MemoryManager.UnmapProcessMemory(dst, size, srcProcess.MemoryManager, src);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x77)]
-        public KernelResult MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
+        public Result MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
         {
             if (!PageAligned(dst) || !PageAligned(src))
             {
@@ -1660,7 +1681,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x78)]
-        public KernelResult UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
+        public Result UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
         {
             if (!PageAligned(dst) || !PageAligned(src))
             {
@@ -1705,19 +1726,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         // System
 
         [Svc(0x7b)]
-        public KernelResult TerminateProcess(int handle)
+        public Result TerminateProcess(int handle)
         {
             KProcess process = KernelStatic.GetCurrentProcess();
 
             process = process.HandleTable.GetObject<KProcess>(handle);
 
-            KernelResult result;
+            Result result;
 
             if (process != null)
             {
                 if (process == KernelStatic.GetCurrentProcess())
                 {
-                    result = KernelResult.Success;
+                    result = Result.Success;
                     process.DecrementToZeroWhileTerminatingCurrent();
                 }
                 else
@@ -1741,19 +1762,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x11)]
-        public KernelResult SignalEvent(int handle)
+        public Result SignalEvent(int handle)
         {
             KProcess process = KernelStatic.GetCurrentProcess();
 
             KWritableEvent writableEvent = process.HandleTable.GetObject<KWritableEvent>(handle);
 
-            KernelResult result;
+            Result result;
 
             if (writableEvent != null)
             {
                 writableEvent.Signal();
 
-                result = KernelResult.Success;
+                result = Result.Success;
             }
             else
             {
@@ -1764,9 +1785,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x12)]
-        public KernelResult ClearEvent(int handle)
+        public Result ClearEvent(int handle)
         {
-            KernelResult result;
+            Result result;
 
             KProcess process = KernelStatic.GetCurrentProcess();
 
@@ -1787,21 +1808,21 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x16)]
-        public KernelResult CloseHandle(int handle)
+        public Result CloseHandle(int handle)
         {
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
-            return currentProcess.HandleTable.CloseHandle(handle) ? KernelResult.Success : KernelResult.InvalidHandle;
+            return currentProcess.HandleTable.CloseHandle(handle) ? Result.Success : KernelResult.InvalidHandle;
         }
 
         [Svc(0x17)]
-        public KernelResult ResetSignal(int handle)
+        public Result ResetSignal(int handle)
         {
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
             KReadableEvent readableEvent = currentProcess.HandleTable.GetObject<KReadableEvent>(handle);
 
-            KernelResult result;
+            Result result;
 
             if (readableEvent != null)
             {
@@ -1868,7 +1889,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x29)]
-        public KernelResult GetInfo(out ulong value, InfoType id, int handle, long subId)
+        public Result GetInfo(out ulong value, InfoType id, int handle, long subId)
         {
             value = 0;
 
@@ -2010,9 +2031,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                             KHandleTable handleTable = currentProcess.HandleTable;
                             KResourceLimit resourceLimit = currentProcess.ResourceLimit;
 
-                            KernelResult result = handleTable.GenerateHandle(resourceLimit, out int resLimHandle);
+                            Result result = handleTable.GenerateHandle(resourceLimit, out int resLimHandle);
 
-                            if (result != KernelResult.Success)
+                            if (result != Result.Success)
                             {
                                 return result;
                             }
@@ -2081,7 +2102,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
                         if (subId != -1 && subId != currentCore)
                         {
-                            return KernelResult.Success;
+                            return Result.Success;
                         }
 
                         KScheduler scheduler = _context.Schedulers[currentCore];
@@ -2122,12 +2143,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                         KProcess currentProcess = KernelStatic.GetCurrentProcess();
                         KHandleTable handleTable = currentProcess.HandleTable;
 
-                        KernelResult result = handleTable.GenerateHandle(currentProcess, out int outHandle);
+                        Result result = handleTable.GenerateHandle(currentProcess, out int outHandle);
 
-                        if (result != KernelResult.Success)
+                        if (result != Result.Success)
                         {
                             return result;
-                        }                        
+                        }
 
                         value = (ulong)outHandle;
 
@@ -2137,23 +2158,23 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 default: return KernelResult.InvalidEnumValue;
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x45)]
-        public KernelResult CreateEvent(out int wEventHandle, out int rEventHandle)
+        public Result CreateEvent(out int wEventHandle, out int rEventHandle)
         {
             KEvent Event = new KEvent(_context);
 
             KProcess process = KernelStatic.GetCurrentProcess();
 
-            KernelResult result = process.HandleTable.GenerateHandle(Event.WritableEvent, out wEventHandle);
+            Result result = process.HandleTable.GenerateHandle(Event.WritableEvent, out wEventHandle);
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 result = process.HandleTable.GenerateHandle(Event.ReadableEvent, out rEventHandle);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     process.HandleTable.CloseHandle(wEventHandle);
                 }
@@ -2167,7 +2188,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x65)]
-        public KernelResult GetProcessList(out int count, [PointerSized] ulong address, int maxCount)
+        public Result GetProcessList(out int count, [PointerSized] ulong address, int maxCount)
         {
             count = 0;
 
@@ -2213,11 +2234,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             count = copyCount;
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x6f)]
-        public KernelResult GetSystemInfo(out long value, uint id, int handle, long subId)
+        public Result GetSystemInfo(out long value, uint id, int handle, long subId)
         {
             value = 0;
 
@@ -2270,11 +2291,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x30)]
-        public KernelResult GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource)
+        public Result GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource)
         {
             limitValue = 0;
 
@@ -2292,11 +2313,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             limitValue = resourceLimit.GetLimitValue(resource);
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x31)]
-        public KernelResult GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource)
+        public Result GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource)
         {
             limitValue = 0;
 
@@ -2314,11 +2335,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             limitValue = resourceLimit.GetCurrentValue(resource);
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x37)]
-        public KernelResult GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource)
+        public Result GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource)
         {
             peak = 0;
 
@@ -2336,11 +2357,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             peak = resourceLimit.GetPeakValue(resource);
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x7d)]
-        public KernelResult CreateResourceLimit(out int handle)
+        public Result CreateResourceLimit(out int handle)
         {
             KResourceLimit limit = new KResourceLimit(_context);
 
@@ -2350,7 +2371,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x7e)]
-        public KernelResult SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue)
+        public Result SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue)
         {
             if (resource >= LimitableResource.Count)
             {
@@ -2370,7 +2391,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         // Thread
 
         [Svc(8)]
-        public KernelResult CreateThread(
+        public Result CreateThread(
             out int handle,
             [PointerSized] ulong entrypoint,
             [PointerSized] ulong argsPtr,
@@ -2381,7 +2402,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             return CreateThread(out handle, entrypoint, argsPtr, stackTop, priority, cpuCore, null);
         }
 
-        public KernelResult CreateThread(
+        public Result CreateThread(
             out int handle,
             ulong entrypoint,
             ulong argsPtr,
@@ -2419,7 +2440,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             KThread thread = new KThread(_context);
 
-            KernelResult result = currentProcess.InitializeThread(
+            Result result = currentProcess.InitializeThread(
                 thread,
                 entrypoint,
                 argsPtr,
@@ -2428,7 +2449,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 cpuCore,
                 customThreadStart);
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 KProcess process = KernelStatic.GetCurrentProcess();
 
@@ -2445,7 +2466,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(9)]
-        public KernelResult StartThread(int handle)
+        public Result StartThread(int handle)
         {
             KProcess process = KernelStatic.GetCurrentProcess();
 
@@ -2455,9 +2476,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             {
                 thread.IncrementReferenceCount();
 
-                KernelResult result = thread.Start();
+                Result result = thread.Start();
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     thread.IncrementReferenceCount();
                 }
@@ -2499,7 +2520,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0xc)]
-        public KernelResult GetThreadPriority(out int priority, int handle)
+        public Result GetThreadPriority(out int priority, int handle)
         {
             KProcess process = KernelStatic.GetCurrentProcess();
 
@@ -2509,7 +2530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             {
                 priority = thread.DynamicPriority;
 
-                return KernelResult.Success;
+                return Result.Success;
             }
             else
             {
@@ -2520,7 +2541,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0xd)]
-        public KernelResult SetThreadPriority(int handle, int priority)
+        public Result SetThreadPriority(int handle, int priority)
         {
             // TODO: NPDM check.
 
@@ -2535,11 +2556,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             thread.SetPriority(priority);
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0xe)]
-        public KernelResult GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle)
+        public Result GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle)
         {
             KProcess process = KernelStatic.GetCurrentProcess();
 
@@ -2550,7 +2571,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 preferredCore = thread.PreferredCore;
                 affinityMask = thread.AffinityMask;
 
-                return KernelResult.Success;
+                return Result.Success;
             }
             else
             {
@@ -2562,7 +2583,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0xf)]
-        public KernelResult SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask)
+        public Result SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask)
         {
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
@@ -2617,7 +2638,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x25)]
-        public KernelResult GetThreadId(out ulong threadUid, int handle)
+        public Result GetThreadId(out ulong threadUid, int handle)
         {
             KProcess process = KernelStatic.GetCurrentProcess();
 
@@ -2627,7 +2648,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             {
                 threadUid = thread.ThreadUid;
 
-                return KernelResult.Success;
+                return Result.Success;
             }
             else
             {
@@ -2638,7 +2659,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x32)]
-        public KernelResult SetThreadActivity(int handle, bool pause)
+        public Result SetThreadActivity(int handle, bool pause)
         {
             KProcess process = KernelStatic.GetCurrentProcess();
 
@@ -2663,7 +2684,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x33)]
-        public KernelResult GetThreadContext3([PointerSized] ulong address, int handle)
+        public Result GetThreadContext3([PointerSized] ulong address, int handle)
         {
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
             KThread currentThread = KernelStatic.GetCurrentThread();
@@ -2685,12 +2706,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 return KernelResult.InvalidThread;
             }
 
-            KernelResult result = thread.GetThreadContext3(out ThreadContext context);
+            Result result = thread.GetThreadContext3(out ThreadContext context);
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 return KernelTransfer.KernelToUser(address, context)
-                    ? KernelResult.Success
+                    ? Result.Success
                     : KernelResult.InvalidMemState;
             }
 
@@ -2700,7 +2721,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         // Thread synchronization
 
         [Svc(0x18)]
-        public KernelResult WaitSynchronization(out int handleIndex, [PointerSized] ulong handlesPtr, int handlesCount, long timeout)
+        public Result WaitSynchronization(out int handleIndex, [PointerSized] ulong handlesPtr, int handlesCount, long timeout)
         {
             handleIndex = 0;
 
@@ -2711,8 +2732,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             KThread currentThread = KernelStatic.GetCurrentThread();
 
-            var syncObjs = new Span<KSynchronizationObject>(currentThread.WaitSyncObjects).Slice(0, handlesCount);
-
             if (handlesCount != 0)
             {
                 KProcess currentProcess = KernelStatic.GetCurrentProcess();
@@ -2741,9 +2760,32 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                     return KernelResult.UserCopyFailed;
                 }
 
+                return WaitSynchronization(out handleIndex, handles, timeout);
+            }
+
+            return WaitSynchronization(out handleIndex, ReadOnlySpan<int>.Empty, timeout);
+        }
+
+        public Result WaitSynchronization(out int handleIndex, ReadOnlySpan<int> handles, long timeout)
+        {
+            handleIndex = 0;
+
+            if ((uint)handles.Length > KThread.MaxWaitSyncObjects)
+            {
+                return KernelResult.MaximumExceeded;
+            }
+
+            KThread currentThread = KernelStatic.GetCurrentThread();
+
+            var syncObjs = new Span<KSynchronizationObject>(currentThread.WaitSyncObjects).Slice(0, handles.Length);
+
+            if (handles.Length != 0)
+            {
+                KProcess currentProcess = KernelStatic.GetCurrentProcess();
+
                 int processedHandles = 0;
 
-                for (; processedHandles < handlesCount; processedHandles++)
+                for (; processedHandles < handles.Length; processedHandles++)
                 {
                     KSynchronizationObject syncObj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[processedHandles]);
 
@@ -2757,7 +2799,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                     syncObj.IncrementReferenceCount();
                 }
 
-                if (processedHandles != handlesCount)
+                if (processedHandles != handles.Length)
                 {
                     // One or more handles are invalid.
                     for (int index = 0; index < processedHandles; index++)
@@ -2774,14 +2816,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
             }
 
-            KernelResult result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex);
+            Result result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex);
 
             if (result == KernelResult.PortRemoteClosed)
             {
-                result = KernelResult.Success;
+                result = Result.Success;
             }
 
-            for (int index = 0; index < handlesCount; index++)
+            for (int index = 0; index < handles.Length; index++)
             {
                 currentThread.WaitSyncObjects[index].DecrementReferenceCount();
             }
@@ -2790,7 +2832,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x19)]
-        public KernelResult CancelSynchronization(int handle)
+        public Result CancelSynchronization(int handle)
         {
             KProcess process = KernelStatic.GetCurrentProcess();
 
@@ -2803,11 +2845,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
 
             thread.CancelSynchronization();
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x1a)]
-        public KernelResult ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle)
+        public Result ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle)
         {
             if (IsPointingInsideKernel(mutexAddress))
             {
@@ -2825,7 +2867,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x1b)]
-        public KernelResult ArbitrateUnlock([PointerSized] ulong mutexAddress)
+        public Result ArbitrateUnlock([PointerSized] ulong mutexAddress)
         {
             if (IsPointingInsideKernel(mutexAddress))
             {
@@ -2843,7 +2885,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x1c)]
-        public KernelResult WaitProcessWideKeyAtomic(
+        public Result WaitProcessWideKeyAtomic(
             [PointerSized] ulong mutexAddress,
             [PointerSized] ulong condVarAddress,
             int handle,
@@ -2874,17 +2916,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x1d)]
-        public KernelResult SignalProcessWideKey([PointerSized] ulong address, int count)
+        public Result SignalProcessWideKey([PointerSized] ulong address, int count)
         {
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
             currentProcess.AddressArbiter.SignalProcessWideKey(address, count);
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         [Svc(0x34)]
-        public KernelResult WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout)
+        public Result WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout)
         {
             if (IsPointingInsideKernel(address))
             {
@@ -2916,7 +2958,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x35)]
-        public KernelResult SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count)
+        public Result SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count)
         {
             if (IsPointingInsideKernel(address))
             {
@@ -2943,11 +2985,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
         }
 
         [Svc(0x36)]
-        public KernelResult SynchronizePreemptionState()
+        public Result SynchronizePreemptionState()
         {
             KernelStatic.GetCurrentThread().SynchronizePreemptionState();
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         private static bool IsPointingInsideKernel(ulong address)
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs
index f53b43b3cc..a5f9df5ef2 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs
@@ -1,5 +1,6 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -24,14 +25,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             _arbiterThreads = new List<KThread>();
         }
 
-        public KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
+        public Result ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
         {
             KThread currentThread = KernelStatic.GetCurrentThread();
 
             _context.CriticalSection.Enter();
 
             currentThread.SignaledObj   = null;
-            currentThread.ObjSyncResult = KernelResult.Success;
+            currentThread.ObjSyncResult = Result.Success;
 
             KProcess currentProcess = KernelStatic.GetCurrentProcess();
 
@@ -46,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             {
                 _context.CriticalSection.Leave();
 
-                return 0;
+                return Result.Success;
             }
 
             KThread mutexOwner = currentProcess.HandleTable.GetObject<KThread>(ownerHandle);
@@ -78,7 +79,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             return currentThread.ObjSyncResult;
         }
 
-        public KernelResult ArbitrateUnlock(ulong mutexAddress)
+        public Result ArbitrateUnlock(ulong mutexAddress)
         {
             _context.CriticalSection.Enter();
 
@@ -86,14 +87,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
 
             (int mutexValue, KThread newOwnerThread) = MutexUnlock(currentThread, mutexAddress);
 
-            KernelResult result = KernelResult.Success;
+            Result result = Result.Success;
 
             if (!KernelTransfer.KernelToUser(mutexAddress, mutexValue))
             {
                 result = KernelResult.InvalidMemState;
             }
 
-            if (result != KernelResult.Success && newOwnerThread != null)
+            if (result != Result.Success && newOwnerThread != null)
             {
                 newOwnerThread.SignaledObj   = null;
                 newOwnerThread.ObjSyncResult = result;
@@ -104,7 +105,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             return result;
         }
 
-        public KernelResult WaitProcessWideKeyAtomic(ulong mutexAddress, ulong condVarAddress, int threadHandle, long timeout)
+        public Result WaitProcessWideKeyAtomic(ulong mutexAddress, ulong condVarAddress, int threadHandle, long timeout)
         {
             _context.CriticalSection.Enter();
 
@@ -185,7 +186,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
                 }
 
                 newOwnerThread.SignaledObj   = null;
-                newOwnerThread.ObjSyncResult = KernelResult.Success;
+                newOwnerThread.ObjSyncResult = Result.Success;
 
                 newOwnerThread.ReleaseAndResume();
             }
@@ -247,7 +248,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             {
                 // We now own the mutex.
                 requester.SignaledObj   = null;
-                requester.ObjSyncResult = KernelResult.Success;
+                requester.ObjSyncResult = Result.Success;
 
                 requester.ReleaseAndResume();
 
@@ -273,7 +274,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             }
         }
 
-        public KernelResult WaitForAddressIfEqual(ulong address, int value, long timeout)
+        public Result WaitForAddressIfEqual(ulong address, int value, long timeout)
         {
             KThread currentThread = KernelStatic.GetCurrentThread();
 
@@ -344,7 +345,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             return KernelResult.InvalidState;
         }
 
-        public KernelResult WaitForAddressIfLessThan(ulong address, int value, bool shouldDecrement, long timeout)
+        public Result WaitForAddressIfLessThan(ulong address, int value, bool shouldDecrement, long timeout)
         {
             KThread currentThread = KernelStatic.GetCurrentThread();
 
@@ -422,7 +423,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             return KernelResult.InvalidState;
         }
 
-        public KernelResult Signal(ulong address, int count)
+        public Result Signal(ulong address, int count)
         {
             _context.CriticalSection.Enter();
 
@@ -430,10 +431,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
 
             _context.CriticalSection.Leave();
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult SignalAndIncrementIfEqual(ulong address, int value, int count)
+        public Result SignalAndIncrementIfEqual(ulong address, int value, int count)
         {
             _context.CriticalSection.Enter();
 
@@ -467,10 +468,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
 
             _context.CriticalSection.Leave();
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult SignalAndModifyIfEqual(ulong address, int value, int count)
+        public Result SignalAndModifyIfEqual(ulong address, int value, int count)
         {
             _context.CriticalSection.Enter();
 
@@ -539,7 +540,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
 
             _context.CriticalSection.Leave();
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         private void WakeArbiterThreads(ulong address, int count)
@@ -547,7 +548,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             static void RemoveArbiterThread(KThread thread)
             {
                 thread.SignaledObj   = null;
-                thread.ObjSyncResult = KernelResult.Success;
+                thread.ObjSyncResult = Result.Success;
 
                 thread.ReleaseAndResume();
 
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KReadableEvent.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KReadableEvent.cs
index d378b81e39..d9e7befa6f 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KReadableEvent.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KReadableEvent.cs
@@ -1,4 +1,5 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
 
 namespace Ryujinx.HLE.HOS.Kernel.Threading
 {
@@ -27,16 +28,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             KernelContext.CriticalSection.Leave();
         }
 
-        public KernelResult Clear()
+        public Result Clear()
         {
             _signaled = false;
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult ClearIfSignaled()
+        public Result ClearIfSignaled()
         {
-            KernelResult result;
+            Result result;
 
             KernelContext.CriticalSection.Enter();
 
@@ -44,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             {
                 _signaled = false;
 
-                result = KernelResult.Success;
+                result = Result.Success;
             }
             else
             {
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs
index 419f15368b..01b65f55ea 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs
@@ -1,4 +1,5 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Collections.Generic;
 
@@ -13,11 +14,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             _context = context;
         }
 
-        public KernelResult WaitFor(Span<KSynchronizationObject> syncObjs, long timeout, out int handleIndex)
+        public Result WaitFor(Span<KSynchronizationObject> syncObjs, long timeout, out int handleIndex)
         {
             handleIndex = 0;
 
-            KernelResult result = KernelResult.TimedOut;
+            Result result = KernelResult.TimedOut;
 
             _context.CriticalSection.Enter();
 
@@ -33,7 +34,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
 
                 _context.CriticalSection.Leave();
 
-                return KernelResult.Success;
+                return Result.Success;
             }
 
             if (timeout == 0)
@@ -122,7 +123,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
                     if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
                     {
                         thread.SignaledObj   = syncObj;
-                        thread.ObjSyncResult = KernelResult.Success;
+                        thread.ObjSyncResult = Result.Success;
 
                         thread.Reschedule(ThreadSchedState.Running);
                     }
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
index b9dd91ef88..6fd496058c 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
@@ -3,6 +3,7 @@ using Ryujinx.Cpu;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Collections.Generic;
 using System.Numerics;
@@ -79,7 +80,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
         private ThreadSchedState _forcePauseFlags;
         private ThreadSchedState _forcePausePermissionFlags;
 
-        public KernelResult ObjSyncResult { get; set; }
+        public Result ObjSyncResult { get; set; }
 
         public int BasePriority { get; set; }
         public int PreferredCore { get; set; }
@@ -130,7 +131,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             _activityOperationLock = new object();
         }
 
-        public KernelResult Initialize(
+        public Result Initialize(
             ulong entrypoint,
             ulong argsPtr,
             ulong stackTop,
@@ -145,8 +146,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
                 throw new ArgumentException($"Invalid thread type \"{type}\".");
             }
 
-            ThreadContext = new KThreadContext();
-
             PreferredCore = cpuCore;
             AffinityMask |= 1UL << cpuCore;
 
@@ -166,7 +165,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
 
             if (type == ThreadType.User)
             {
-                if (owner.AllocateThreadLocalStorage(out _tlsAddress) != KernelResult.Success)
+                if (owner.AllocateThreadLocalStorage(out _tlsAddress) != Result.Success)
                 {
                     return KernelResult.OutOfMemory;
                 }
@@ -194,6 +193,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
 
             Context = owner?.CreateExecutionContext() ?? new ProcessExecutionContext();
 
+            ThreadContext = new KThreadContext(Context);
+
             Context.IsAarch32 = !is64Bits;
 
             Context.SetX(0, argsPtr);
@@ -230,7 +231,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
                     {
                         KernelContext.CriticalSection.Leave();
 
-                        return KernelResult.Success;
+                        return Result.Success;
                     }
 
                     _forcePauseFlags |= ThreadSchedState.ProcessPauseFlag;
@@ -241,10 +242,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
                 }
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
-        public KernelResult Start()
+        public Result Start()
         {
             if (!KernelContext.KernelInitialized)
             {
@@ -260,7 +261,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
                 KernelContext.CriticalSection.Leave();
             }
 
-            KernelResult result = KernelResult.ThreadTerminating;
+            Result result = KernelResult.ThreadTerminating;
 
             KernelContext.CriticalSection.Enter();
 
@@ -287,7 +288,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
 
                         StartHostThread();
 
-                        result = KernelResult.Success;
+                        result = Result.Success;
                         break;
                     }
                     else
@@ -465,7 +466,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             return -1;
         }
 
-        public KernelResult Sleep(long timeout)
+        public Result Sleep(long timeout)
         {
             KernelContext.CriticalSection.Enter();
 
@@ -490,7 +491,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
                 KernelContext.TimeManager.UnscheduleFutureInvocation(this);
             }
 
-            return 0;
+            return Result.Success;
         }
 
         public void SetPriority(int priority)
@@ -534,11 +535,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             }
         }
 
-        public KernelResult SetActivity(bool pause)
+        public Result SetActivity(bool pause)
         {
             lock (_activityOperationLock)
             {
-                KernelResult result = KernelResult.Success;
+                Result result = Result.Success;
 
                 KernelContext.CriticalSection.Enter();
 
@@ -581,7 +582,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
 
                 KernelContext.CriticalSection.Leave();
 
-                if (result == KernelResult.Success && pause)
+                if (result == Result.Success && pause)
                 {
                     bool isThreadRunning = true;
 
@@ -628,7 +629,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             }
         }
 
-        public KernelResult GetThreadContext3(out ThreadContext context)
+        public Result GetThreadContext3(out ThreadContext context)
         {
             context = default;
 
@@ -651,7 +652,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
                 KernelContext.CriticalSection.Leave();
             }
 
-            return KernelResult.Success;
+            return Result.Success;
         }
 
         private static uint GetPsr(IExecutionContext context)
@@ -739,7 +740,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             KernelContext.CriticalSection.Leave();
         }
 
-        public KernelResult SetCoreAndAffinityMask(int newCore, ulong newAffinityMask)
+        public Result SetCoreAndAffinityMask(int newCore, ulong newAffinityMask)
         {
             lock (_activityOperationLock)
             {
@@ -838,7 +839,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
                     KernelContext.CriticalSection.Leave();
                 }
 
-                return KernelResult.Success;
+                return Result.Success;
             }
         }
 
@@ -1259,6 +1260,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             if (_customThreadStart != null)
             {
                 _customThreadStart();
+
+                // Ensure that anything trying to join the HLE thread is unblocked.
+                Exit();
+                HandlePostSyscall();
             }
             else
             {
@@ -1304,7 +1309,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
         {
             Owner?.RemoveThread(this);
 
-            if (_tlsAddress != 0 && Owner.FreeThreadLocalStorage(_tlsAddress) != KernelResult.Success)
+            if (_tlsAddress != 0 && Owner.FreeThreadLocalStorage(_tlsAddress) != Result.Success)
             {
                 throw new InvalidOperationException("Unexpected failure freeing thread local storage.");
             }
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThreadContext.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThreadContext.cs
index a7e9c4b3a2..e8ad53c286 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KThreadContext.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThreadContext.cs
@@ -1,11 +1,25 @@
-using System.Threading;
+using Ryujinx.Cpu;
+using Ryujinx.Horizon.Common;
+using System.Threading;
 
 namespace Ryujinx.HLE.HOS.Kernel.Threading
 {
-    class KThreadContext
+    class KThreadContext : IThreadContext
     {
+        private readonly IExecutionContext _context;
+
+        public bool Running => _context.Running;
+        public ulong TlsAddress => (ulong)_context.TpidrroEl0;
+
+        public ulong GetX(int index) => _context.GetX(index);
+
         private int _locked;
 
+        public KThreadContext(IExecutionContext context)
+        {
+            _context = context;
+        }
+
         public bool Lock()
         {
             return Interlocked.Exchange(ref _locked, 1) == 0;
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KWritableEvent.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KWritableEvent.cs
index 7aee0b57c4..b46122be7f 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KWritableEvent.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KWritableEvent.cs
@@ -1,4 +1,5 @@
 using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
 
 namespace Ryujinx.HLE.HOS.Kernel.Threading
 {
@@ -16,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             _parent.ReadableEvent.Signal();
         }
 
-        public KernelResult Clear()
+        public Result Clear()
         {
             return _parent.ReadableEvent.Clear();
         }
diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs
index beeb5ad600..b422fef754 100644
--- a/Ryujinx.HLE/HOS/ProgramLoader.cs
+++ b/Ryujinx.HLE/HOS/ProgramLoader.cs
@@ -9,6 +9,7 @@ using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Memory;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.Loaders.Executables;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Linq;
 using System.Runtime.InteropServices;
@@ -90,9 +91,9 @@ namespace Ryujinx.HLE.HOS
 
             KMemoryRegionManager region = context.MemoryManager.MemoryRegions[(int)memoryRegion];
 
-            KernelResult result = region.AllocatePages(out KPageList pageList, (ulong)codePagesCount);
+            Result result = region.AllocatePages(out KPageList pageList, (ulong)codePagesCount);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
 
@@ -111,7 +112,7 @@ namespace Ryujinx.HLE.HOS
                 memoryRegion,
                 processContextFactory);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
 
@@ -120,7 +121,7 @@ namespace Ryujinx.HLE.HOS
 
             result = LoadIntoMemory(process, kip, codeBaseAddress);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
 
@@ -131,7 +132,7 @@ namespace Ryujinx.HLE.HOS
 
             result = process.Start(kip.Priority, (ulong)kip.StackSize);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");
 
@@ -230,19 +231,35 @@ namespace Ryujinx.HLE.HOS
 
             context.Device.System.LibHacHorizonManager.InitializeApplicationClient(new ProgramId(programInfo.ProgramId), in npdm);
 
-            KernelResult result;
+            Result result;
 
             KResourceLimit resourceLimit = new KResourceLimit(context);
 
             long applicationRgSize = (long)context.MemoryManager.MemoryRegions[(int)MemoryRegion.Application].Size;
 
-            result  = resourceLimit.SetLimitValue(LimitableResource.Memory,         applicationRgSize);
-            result |= resourceLimit.SetLimitValue(LimitableResource.Thread,         608);
-            result |= resourceLimit.SetLimitValue(LimitableResource.Event,          700);
-            result |= resourceLimit.SetLimitValue(LimitableResource.TransferMemory, 128);
-            result |= resourceLimit.SetLimitValue(LimitableResource.Session,        894);
+            result = resourceLimit.SetLimitValue(LimitableResource.Memory, applicationRgSize);
 
-            if (result != KernelResult.Success)
+            if (result.IsSuccess)
+            {
+                result = resourceLimit.SetLimitValue(LimitableResource.Thread, 608);
+            }
+
+            if (result.IsSuccess)
+            {
+                result = resourceLimit.SetLimitValue(LimitableResource.Event, 700);
+            }
+
+            if (result.IsSuccess)
+            {
+                result = resourceLimit.SetLimitValue(LimitableResource.TransferMemory, 128);
+            }
+
+            if (result.IsSuccess)
+            {
+                result = resourceLimit.SetLimitValue(LimitableResource.Session, 894);
+            }
+
+            if (result != Result.Success)
             {
                 Logger.Error?.Print(LogClass.Loader, $"Process initialization failed setting resource limit values.");
 
@@ -273,7 +290,7 @@ namespace Ryujinx.HLE.HOS
                 memoryRegion,
                 processContextFactory);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
 
@@ -288,7 +305,7 @@ namespace Ryujinx.HLE.HOS
 
                 result = LoadIntoMemory(process, executables[index], nsoBase[index]);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
 
@@ -302,7 +319,7 @@ namespace Ryujinx.HLE.HOS
 
             result = process.Start(meta.MainThreadPriority, meta.MainThreadStackSize);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");
 
@@ -322,18 +339,18 @@ namespace Ryujinx.HLE.HOS
             return true;
         }
 
-        private static KernelResult LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
+        private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
         {
-            ulong textStart = baseAddress + (ulong)image.TextOffset;
-            ulong roStart   = baseAddress + (ulong)image.RoOffset;
-            ulong dataStart = baseAddress + (ulong)image.DataOffset;
-            ulong bssStart  = baseAddress + (ulong)image.BssOffset;
+            ulong textStart = baseAddress + image.TextOffset;
+            ulong roStart   = baseAddress + image.RoOffset;
+            ulong dataStart = baseAddress + image.DataOffset;
+            ulong bssStart  = baseAddress + image.BssOffset;
 
             ulong end = dataStart + (ulong)image.Data.Length;
 
             if (image.BssSize != 0)
             {
-                end = bssStart + (ulong)image.BssSize;
+                end = bssStart + image.BssSize;
             }
 
             process.CpuMemory.Write(textStart, image.Text);
@@ -342,11 +359,11 @@ namespace Ryujinx.HLE.HOS
 
             process.CpuMemory.Fill(bssStart, image.BssSize, 0);
 
-            KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
+            Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
             {
                 if (size == 0)
                 {
-                    return KernelResult.Success;
+                    return Result.Success;
                 }
 
                 size = BitUtils.AlignUp<ulong>(size, KPageTableBase.PageSize);
@@ -354,16 +371,16 @@ namespace Ryujinx.HLE.HOS
                 return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
             }
 
-            KernelResult result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, KMemoryPermission.ReadAndExecute);
+            Result result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, KMemoryPermission.ReadAndExecute);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, KMemoryPermission.Read);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IAsyncContext.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IAsyncContext.cs
index b49a44e7d3..9a12e70183 100644
--- a/Ryujinx.HLE/HOS/Services/Account/Acc/IAsyncContext.cs
+++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IAsyncContext.cs
@@ -1,6 +1,6 @@
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Account.Acc
@@ -18,7 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
         // GetSystemEvent() -> handle<copy>
         public ResultCode GetSystemEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(AsyncExecution.SystemEvent.ReadableEvent, out int _systemEventHandle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(AsyncExecution.SystemEvent.ReadableEvent, out int _systemEventHandle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
index 405806c429..134566d96a 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
@@ -2,8 +2,8 @@
 using Ryujinx.HLE.HOS.Applets;
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletCreator
@@ -68,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
         {
             if (_stateChangedEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out _stateChangedEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out _stateChangedEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -178,7 +178,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
         {
             if (_normalOutDataEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out _normalOutDataEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out _normalOutDataEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -195,7 +195,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
         {
             if (_interactiveOutDataEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out _interactiveOutDataEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out _interactiveOutDataEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
index cb298fd47c..b145a65d10 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
@@ -1,10 +1,10 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Settings.Types;
 using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService;
 using Ryujinx.HLE.HOS.SystemState;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
@@ -38,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
 
             if (_messageEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(messageEvent.ReadableEvent, out _messageEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(messageEvent.ReadableEvent, out _messageEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -211,7 +211,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
             // NOTE: Original service calls IOperationModeManager::GetDefaultDisplayResolutionChangeEvent of omm service.
             if (_displayResolutionChangedEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out _displayResolutionChangedEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out _displayResolutionChangedEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs
index d7816de943..7c03fc2788 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs
@@ -1,7 +1,7 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
@@ -66,7 +66,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
                 return ResultCode.BufferAlreadyAcquired;
             }
 
-            if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
@@ -89,7 +89,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
                 return ResultCode.BufferAlreadyAcquired;
             }
 
-            if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs
index 5c53c66f83..2a9848ddc2 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs
@@ -1,7 +1,7 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
@@ -32,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
         {
             if (_channelEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out _channelEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out _channelEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
index 567bc26454..39be757764 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
@@ -1,8 +1,8 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy.Types;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
@@ -111,7 +111,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
 
             if (_libraryAppletLaunchableEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out _libraryAppletLaunchableEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out _libraryAppletLaunchableEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -378,7 +378,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
 
                 _accumulatedSuspendedTickChangedEvent.ReadableEvent.Signal();
 
-                if (context.Process.HandleTable.GenerateHandle(_accumulatedSuspendedTickChangedEvent.ReadableEvent, out _accumulatedSuspendedTickChangedEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_accumulatedSuspendedTickChangedEvent.ReadableEvent, out _accumulatedSuspendedTickChangedEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
index 74068ad668..49331e2168 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
@@ -1,4 +1,3 @@
-using LibHac;
 using LibHac.Account;
 using LibHac.Common;
 using LibHac.Fs;
@@ -9,13 +8,13 @@ using Ryujinx.Common;
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Memory;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage;
 using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
 using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService;
 using Ryujinx.HLE.HOS.SystemState;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Numerics;
 using System.Threading;
@@ -43,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
 
         private int _jitLoaded;
 
-        private HorizonClient _horizon;
+        private LibHac.HorizonClient _horizon;
 
         public IApplicationFunctions(Horizon system)
         {
@@ -136,8 +135,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
                     "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
             }
 
-            HorizonClient hos = context.Device.System.LibHacHorizonManager.AmClient;
-            Result result = hos.Fs.EnsureApplicationSaveData(out long requiredSize, applicationId, in control, in userId);
+            LibHac.HorizonClient hos = context.Device.System.LibHacHorizonManager.AmClient;
+            LibHac.Result result = hos.Fs.EnsureApplicationSaveData(out long requiredSize, applicationId, in control, in userId);
 
             context.ResponseData.Write(requiredSize);
 
@@ -185,7 +184,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         // SetTerminateResult(u32)
         public ResultCode SetTerminateResult(ServiceCtx context)
         {
-            Result result = new Result(context.RequestData.ReadUInt32());
+            LibHac.Result result = new LibHac.Result(context.RequestData.ReadUInt32());
 
             Logger.Info?.Print(LogClass.ServiceAm, $"Result = 0x{result.Value:x8} ({result.ToStringWithName()}).");
 
@@ -256,7 +255,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
 
             BlitStruct<ApplicationControlProperty> controlHolder = context.Device.Application.ControlData;
 
-            Result result = _horizon.Fs.CreateApplicationCacheStorage(out long requiredSize,
+            LibHac.Result result = _horizon.Fs.CreateApplicationCacheStorage(out long requiredSize,
                 out CacheStorageTargetMedia storageTarget, applicationId, in controlHolder.Value, index, saveSize,
                 journalSize);
 
@@ -584,7 +583,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         {
             if (_gpuErrorDetectedSystemEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out _gpuErrorDetectedSystemEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out _gpuErrorDetectedSystemEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -605,7 +604,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         {
             if (_friendInvitationStorageChannelEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out _friendInvitationStorageChannelEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out _friendInvitationStorageChannelEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -636,7 +635,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         {
             if (_notificationStorageChannelEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out _notificationStorageChannelEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out _notificationStorageChannelEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -653,7 +652,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         {
             if (_healthWarningDisappearedSystemEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_healthWarningDisappearedSystemEvent.ReadableEvent, out _healthWarningDisappearedSystemEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_healthWarningDisappearedSystemEvent.ReadableEvent, out _healthWarningDisappearedSystemEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs
index f9a9447f47..4911b7f00a 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs
@@ -1,8 +1,8 @@
 using Ryujinx.Audio.Common;
 using Ryujinx.Cpu;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using Ryujinx.Memory;
 using System;
 using System.Runtime.InteropServices;
@@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioIn
         {
             KEvent bufferEvent = _impl.RegisterBufferEvent();
 
-            if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs
index aff08811c0..2d6908e3f0 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs
@@ -1,8 +1,8 @@
 using Ryujinx.Audio.Common;
 using Ryujinx.Cpu;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using Ryujinx.Memory;
 using System;
 using System.Runtime.InteropServices;
@@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut
         {
             KEvent bufferEvent = _impl.RegisterBufferEvent();
 
-            if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs
index 1ef97ecce9..e868ad5af1 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs
@@ -1,8 +1,8 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.Cpu;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Text;
 
@@ -115,7 +115,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
         {
             KEvent deviceSystemEvent = _impl.QueryAudioDeviceSystemEvent();
 
-            if (context.Process.HandleTable.GenerateHandle(deviceSystemEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(deviceSystemEvent.ReadableEvent, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
@@ -230,7 +230,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
         {
             KEvent deviceInputEvent = _impl.QueryAudioDeviceInputEvent();
 
-            if (context.Process.HandleTable.GenerateHandle(deviceInputEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(deviceInputEvent.ReadableEvent, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
@@ -248,7 +248,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
         {
             KEvent deviceOutputEvent = _impl.QueryAudioDeviceOutputEvent();
 
-            if (context.Process.HandleTable.GenerateHandle(deviceOutputEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(deviceOutputEvent.ReadableEvent, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
index b2ddb697a2..3843b408ec 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
@@ -1,7 +1,7 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Buffers;
 
@@ -111,7 +111,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
 
             if (result == ResultCode.Success)
             {
-                if (context.Process.HandleTable.GenerateHandle(systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(systemEvent.ReadableEvent, out int handle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs
index 3e516d83ee..b176195db8 100644
--- a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs
+++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs
@@ -1,9 +1,9 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.Cpu;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator.Types;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
@@ -24,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
         {
             if (_eventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs b/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs
index 5ce434956e..65535ea10a 100644
--- a/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs
+++ b/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs
@@ -1,8 +1,8 @@
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Bluetooth.BluetoothDriver;
 using Ryujinx.HLE.HOS.Services.Settings;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Bluetooth
@@ -30,7 +30,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
                 {
                     BluetoothEventManager.InitializeBleDebugEvent = new KEvent(context.Device.System.KernelContext);
 
-                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.InitializeBleDebugEvent.ReadableEvent, out BluetoothEventManager.InitializeBleDebugEventHandle) != KernelResult.Success)
+                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.InitializeBleDebugEvent.ReadableEvent, out BluetoothEventManager.InitializeBleDebugEventHandle) != Result.Success)
                     {
                         throw new InvalidOperationException("Out of handles!");
                     }
@@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
                 {
                     BluetoothEventManager.UnknownBleDebugEvent = new KEvent(context.Device.System.KernelContext);
 
-                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.UnknownBleDebugEvent.ReadableEvent, out BluetoothEventManager.UnknownBleDebugEventHandle) != KernelResult.Success)
+                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.UnknownBleDebugEvent.ReadableEvent, out BluetoothEventManager.UnknownBleDebugEventHandle) != Result.Success)
                     {
                         throw new InvalidOperationException("Out of handles!");
                     }
@@ -50,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
                 {
                     BluetoothEventManager.RegisterBleDebugEvent = new KEvent(context.Device.System.KernelContext);
 
-                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.RegisterBleDebugEvent.ReadableEvent, out BluetoothEventManager.RegisterBleDebugEventHandle) != KernelResult.Success)
+                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.RegisterBleDebugEvent.ReadableEvent, out BluetoothEventManager.RegisterBleDebugEventHandle) != Result.Success)
                     {
                         throw new InvalidOperationException("Out of handles!");
                     }
@@ -66,7 +66,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
                 {
                     BluetoothEventManager.InitializeBleEvent = new KEvent(context.Device.System.KernelContext);
 
-                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.InitializeBleEvent.ReadableEvent, out BluetoothEventManager.InitializeBleEventHandle) != KernelResult.Success)
+                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.InitializeBleEvent.ReadableEvent, out BluetoothEventManager.InitializeBleEventHandle) != Result.Success)
                     {
                         throw new InvalidOperationException("Out of handles!");
                     }
@@ -76,7 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
                 {
                     BluetoothEventManager.UnknownBleEvent = new KEvent(context.Device.System.KernelContext);
 
-                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.UnknownBleEvent.ReadableEvent, out BluetoothEventManager.UnknownBleEventHandle) != KernelResult.Success)
+                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.UnknownBleEvent.ReadableEvent, out BluetoothEventManager.UnknownBleEventHandle) != Result.Success)
                     {
                         throw new InvalidOperationException("Out of handles!");
                     }
@@ -86,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
                 {
                     BluetoothEventManager.RegisterBleEvent = new KEvent(context.Device.System.KernelContext);
 
-                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.RegisterBleEvent.ReadableEvent, out BluetoothEventManager.RegisterBleEventHandle) != KernelResult.Success)
+                    if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.RegisterBleEvent.ReadableEvent, out BluetoothEventManager.RegisterBleEventHandle) != Result.Success)
                     {
                         throw new InvalidOperationException("Out of handles!");
                     }
diff --git a/Ryujinx.HLE/HOS/Services/BluetoothManager/BtmUser/IBtmUserCore.cs b/Ryujinx.HLE/HOS/Services/BluetoothManager/BtmUser/IBtmUserCore.cs
index 8f13865237..026b5bf127 100644
--- a/Ryujinx.HLE/HOS/Services/BluetoothManager/BtmUser/IBtmUserCore.cs
+++ b/Ryujinx.HLE/HOS/Services/BluetoothManager/BtmUser/IBtmUserCore.cs
@@ -1,7 +1,7 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 
 namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
 {
@@ -25,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
         // AcquireBleScanEvent() -> (byte<1>, handle<copy>)
         public ResultCode AcquireBleScanEvent(ServiceCtx context)
         {
-            KernelResult result = KernelResult.Success;
+            Result result = Result.Success;
 
             if (_bleScanEventHandle == 0)
             {
@@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
 
                 result = context.Process.HandleTable.GenerateHandle(_bleScanEvent.ReadableEvent, out _bleScanEventHandle);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not.
                     Logger.Error?.Print(LogClass.ServiceBsd, "Out of handles!");
@@ -42,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
 
             context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleScanEventHandle);
 
-            context.ResponseData.Write(result == KernelResult.Success ? 1 : 0);
+            context.ResponseData.Write(result == Result.Success ? 1 : 0);
 
             return ResultCode.Success;
         }
@@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
         // AcquireBleConnectionEvent() -> (byte<1>, handle<copy>)
         public ResultCode AcquireBleConnectionEvent(ServiceCtx context)
         {
-            KernelResult result = KernelResult.Success;
+            Result result = Result.Success;
 
             if (_bleConnectionEventHandle == 0)
             {
@@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
 
                 result = context.Process.HandleTable.GenerateHandle(_bleConnectionEvent.ReadableEvent, out _bleConnectionEventHandle);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not.
                     Logger.Error?.Print(LogClass.ServiceBsd, "Out of handles!");
@@ -68,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
 
             context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleConnectionEventHandle);
 
-            context.ResponseData.Write(result == KernelResult.Success ? 1 : 0);
+            context.ResponseData.Write(result == Result.Success ? 1 : 0);
 
             return ResultCode.Success;
         }
@@ -77,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
         // AcquireBleServiceDiscoveryEvent() -> (byte<1>, handle<copy>)
         public ResultCode AcquireBleServiceDiscoveryEvent(ServiceCtx context)
         {
-            KernelResult result = KernelResult.Success;
+            Result result = Result.Success;
 
             if (_bleServiceDiscoveryEventHandle == 0)
             {
@@ -85,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
 
                 result = context.Process.HandleTable.GenerateHandle(_bleServiceDiscoveryEvent.ReadableEvent, out _bleServiceDiscoveryEventHandle);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not.
                     Logger.Error?.Print(LogClass.ServiceBsd, "Out of handles!");
@@ -94,7 +94,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
 
             context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleServiceDiscoveryEventHandle);
 
-            context.ResponseData.Write(result == KernelResult.Success ? 1 : 0);
+            context.ResponseData.Write(result == Result.Success ? 1 : 0);
 
             return ResultCode.Success;
         }
@@ -103,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
         // AcquireBleMtuConfigEvent() -> (byte<1>, handle<copy>)
         public ResultCode AcquireBleMtuConfigEvent(ServiceCtx context)
         {
-            KernelResult result = KernelResult.Success;
+            Result result = Result.Success;
 
             if (_bleMtuConfigEventHandle == 0)
             {
@@ -111,7 +111,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
 
                 result = context.Process.HandleTable.GenerateHandle(_bleMtuConfigEvent.ReadableEvent, out _bleMtuConfigEventHandle);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not.
                     Logger.Error?.Print(LogClass.ServiceBsd, "Out of handles!");
@@ -120,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
 
             context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleMtuConfigEventHandle);
 
-            context.ResponseData.Write(result == KernelResult.Success ? 1 : 0);
+            context.ResponseData.Write(result == Result.Success ? 1 : 0);
 
             return ResultCode.Success;
         }
diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
index 8159d09189..17a33b7995 100644
--- a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
+++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
@@ -4,12 +4,11 @@ using Ryujinx.Common.Logging;
 using Ryujinx.Common.Memory;
 using Ryujinx.Common.Utilities;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Account.Acc;
 using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService;
+using Ryujinx.Horizon.Common;
 using System;
-using System.IO;
 using System.Runtime.InteropServices;
 
 namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
@@ -33,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
                 _completionEvent = new KEvent(context.Device.System.KernelContext);
             }
 
-            if (context.Process.HandleTable.GenerateHandle(_completionEvent.ReadableEvent, out int completionEventHandle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(_completionEvent.ReadableEvent, out int completionEventHandle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs
index f5614dddcf..65cbd38e72 100644
--- a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs
+++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs
@@ -1,9 +1,9 @@
 using Ryujinx.Common;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Account.Acc;
 using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Collections.Generic;
 
@@ -43,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
         {
             if (_notificationEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs
index b38b25c33f..29ee1706c4 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs
@@ -1,6 +1,6 @@
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
@@ -21,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
         {
             if (_hidSharedMemHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out _hidSharedMemHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out _hidSharedMemHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
index 957cd55309..d347a3bde9 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
@@ -1,11 +1,11 @@
 using Ryujinx.Common;
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Hid.HidServer;
 using Ryujinx.HLE.HOS.Services.Hid.Types;
 using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
@@ -55,7 +55,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
 
             // TODO: signal event at right place
             _xpadIdEvent.ReadableEvent.Signal();
-            
+
             _vibrationPermitted = true;
         }
 
@@ -170,7 +170,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             long xpadId = context.RequestData.ReadInt64();
 
-            if (context.Process.HandleTable.GenerateHandle(_xpadIdEvent.ReadableEvent, out _xpadIdEventHandle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(_xpadIdEvent.ReadableEvent, out _xpadIdEventHandle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
@@ -761,7 +761,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             long        npadStyleSet         = context.RequestData.ReadInt64();
 
             KEvent evnt = context.Device.Hid.Npads.GetStyleSetUpdateEvent(npadId);
-            if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
@@ -1597,7 +1597,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             int palmaConnectionHandle = context.RequestData.ReadInt32();
 
-            if (context.Process.HandleTable.GenerateHandle(_palmaOperationCompleteEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(_palmaOperationCompleteEvent.ReadableEvent, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
index a0bd637528..7af06431a9 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
@@ -1,9 +1,9 @@
 using Ryujinx.Common;
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Services.Hid.HidServer;
 using Ryujinx.HLE.HOS.Services.Hid.Irs.Types;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Hid.Irs
@@ -50,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
 
             if (_irsensorSharedMemoryHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(context.Device.System.IirsSharedMem, out _irsensorSharedMemoryHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(context.Device.System.IirsSharedMem, out _irsensorSharedMemoryHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -172,8 +172,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
         {
             NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32();
 
-            if (npadIdType >  NpadIdType.Player8 && 
-                npadIdType != NpadIdType.Unknown && 
+            if (npadIdType >  NpadIdType.Player8 &&
+                npadIdType != NpadIdType.Unknown &&
                 npadIdType != NpadIdType.Handheld)
             {
                 return ResultCode.NpadIdOutOfRange;
@@ -183,7 +183,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
 
             context.ResponseData.Write((int)irCameraHandle);
 
-            // NOTE: If the irCameraHandle pointer is null this error is returned, Doesn't occur in our case. 
+            // NOTE: If the irCameraHandle pointer is null this error is returned, Doesn't occur in our case.
             //       return ResultCode.HandlePointerIsNull;
 
             return ResultCode.Success;
diff --git a/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs b/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs
index dd3dad59aa..0c223c067f 100644
--- a/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs
+++ b/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs
@@ -1,6 +1,6 @@
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Services.Ldn.Types;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Net;
 
@@ -47,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
         {
             if (_stateChangeEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_networkInterface.StateChangeEvent.ReadableEvent, out _stateChangeEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_networkInterface.StateChangeEvent.ReadableEvent, out _stateChangeEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs
index f4ad03661e..a7f2dbb85a 100644
--- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs
@@ -2,11 +2,11 @@
 using Ryujinx.Cpu;
 using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Hid;
 using Ryujinx.HLE.HOS.Services.Hid.HidServer;
 using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Buffers.Binary;
 using System.Globalization;
@@ -851,7 +851,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
                 {
                     context.Device.System.NfpDevices[i].ActivateEvent = new KEvent(context.Device.System.KernelContext);
 
-                    if (context.Process.HandleTable.GenerateHandle(context.Device.System.NfpDevices[i].ActivateEvent.ReadableEvent, out int activateEventHandle) != KernelResult.Success)
+                    if (context.Process.HandleTable.GenerateHandle(context.Device.System.NfpDevices[i].ActivateEvent.ReadableEvent, out int activateEventHandle) != Result.Success)
                     {
                         throw new InvalidOperationException("Out of handles!");
                     }
@@ -877,7 +877,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
                 {
                     context.Device.System.NfpDevices[i].DeactivateEvent = new KEvent(context.Device.System.KernelContext);
 
-                    if (context.Process.HandleTable.GenerateHandle(context.Device.System.NfpDevices[i].DeactivateEvent.ReadableEvent, out int deactivateEventHandle) != KernelResult.Success)
+                    if (context.Process.HandleTable.GenerateHandle(context.Device.System.NfpDevices[i].DeactivateEvent.ReadableEvent, out int deactivateEventHandle) != Result.Success)
                     {
                         throw new InvalidOperationException("Out of handles!");
                     }
@@ -960,7 +960,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
         {
             _availabilityChangeEvent = new KEvent(context.Device.System.KernelContext);
 
-            if (context.Process.HandleTable.GenerateHandle(_availabilityChangeEvent.ReadableEvent, out int availabilityChangeEventHandle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(_availabilityChangeEvent.ReadableEvent, out int availabilityChangeEventHandle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
index 7a3fdabd02..88757bee78 100644
--- a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
+++ b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
@@ -1,7 +1,7 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
@@ -66,7 +66,7 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
         {
             if (_event0Handle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out _event0Handle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out _event0Handle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -74,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
 
             if (_event1Handle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out _event1Handle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out _event1Handle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs
index 919639b632..d6843d12e4 100644
--- a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs
+++ b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs
@@ -1,8 +1,8 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServiceAccessServer.ShopServiceAccessor;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServiceAccessServer
@@ -26,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServ
 
             if (_eventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Nim/Ntc/StaticService/IEnsureNetworkClockAvailabilityService.cs b/Ryujinx.HLE/HOS/Services/Nim/Ntc/StaticService/IEnsureNetworkClockAvailabilityService.cs
index fb31bd1f0d..3b533f0ff1 100644
--- a/Ryujinx.HLE/HOS/Services/Nim/Ntc/StaticService/IEnsureNetworkClockAvailabilityService.cs
+++ b/Ryujinx.HLE/HOS/Services/Nim/Ntc/StaticService/IEnsureNetworkClockAvailabilityService.cs
@@ -1,12 +1,12 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Nim.Ntc.StaticService
 {
-    class IEnsureNetworkClockAvailabilityService : IpcService 
+    class IEnsureNetworkClockAvailabilityService : IpcService
     {
         private KEvent     _finishNotificationEvent;
         private ResultCode _taskResultCode;
@@ -43,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Nim.Ntc.StaticService
         // GetFinishNotificationEvent() -> handle<copy>
         public ResultCode GetFinishNotificationEvent(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_finishNotificationEvent.ReadableEvent, out int finishNotificationEventHandle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(_finishNotificationEvent.ReadableEvent, out int finishNotificationEventHandle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs b/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs
index 53866a6b38..0d5520038b 100644
--- a/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs
@@ -1,7 +1,7 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Collections.Generic;
 
@@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
 
             // TODO: Found where stored value is used.
             ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Application.TitleId);
-            
+
             if (resultCode != ResultCode.Success)
             {
                 return resultCode;
@@ -327,7 +327,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
         {
             if (_addOnContentListChangedEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out _addOnContentListChangedEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out _addOnContentListChangedEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Ns/Aoc/IPurchaseEventManager.cs b/Ryujinx.HLE/HOS/Services/Ns/Aoc/IPurchaseEventManager.cs
index 9b65e0f9ea..5ec43a3f5a 100644
--- a/Ryujinx.HLE/HOS/Services/Ns/Aoc/IPurchaseEventManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Ns/Aoc/IPurchaseEventManager.cs
@@ -1,7 +1,7 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
@@ -38,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
         // GetPurchasedEventReadableHandle() -> handle<copy, event>
         public ResultCode GetPurchasedEventReadableHandle(ServiceCtx context)
         {
-            if (context.Process.HandleTable.GenerateHandle(_purchasedEvent.ReadableEvent, out int purchasedEventReadableHandle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(_purchasedEvent.ReadableEvent, out int purchasedEventReadableHandle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs
index 5bc3e3bd34..f33cc46018 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs
@@ -1,6 +1,6 @@
-using Ryujinx.HLE.HOS.Kernel.Common;
-using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
+using Ryujinx.Horizon.Common;
 using Ryujinx.Memory;
 using System;
 
@@ -27,7 +27,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
         {
             KEvent evnt = new KEvent(context.Device.System.KernelContext);
 
-            if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs
index d332bb0442..ac5512eda0 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs
@@ -2,9 +2,9 @@ using Ryujinx.Common.Logging;
 using Ryujinx.Graphics.Gpu;
 using Ryujinx.Graphics.Gpu.Synchronization;
 using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Nv.Types;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Threading;
 
@@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
 
             Event = new KEvent(system.KernelContext);
 
-            if (KernelStatic.GetCurrentProcess().HandleTable.GenerateHandle(Event.ReadableEvent, out EventHandle) != KernelResult.Success)
+            if (KernelStatic.GetCurrentProcess().HandleTable.GenerateHandle(Event.ReadableEvent, out EventHandle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs
index f1a6570b08..d6a8e29fbe 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs
@@ -1,7 +1,7 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types;
+using Ryujinx.Horizon.Common;
 using Ryujinx.Memory;
 using System;
 using System.Diagnostics;
@@ -99,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu
 
             if (targetEvent != null)
             {
-                if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
+                if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs b/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs
index 8c96c4ad96..94ab49cac6 100644
--- a/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs
@@ -1,7 +1,7 @@
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Services.Pcv.Clkrst.ClkrstManager;
 using Ryujinx.HLE.HOS.Services.Pcv.Types;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Pcv.Clkrst
@@ -34,7 +34,7 @@ namespace Ryujinx.HLE.HOS.Services.Pcv.Clkrst
         {
             if (_moduleStateTableEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(context.Device.System.IirsSharedMem, out _moduleStateTableEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(context.Device.System.IirsSharedMem, out _moduleStateTableEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs b/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs
index 4b0df9b7b0..c9c6354df0 100644
--- a/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs
@@ -1,7 +1,7 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
 
 namespace Ryujinx.HLE.HOS.Services.Pm
 {
@@ -18,7 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Pm
 
             KProcess process = KernelStatic.GetProcessByPid(pid);
 
-            if (context.Process.HandleTable.GenerateHandle(process, out int processHandle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(process, out int processHandle) != Result.Success)
             {
                 throw new System.Exception("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs b/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs
index 6015c6a4ba..9b4e996d92 100644
--- a/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs
+++ b/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs
@@ -1,7 +1,7 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 
 namespace Ryujinx.HLE.HOS.Services.Ptm.Psm
 {
@@ -22,11 +22,11 @@ namespace Ryujinx.HLE.HOS.Services.Ptm.Psm
         {
             if (_stateChangeEventHandle == -1)
             {
-                KernelResult resultCode = context.Process.HandleTable.GenerateHandle(_stateChangeEvent.ReadableEvent, out _stateChangeEventHandle);
+                Result resultCode = context.Process.HandleTable.GenerateHandle(_stateChangeEvent.ReadableEvent, out _stateChangeEventHandle);
 
-                if (resultCode != KernelResult.Success)
+                if (resultCode != Result.Success)
                 {
-                    return (ResultCode)resultCode;
+                    return (ResultCode)resultCode.ErrorCode;
                 }
             }
 
diff --git a/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs b/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
index 36e1078fd6..263e1c4ce7 100644
--- a/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
@@ -1,10 +1,10 @@
 using LibHac.Tools.FsSystem;
 using Ryujinx.Common;
 using Ryujinx.Cpu;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Memory;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.Loaders.Executables;
+using Ryujinx.Horizon.Common;
 using Ryujinx.Memory;
 using System;
 using System.Collections.Generic;
@@ -217,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
 
                 if (info.BssSize > 0)
                 {
-                    KernelResult bssMappingResult = memMgr.MapProcessCodeMemory(nroMappedAddress + info.NroSize, info.BssAddress, info.BssSize);
+                    Result bssMappingResult = memMgr.MapProcessCodeMemory(nroMappedAddress + info.NroSize, info.BssAddress, info.BssSize);
 
                     if (bssMappingResult == KernelResult.InvalidMemState)
                     {
@@ -226,12 +226,12 @@ namespace Ryujinx.HLE.HOS.Services.Ro
 
                         continue;
                     }
-                    else if (bssMappingResult != KernelResult.Success)
+                    else if (bssMappingResult != Result.Success)
                     {
                         memMgr.UnmapProcessCodeMemory(nroMappedAddress + info.NroSize, info.BssAddress, info.BssSize);
                         memMgr.UnmapProcessCodeMemory(nroMappedAddress, info.NroAddress, info.NroSize);
 
-                        return (ResultCode)bssMappingResult;
+                        return (ResultCode)bssMappingResult.ErrorCode;
                     }
                 }
 
@@ -286,15 +286,15 @@ namespace Ryujinx.HLE.HOS.Services.Ro
                     }
                 }
 
-                KernelResult result = memMgr.MapProcessCodeMemory(targetAddress, baseAddress, size);
+                Result result = memMgr.MapProcessCodeMemory(targetAddress, baseAddress, size);
 
                 if (result == KernelResult.InvalidMemState)
                 {
                     continue;
                 }
-                else if (result != KernelResult.Success)
+                else if (result != Result.Success)
                 {
-                    return (ResultCode)result;
+                    return (ResultCode)result.ErrorCode;
                 }
 
                 if (!CanAddGuardRegionsInProcess(process, targetAddress, size))
@@ -313,11 +313,11 @@ namespace Ryujinx.HLE.HOS.Services.Ro
             return ResultCode.Success;
         }
 
-        private KernelResult SetNroMemoryPermissions(KProcess process, IExecutable relocatableObject, ulong baseAddress)
+        private Result SetNroMemoryPermissions(KProcess process, IExecutable relocatableObject, ulong baseAddress)
         {
-            ulong textStart = baseAddress + (ulong)relocatableObject.TextOffset;
-            ulong roStart   = baseAddress + (ulong)relocatableObject.RoOffset;
-            ulong dataStart = baseAddress + (ulong)relocatableObject.DataOffset;
+            ulong textStart = baseAddress + relocatableObject.TextOffset;
+            ulong roStart   = baseAddress + relocatableObject.RoOffset;
+            ulong dataStart = baseAddress + relocatableObject.DataOffset;
 
             ulong bssStart = dataStart + (ulong)relocatableObject.Data.Length;
 
@@ -329,18 +329,18 @@ namespace Ryujinx.HLE.HOS.Services.Ro
 
             MemoryHelper.FillWithZeros(process.CpuMemory, bssStart, (int)(bssEnd - bssStart));
 
-            KernelResult result;
+            Result result;
 
             result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, KMemoryPermission.ReadAndExecute);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
 
             result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, KMemoryPermission.Read);
 
-            if (result != KernelResult.Success)
+            if (result != Result.Success)
             {
                 return result;
             }
@@ -385,7 +385,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
             ulong dataSize = (ulong)info.Executable.Data.Length;
             ulong bssSize  = (ulong)info.Executable.BssSize;
 
-            KernelResult result = KernelResult.Success;
+            Result result = Result.Success;
 
             if (info.Executable.BssSize != 0)
             {
@@ -395,14 +395,14 @@ namespace Ryujinx.HLE.HOS.Services.Ro
                     bssSize);
             }
 
-            if (result == KernelResult.Success)
+            if (result == Result.Success)
             {
                 result = _owner.MemoryManager.UnmapProcessCodeMemory(
                     info.NroMappedAddress + textSize + roSize,
                     info.Executable.SourceAddress + textSize + roSize,
                     dataSize);
 
-                if (result == KernelResult.Success)
+                if (result == Result.Success)
                 {
                     result = _owner.MemoryManager.UnmapProcessCodeMemory(
                         info.NroMappedAddress,
@@ -411,7 +411,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
                 }
             }
 
-            return (ResultCode)result;
+            return (ResultCode)result.ErrorCode;
         }
 
         private ResultCode IsInitialized(ulong pid)
@@ -452,7 +452,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
 
                     if (result == ResultCode.Success)
                     {
-                        result = (ResultCode)SetNroMemoryPermissions(_owner, info.Executable, nroMappedAddress);
+                        result = (ResultCode)SetNroMemoryPermissions(_owner, info.Executable, nroMappedAddress).ErrorCode;
 
                         if (result == ResultCode.Success)
                         {
diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs b/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs
index 82e246b738..f95c1d1f3c 100644
--- a/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs
@@ -1,6 +1,6 @@
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Services.Sdb.Pl.Types;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
@@ -67,7 +67,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
 
             if (_fontSharedMemHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out _fontSharedMemHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out _fontSharedMemHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -107,7 +107,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
         // GetSharedFontInOrderOfPriorityForSystem(bytes<8, 1>) -> (u8, u32, buffer<unknown, 6>, buffer<unknown, 6>, buffer<unknown, 6>)
         public ResultCode GetSharedFontInOrderOfPriorityForSystem(ServiceCtx context)
         {
-            // TODO: Check the differencies with GetSharedFontInOrderOfPriority. 
+            // TODO: Check the differencies with GetSharedFontInOrderOfPriority.
 
             return GetSharedFontInOrderOfPriority(context);
         }
diff --git a/Ryujinx.HLE/HOS/Services/ServerBase.cs b/Ryujinx.HLE/HOS/Services/ServerBase.cs
index 3c53abecac..50f6c99e66 100644
--- a/Ryujinx.HLE/HOS/Services/ServerBase.cs
+++ b/Ryujinx.HLE/HOS/Services/ServerBase.cs
@@ -1,9 +1,9 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Buffers.Binary;
 using System.Collections.Generic;
@@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Services
 
                 replyTargetHandle = 0;
 
-                if (rc == KernelResult.Success && signaledIndex >= portHandles.Length)
+                if (rc == Result.Success && signaledIndex >= portHandles.Length)
                 {
                     // We got a IPC request, process it, pass to the appropriate service if needed.
                     int signaledHandle = handles[signaledIndex];
@@ -141,10 +141,10 @@ namespace Ryujinx.HLE.HOS.Services
                 }
                 else
                 {
-                    if (rc == KernelResult.Success)
+                    if (rc == Result.Success)
                     {
                         // We got a new connection, accept the session to allow servicing future requests.
-                        if (_context.Syscall.AcceptSession(out int serverSessionHandle, handles[signaledIndex]) == KernelResult.Success)
+                        if (_context.Syscall.AcceptSession(out int serverSessionHandle, handles[signaledIndex]) == Result.Success)
                         {
                             IpcService obj = _ports[handles[signaledIndex]].Invoke();
 
diff --git a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
index 8e66b28dad..86031a7073 100644
--- a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
@@ -1,8 +1,8 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Ipc;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -72,14 +72,14 @@ namespace Ryujinx.HLE.HOS.Services.Sm
 
             if (_registry.TryGetService(name, out KPort port))
             {
-                KernelResult result = port.EnqueueIncomingSession(session.ServerSession);
+                Result result = port.EnqueueIncomingSession(session.ServerSession);
 
-                if (result != KernelResult.Success)
+                if (result != Result.Success)
                 {
                     throw new InvalidOperationException($"Session enqueue on port returned error \"{result}\".");
                 }
 
-                if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -113,7 +113,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
                     }
                 }
 
-                if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
@@ -182,14 +182,14 @@ namespace Ryujinx.HLE.HOS.Services.Sm
 
             Logger.Info?.Print(LogClass.ServiceSm, $"Register \"{name}\".");
 
-            KPort port = new KPort(context.Device.System.KernelContext, maxSessions, isLight, 0);
+            KPort port = new KPort(context.Device.System.KernelContext, maxSessions, isLight, null);
 
             if (!_registry.TryRegister(name, port))
             {
                 return ResultCode.AlreadyRegistered;
             }
 
-            if (context.Process.HandleTable.GenerateHandle(port.ServerPort, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(port.ServerPort, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
index c3dcbee76a..d641f7f093 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
@@ -1,6 +1,6 @@
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
@@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
 
             GetNativeHandle(binderId, typeId, out KReadableEvent readableEvent);
 
-            if (context.Process.HandleTable.GenerateHandle(readableEvent, out int handle) != KernelResult.Success)
+            if (context.Process.HandleTable.GenerateHandle(readableEvent, out int handle) != Result.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs
index 4f35181210..abb5bb40d2 100644
--- a/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs
@@ -1,10 +1,10 @@
 using Ryujinx.Common;
 using Ryujinx.Cpu;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Services.Time.Clock;
 using Ryujinx.HLE.HOS.Services.Time.StaticService;
 using Ryujinx.HLE.HOS.Services.Time.TimeZone;
+using Ryujinx.Horizon.Common;
 using System;
 using System.Diagnostics;
 using System.IO;
@@ -102,7 +102,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         {
             if (_timeSharedMemoryNativeHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_timeManager.SharedMemory.GetSharedMemory(), out _timeSharedMemoryNativeHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_timeManager.SharedMemory.GetSharedMemory(), out _timeSharedMemoryNativeHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs
index 1ff5b2d69a..aae9aaafc1 100644
--- a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs
@@ -2,9 +2,9 @@
 using Ryujinx.Cpu;
 using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Services.Time.Clock;
 using Ryujinx.HLE.Utilities;
+using Ryujinx.Horizon.Common;
 using System;
 using System.IO;
 
@@ -180,7 +180,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         {
             if (_automaticCorrectionEvent == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(_timeManager.StandardUserSystemClock.GetAutomaticCorrectionReadableEvent(), out _automaticCorrectionEvent) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(_timeManager.StandardUserSystemClock.GetAutomaticCorrectionReadableEvent(), out _automaticCorrectionEvent) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs
index 085cc71dca..c43c15820b 100644
--- a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs
@@ -1,9 +1,9 @@
 using Ryujinx.Common;
 using Ryujinx.Cpu;
 using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Time.Clock;
+using Ryujinx.Horizon.Common;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Time.StaticService
@@ -117,7 +117,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
 
                 _clockCore.RegisterOperationEvent(kEvent.WritableEvent);
 
-                if (context.Process.HandleTable.GenerateHandle(kEvent.ReadableEvent, out _operationEventReadableHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(kEvent.ReadableEvent, out _operationEventReadableHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs
index 885a4cd7ce..d6feb33f47 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs
+++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs
@@ -14,6 +14,7 @@ using System.Diagnostics;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 using System.Text;
+using Ryujinx.Horizon.Common;
 
 namespace Ryujinx.HLE.HOS.Services.Vi.RootService
 {
@@ -471,7 +472,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
 
             if (_vsyncEventHandle == 0)
             {
-                if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out _vsyncEventHandle) != KernelResult.Success)
+                if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out _vsyncEventHandle) != Result.Success)
                 {
                     throw new InvalidOperationException("Out of handles!");
                 }
diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj
index f1f295a274..5e3aa0eacb 100644
--- a/Ryujinx.HLE/Ryujinx.HLE.csproj
+++ b/Ryujinx.HLE/Ryujinx.HLE.csproj
@@ -11,7 +11,9 @@
     <ProjectReference Include="..\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj" />
-    <ProjectReference Include="..\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+    <ProjectReference Include="..\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj" />
+    <ProjectReference Include="..\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+    <ProjectReference Include="..\Ryujinx.Horizon\Ryujinx.Horizon.csproj" />
     <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
     <ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs
index 46af68f493..61e5e57279 100644
--- a/Ryujinx.HLE/Switch.cs
+++ b/Ryujinx.HLE/Switch.cs
@@ -19,7 +19,7 @@ namespace Ryujinx.HLE
         public MemoryBlock           Memory            { get; }
         public GpuContext            Gpu               { get; }
         public VirtualFileSystem     FileSystem        { get; }
-        public Horizon               System            { get; }
+        public HOS.Horizon           System            { get; }
         public ApplicationLoader     Application       { get; }
         public PerformanceStatistics Statistics        { get; }
         public Hid                   Hid               { get; }
@@ -47,7 +47,7 @@ namespace Ryujinx.HLE
             AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver);
             Memory            = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), memoryAllocationFlags);
             Gpu               = new GpuContext(Configuration.GpuRenderer);
-            System            = new Horizon(this);
+            System            = new HOS.Horizon(this);
             Statistics        = new PerformanceStatistics();
             Hid               = new Hid(this, System.HidStorage);
             Application       = new ApplicationLoader(this);
diff --git a/Ryujinx.Horizon.Common/ISyscallApi.cs b/Ryujinx.Horizon.Common/ISyscallApi.cs
new file mode 100644
index 0000000000..8fa276b526
--- /dev/null
+++ b/Ryujinx.Horizon.Common/ISyscallApi.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Ryujinx.Horizon.Common
+{
+    public interface ISyscallApi
+    {
+        Result SetHeapSize(out ulong address, ulong size);
+
+        void SleepThread(long timeout);
+
+        Result CloseHandle(int handle);
+
+        Result WaitSynchronization(out int handleIndex, ReadOnlySpan<int> handles, long timeout);
+        Result CancelSynchronization(int handle);
+
+        Result GetProcessId(out ulong pid, int handle);
+
+        Result ConnectToNamedPort(out int handle, string name);
+        Result SendSyncRequest(int handle);
+        Result CreateSession(out int serverSessionHandle, out int clientSessionHandle, bool isLight, string name);
+        Result AcceptSession(out int sessionHandle, int portHandle);
+        Result ReplyAndReceive(out int handleIndex, ReadOnlySpan<int> handles, int replyTargetHandle, long timeout);
+
+        Result CreateEvent(out int writableHandle, out int readableHandle);
+        Result SignalEvent(int handle);
+        Result ClearEvent(int handle);
+        Result ResetSignal(int handle);
+
+        Result CreatePort(out int serverPortHandle, out int clientPortHandle, int maxSessions, bool isLight, string name);
+        Result ManageNamedPort(out int handle, string name, int maxSessions);
+        Result ConnectToPort(out int clientSessionHandle, int clientPortHandle);
+    }
+}
diff --git a/Ryujinx.Horizon.Common/IThreadContext.cs b/Ryujinx.Horizon.Common/IThreadContext.cs
new file mode 100644
index 0000000000..47aea1a38f
--- /dev/null
+++ b/Ryujinx.Horizon.Common/IThreadContext.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Horizon.Common
+{
+    public interface IThreadContext
+    {
+        bool Running { get; }
+
+        ulong TlsAddress { get; }
+
+        ulong GetX(int index);
+    }
+}
diff --git a/Ryujinx.Horizon.Common/InvalidResultException.cs b/Ryujinx.Horizon.Common/InvalidResultException.cs
new file mode 100644
index 0000000000..cf38b64038
--- /dev/null
+++ b/Ryujinx.Horizon.Common/InvalidResultException.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace Ryujinx.Horizon.Common
+{
+    public class InvalidResultException : Exception
+    {
+        public InvalidResultException()
+        {
+        }
+
+        public InvalidResultException(Result result) : base($"Unexpected result code {result} returned.")
+        {
+        }
+
+        public InvalidResultException(string message) : base(message)
+        {
+        }
+
+        public InvalidResultException(string message, Exception innerException) : base(message, innerException)
+        {
+        }
+    }
+}
diff --git a/Ryujinx.Horizon.Common/KernelResult.cs b/Ryujinx.Horizon.Common/KernelResult.cs
new file mode 100644
index 0000000000..51fec20575
--- /dev/null
+++ b/Ryujinx.Horizon.Common/KernelResult.cs
@@ -0,0 +1,39 @@
+namespace Ryujinx.Horizon.Common
+{
+    public static class KernelResult
+    {
+        private const int ModuleId = 1;
+
+        public static Result SessionCountExceeded => new Result(ModuleId, 7);
+        public static Result InvalidCapability => new Result(ModuleId, 14);
+        public static Result ThreadNotStarted => new Result(ModuleId, 57);
+        public static Result ThreadTerminating => new Result(ModuleId, 59);
+        public static Result InvalidSize => new Result(ModuleId, 101);
+        public static Result InvalidAddress => new Result(ModuleId, 102);
+        public static Result OutOfResource => new Result(ModuleId, 103);
+        public static Result OutOfMemory => new Result(ModuleId, 104);
+        public static Result HandleTableFull => new Result(ModuleId, 105);
+        public static Result InvalidMemState => new Result(ModuleId, 106);
+        public static Result InvalidPermission => new Result(ModuleId, 108);
+        public static Result InvalidMemRange => new Result(ModuleId, 110);
+        public static Result InvalidPriority => new Result(ModuleId, 112);
+        public static Result InvalidCpuCore => new Result(ModuleId, 113);
+        public static Result InvalidHandle => new Result(ModuleId, 114);
+        public static Result UserCopyFailed => new Result(ModuleId, 115);
+        public static Result InvalidCombination => new Result(ModuleId, 116);
+        public static Result TimedOut => new Result(ModuleId, 117);
+        public static Result Cancelled => new Result(ModuleId, 118);
+        public static Result MaximumExceeded => new Result(ModuleId, 119);
+        public static Result InvalidEnumValue => new Result(ModuleId, 120);
+        public static Result NotFound => new Result(ModuleId, 121);
+        public static Result InvalidThread => new Result(ModuleId, 122);
+        public static Result PortRemoteClosed => new Result(ModuleId, 123);
+        public static Result InvalidState => new Result(ModuleId, 125);
+        public static Result ReservedValue => new Result(ModuleId, 126);
+        public static Result PortClosed => new Result(ModuleId, 131);
+        public static Result ResLimitExceeded => new Result(ModuleId, 132);
+        public static Result ReceiveListBroken => new Result(ModuleId, 258);
+        public static Result OutOfVaSpace => new Result(ModuleId, 259);
+        public static Result CmdBufferTooSmall => new Result(ModuleId, 260);
+    }
+}
diff --git a/Ryujinx.Horizon.Common/OnScopeExit.cs b/Ryujinx.Horizon.Common/OnScopeExit.cs
new file mode 100644
index 0000000000..2b81e492fd
--- /dev/null
+++ b/Ryujinx.Horizon.Common/OnScopeExit.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Ryujinx.Horizon.Common
+{
+    public struct OnScopeExit : IDisposable
+    {
+        private readonly Action _action;
+
+        public OnScopeExit(Action action)
+        {
+            _action = action;
+        }
+
+        public void Dispose()
+        {
+            _action();
+        }
+    }
+}
diff --git a/Ryujinx.Horizon.Common/Result.cs b/Ryujinx.Horizon.Common/Result.cs
new file mode 100644
index 0000000000..04281199d0
--- /dev/null
+++ b/Ryujinx.Horizon.Common/Result.cs
@@ -0,0 +1,118 @@
+using System;
+
+namespace Ryujinx.Horizon.Common
+{
+    public struct Result : IEquatable<Result>
+    {
+        private const int ModuleBits = 9;
+        private const int DescriptionBits = 13;
+        private const int ModuleMax = 1 << ModuleBits;
+        private const int DescriptionMax = 1 << DescriptionBits;
+
+        public static Result Success { get; } = new Result(0, 0);
+
+        public int ErrorCode { get; }
+
+        public bool IsSuccess => ErrorCode == 0;
+        public bool IsFailure => ErrorCode != 0;
+
+        public int Module => ErrorCode & (ModuleMax - 1);
+        public int Description => (ErrorCode >> ModuleBits) & (DescriptionMax - 1);
+
+        public string PrintableResult => $"{2000 + Module:D4}-{Description:D4}";
+
+        public Result(int module, int description)
+        {
+            if ((uint)module >= ModuleMax)
+            {
+                throw new ArgumentOutOfRangeException(nameof(module));
+            }
+
+            if ((uint)description >= DescriptionMax)
+            {
+                throw new ArgumentOutOfRangeException(nameof(description));
+            }
+
+            ErrorCode = module | (description << ModuleBits);
+        }
+
+        public override bool Equals(object obj)
+        {
+            return obj is Result result && result.Equals(this);
+        }
+
+        public bool Equals(Result other)
+        {
+            return other.ErrorCode == ErrorCode;
+        }
+
+        public override int GetHashCode()
+        {
+            return ErrorCode;
+        }
+
+        public static bool operator ==(Result lhs, Result rhs)
+        {
+            return lhs.Equals(rhs);
+        }
+
+        public static bool operator !=(Result lhs, Result rhs)
+        {
+            return !lhs.Equals(rhs);
+        }
+
+        public bool InRange(int minInclusive, int maxInclusive)
+        {
+            return (uint)(Description - minInclusive) <= (uint)(maxInclusive - minInclusive);
+        }
+
+        public void AbortOnSuccess()
+        {
+            if (IsSuccess)
+            {
+                ThrowInvalidResult();
+            }
+        }
+
+        public void AbortOnFailure()
+        {
+            if (this == KernelResult.ThreadTerminating)
+            {
+                throw new ThreadTerminatedException();
+            }
+
+            AbortUnless(Success);
+        }
+
+        public void AbortUnless(Result result)
+        {
+            if (this != result)
+            {
+                ThrowInvalidResult();
+            }
+        }
+
+        public void AbortUnless(Result result, Result result2)
+        {
+            if (this != result && this != result2)
+            {
+                ThrowInvalidResult();
+            }
+        }
+
+        private void ThrowInvalidResult()
+        {
+            throw new InvalidResultException(this);
+        }
+
+        public override string ToString()
+        {
+            if (ResultNames.TryGet(ErrorCode, out string name))
+            {
+                return name;
+            }
+
+            return PrintableResult;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon.Common/ResultNames.cs b/Ryujinx.Horizon.Common/ResultNames.cs
new file mode 100644
index 0000000000..8f8173ed5c
--- /dev/null
+++ b/Ryujinx.Horizon.Common/ResultNames.cs
@@ -0,0 +1,1701 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Common
+{
+    static class ResultNames
+    {
+        // Reference: https://github.com/Thealexbarney/LibHac/blob/master/build/CodeGen/results.csv
+        private static readonly IReadOnlyDictionary<int, string> _names = new Dictionary<int, string>()
+        {
+            { 0x0, "Success" },
+            { 0xE01, "OutOfSessions" },
+            { 0x1C01, "InvalidArgument" },
+            { 0x4201, "NotImplemented" },
+            { 0x6C01, "StopProcessingException" },
+            { 0x7201, "NoSynchronizationObject" },
+            { 0x7601, "TerminationRequested" },
+            { 0x8C01, "NoEvent" },
+            { 0xCA01, "InvalidSize" },
+            { 0xCC01, "InvalidAddress" },
+            { 0xCE01, "OutOfResource" },
+            { 0xD001, "OutOfMemory" },
+            { 0xD201, "OutOfHandles" },
+            { 0xD401, "InvalidCurrentMemory" },
+            { 0xD801, "InvalidNewMemoryPermission" },
+            { 0xDC01, "InvalidMemoryRegion" },
+            { 0xE001, "InvalidPriority" },
+            { 0xE201, "InvalidCoreId" },
+            { 0xE401, "InvalidHandle" },
+            { 0xE601, "InvalidPointer" },
+            { 0xE801, "InvalidCombination" },
+            { 0xEA01, "TimedOut" },
+            { 0xEC01, "Cancelled" },
+            { 0xEE01, "OutOfRange" },
+            { 0xF001, "InvalidEnumValue" },
+            { 0xF201, "NotFound" },
+            { 0xF401, "Busy" },
+            { 0xF601, "SessionClosed" },
+            { 0xF801, "NotHandled" },
+            { 0xFA01, "InvalidState" },
+            { 0xFC01, "ReservedUsed" },
+            { 0xFE01, "NotSupported" },
+            { 0x10001, "Debug" },
+            { 0x10201, "NoThread" },
+            { 0x10401, "UnknownThread" },
+            { 0x10601, "PortClosed" },
+            { 0x10801, "LimitReached" },
+            { 0x10A01, "InvalidMemoryPool" },
+            { 0x20401, "ReceiveListBroken" },
+            { 0x20601, "OutOfAddressSpace" },
+            { 0x20801, "MessageTooLarge" },
+            { 0x40A01, "InvalidProcessId" },
+            { 0x40C01, "InvalidThreadId" },
+            { 0x40E01, "InvalidId" },
+            { 0x41001, "ProcessTerminated" },
+            { 0x2, "HandledByAllProcess" },
+            { 0x202, "PathNotFound" },
+            { 0x402, "PathAlreadyExists" },
+            { 0x1002, "DirectoryNotEmpty" },
+            { 0x1A02, "DirectoryStatusChanged" },
+            { 0x3C02, "UsableSpaceNotEnough" },
+            { 0x3E02, "UsableSpaceNotEnoughForSaveData" },
+            { 0x4002, "UsableSpaceNotEnoughForSaveDataEvenAssistanceSuccess" },
+            { 0x4202, "UsableSpaceNotEnoughForCacheStorage" },
+            { 0x4402, "UsableSpaceNotEnoughMmc" },
+            { 0x4602, "UsableSpaceNotEnoughMmcCalibration" },
+            { 0x4802, "UsableSpaceNotEnoughMmcSafe" },
+            { 0x4A02, "UsableSpaceNotEnoughMmcUser" },
+            { 0x4C02, "UsableSpaceNotEnoughMmcSystem" },
+            { 0x4E02, "UsableSpaceNotEnoughSdCard" },
+            { 0x6402, "UnsupportedSdkVersion" },
+            { 0x7802, "MountNameAlreadyExists" },
+            { 0x8C02, "IndividualFileDataCacheAlreadyEnabled" },
+            { 0x7D002, "HandledBySystemProcess" },
+            { 0x7D202, "PartitionNotFound" },
+            { 0x7D402, "TargetNotFound" },
+            { 0x7D602, "HasNotGottenPatrolCount" },
+            { 0x7D802, "NcaExternalKeyUnregistered" },
+            { 0xFA002, "SdCardAccessFailed" },
+            { 0xFA202, "PortSdCardNoDevice" },
+            { 0xFA402, "PortSdCardNotActivated" },
+            { 0xFA602, "PortSdCardDeviceRemoved" },
+            { 0xFA802, "PortSdCardNotAwakened" },
+            { 0xFE002, "PortSdCardCommunicationError" },
+            { 0xFE202, "PortSdCardCommunicationNotAttained" },
+            { 0xFE402, "PortSdCardResponseIndexError" },
+            { 0xFE602, "PortSdCardResponseEndBitError" },
+            { 0xFE802, "PortSdCardResponseCrcError" },
+            { 0xFEA02, "PortSdCardResponseTimeoutError" },
+            { 0xFEC02, "PortSdCardDataEndBitError" },
+            { 0xFEE02, "PortSdCardDataCrcError" },
+            { 0xFF002, "PortSdCardDataTimeoutError" },
+            { 0xFF202, "PortSdCardAutoCommandResponseIndexError" },
+            { 0xFF402, "PortSdCardAutoCommandResponseEndBitError" },
+            { 0xFF602, "PortSdCardAutoCommandResponseCrcError" },
+            { 0xFF802, "PortSdCardAutoCommandResponseTimeoutError" },
+            { 0xFFA02, "PortSdCardCommandCompleteSwTimeout" },
+            { 0xFFC02, "PortSdCardTransferCompleteSwTimeout" },
+            { 0x100002, "PortSdCardDeviceStatusHasError" },
+            { 0x100202, "PortSdCardDeviceStatusAddressOutOfRange" },
+            { 0x100402, "PortSdCardDeviceStatusAddressMisalign" },
+            { 0x100602, "PortSdCardDeviceStatusBlockLenError" },
+            { 0x100802, "PortSdCardDeviceStatusEraseSeqError" },
+            { 0x100A02, "PortSdCardDeviceStatusEraseParam" },
+            { 0x100C02, "PortSdCardDeviceStatusWpViolation" },
+            { 0x100E02, "PortSdCardDeviceStatusLockUnlockFailed" },
+            { 0x101002, "PortSdCardDeviceStatusComCrcError" },
+            { 0x101202, "PortSdCardDeviceStatusIllegalCommand" },
+            { 0x101402, "PortSdCardDeviceStatusDeviceEccFailed" },
+            { 0x101602, "PortSdCardDeviceStatusCcError" },
+            { 0x101802, "PortSdCardDeviceStatusError" },
+            { 0x101A02, "PortSdCardDeviceStatusCidCsdOverwrite" },
+            { 0x101C02, "PortSdCardDeviceStatusWpEraseSkip" },
+            { 0x101E02, "PortSdCardDeviceStatusEraseReset" },
+            { 0x102002, "PortSdCardDeviceStatusSwitchError" },
+            { 0x103002, "PortSdCardUnexpectedDeviceState" },
+            { 0x103202, "PortSdCardUnexpectedDeviceCsdValue" },
+            { 0x103402, "PortSdCardAbortTransactionSwTimeout" },
+            { 0x103602, "PortSdCardCommandInhibitCmdSwTimeout" },
+            { 0x103802, "PortSdCardCommandInhibitDatSwTimeout" },
+            { 0x103A02, "PortSdCardBusySwTimeout" },
+            { 0x103C02, "PortSdCardIssueTuningCommandSwTimeout" },
+            { 0x103E02, "PortSdCardTuningFailed" },
+            { 0x104002, "PortSdCardMmcInitializationSwTimeout" },
+            { 0x104202, "PortSdCardMmcNotSupportExtendedCsd" },
+            { 0x104402, "PortSdCardUnexpectedMmcExtendedCsdValue" },
+            { 0x104602, "PortSdCardMmcEraseSwTimeout" },
+            { 0x104802, "PortSdCardSdCardValidationError" },
+            { 0x104A02, "PortSdCardSdCardInitializationSwTimeout" },
+            { 0x104C02, "PortSdCardSdCardGetValidRcaSwTimeout" },
+            { 0x104E02, "PortSdCardUnexpectedSdCardAcmdDisabled" },
+            { 0x105002, "PortSdCardSdCardNotSupportSwitchFunctionStatus" },
+            { 0x105202, "PortSdCardUnexpectedSdCardSwitchFunctionStatus" },
+            { 0x105402, "PortSdCardSdCardNotSupportAccessMode" },
+            { 0x105602, "PortSdCardSdCardNot4BitBusWidthAtUhsIMode" },
+            { 0x105802, "PortSdCardSdCardNotSupportSdr104AndSdr50" },
+            { 0x105A02, "PortSdCardSdCardCannotSwitchedAccessMode" },
+            { 0x105C02, "PortSdCardSdCardFailedSwitchedAccessMode" },
+            { 0x105E02, "PortSdCardSdCardUnacceptableCurrentConsumption" },
+            { 0x106002, "PortSdCardSdCardNotReadyToVoltageSwitch" },
+            { 0x106202, "PortSdCardSdCardNotCompleteVoltageSwitch" },
+            { 0x10A002, "PortSdCardHostControllerUnexpected" },
+            { 0x10A202, "PortSdCardInternalClockStableSwTimeout" },
+            { 0x10A402, "PortSdCardSdHostStandardUnknownAutoCmdError" },
+            { 0x10A602, "PortSdCardSdHostStandardUnknownError" },
+            { 0x10A802, "PortSdCardSdmmcDllCalibrationSwTimeout" },
+            { 0x10AA02, "PortSdCardSdmmcDllApplicationSwTimeout" },
+            { 0x10AC02, "PortSdCardSdHostStandardFailSwitchTo18V" },
+            { 0x10E002, "PortSdCardInternalError" },
+            { 0x10E202, "PortSdCardNoWaitedInterrupt" },
+            { 0x10E402, "PortSdCardWaitInterruptSwTimeout" },
+            { 0x112002, "PortSdCardAbortCommandIssued" },
+            { 0x113002, "PortSdCardNotSupported" },
+            { 0x113202, "PortSdCardNotImplemented" },
+            { 0x138002, "PortSdCardStorageDeviceInvalidated" },
+            { 0x138202, "PortSdCardWriteVerifyError" },
+            { 0x138402, "PortSdCardFileSystemInvalidatedByRemoved" },
+            { 0x138602, "PortSdCardUnexpected" },
+            { 0x138802, "GameCardAccessFailed" },
+            { 0x138A02, "GameCardUnknown" },
+            { 0x138C02, "GameCardUnexpectedDeadCode" },
+            { 0x138E02, "GameCardPreconditionViolation" },
+            { 0x139002, "GameCardNotImplemented" },
+            { 0x139C02, "GameCardQueueFullFailure" },
+            { 0x139E02, "GameCardLockerOutOfRange" },
+            { 0x13A802, "GameCardFailedIoMappingForGpio" },
+            { 0x13B002, "GameCardCardNotInserted" },
+            { 0x13B202, "GameCardCardIdMismatch" },
+            { 0x13B402, "GameCardCardNotActivated" },
+            { 0x13B602, "GameCardNotAwakened" },
+            { 0x13C402, "GameCardCardAccessFailure" },
+            { 0x13C602, "GameCardCardAccessTimeout" },
+            { 0x13C802, "GameCardCardFatal" },
+            { 0x13CA02, "GameCardCardNeedRetry" },
+            { 0x13CC02, "GameCardCardRetryFailure" },
+            { 0x13D002, "GameCardRetryLimitOut" },
+            { 0x13D202, "GameCardNeedRefresh" },
+            { 0x13D402, "GameCardNeedRefreshAndCardNeedRetry" },
+            { 0x13D802, "GameCardInvalidSecureAccess" },
+            { 0x13DA02, "GameCardInvalidNormalAccess" },
+            { 0x13DC02, "GameCardInvalidAccessAcrossMode" },
+            { 0x13DE02, "GameCardWrongCard" },
+            { 0x13E002, "GameCardInitialDataMismatch" },
+            { 0x13E202, "GameCardInitialNotFilledWithZero" },
+            { 0x13E402, "GameCardKekIndexMismatch" },
+            { 0x13E802, "GameCardInvalidGetCardDeviceCertificate" },
+            { 0x13EA02, "GameCardUnregisteredCardSecureMethod" },
+            { 0x13EC02, "GameCardCardNeedRetryAfterAsicReinitialize" },
+            { 0x13EE02, "GameCardCardHeaderReadFailure" },
+            { 0x13F002, "GameCardCardReinitializeFailure" },
+            { 0x13F202, "GameCardInvalidChallengeCardExistenceMode" },
+            { 0x13F402, "GameCardInvalidCardHeader" },
+            { 0x13F602, "GameCardInvalidT1CardCertificate" },
+            { 0x13FA02, "GameCardInvalidCa10Certificate" },
+            { 0x13FC02, "GameCardInvalidCa10CardHeader" },
+            { 0x140A02, "GameCardCommunicationFailure" },
+            { 0x140C02, "GameCardFinishOperationFailed" },
+            { 0x144A02, "GameCardStateTransitionFailure" },
+            { 0x144C02, "GameCardAlreadyTransitionedState" },
+            { 0x144E02, "GameCardShouldTransitFromAsicInitialToSecure" },
+            { 0x145002, "GameCardShouldTransitFromInitialToNormal" },
+            { 0x145202, "GameCardShouldTransitFromNormalModeToSecure" },
+            { 0x145402, "GameCardShouldTransitFromNormalModeToDebug" },
+            { 0x148A02, "GameCardInitializeAsicFailure" },
+            { 0x148C02, "GameCardAlreadyInitializedAsic" },
+            { 0x148E02, "GameCardActivateAsicFailure" },
+            { 0x149002, "GameCardAsicBootFailure" },
+            { 0x149402, "GameCardSendFirmwareFailure" },
+            { 0x149802, "GameCardVerifyCertificateFailure" },
+            { 0x149A02, "GameCardReceiveCertificateFailure" },
+            { 0x149C02, "GameCardParseCertificateFailure" },
+            { 0x149E02, "GameCardInvalidCertificate" },
+            { 0x14A002, "GameCardSendSocCertificateFailure" },
+            { 0x14A802, "GameCardGenerateCommonKeyFailure" },
+            { 0x14AA02, "GameCardReceiveRandomValueFailure" },
+            { 0x14AC02, "GameCardSendRandomValueFailure" },
+            { 0x14AE02, "GameCardDecryptRandomValueFailure" },
+            { 0x14B402, "GameCardAuthenticateMutuallyFailure" },
+            { 0x14B602, "GameCardReceiveDeviceChallengeFailure" },
+            { 0x14B802, "GameCardRespondDeviceChallengeFailure" },
+            { 0x14BA02, "GameCardSendHostChallengeFailure" },
+            { 0x14BC02, "GameCardReceiveChallengeResponseFailure" },
+            { 0x14BE02, "GameCardChallengeAndResponseFailure" },
+            { 0x14C402, "GameCardChangeModeToSecureFailure" },
+            { 0x14C602, "GameCardExchangeRandomValuesFailure" },
+            { 0x14C802, "GameCardAsicChallengeCardExistenceFailure" },
+            { 0x14CE02, "GameCardInitializeAsicTimeOut" },
+            { 0x14D202, "GameCardSplFailure" },
+            { 0x14D402, "GameCardSplDecryptAesKeyFailure" },
+            { 0x14D602, "GameCardSplDecryptAndStoreGcKeyFailure" },
+            { 0x14D802, "GameCardSplGenerateRandomBytesFailure" },
+            { 0x14DA02, "GameCardSplDecryptGcMessageFailure" },
+            { 0x14DE02, "GameCardReadRegisterFailure" },
+            { 0x14E002, "GameCardWriteRegisterFailure" },
+            { 0x14E202, "GameCardEnableCardBusFailure" },
+            { 0x14E402, "GameCardGetCardHeaderFailure" },
+            { 0x14E602, "GameCardAsicStatusError" },
+            { 0x14E802, "GameCardChangeGcModeToSecureFailure" },
+            { 0x14EA02, "GameCardChangeGcModeToDebugFailure" },
+            { 0x14EC02, "GameCardReadRmaInfoFailure" },
+            { 0x14F002, "GameCardUpdateKeyFailure" },
+            { 0x14F202, "GameCardKeySourceNotFound" },
+            { 0x150402, "GameCardStateFailure" },
+            { 0x150602, "GameCardStateCardNormalModeRequired" },
+            { 0x150802, "GameCardStateCardSecureModeRequired" },
+            { 0x150A02, "GameCardStateCardDebugModeRequired" },
+            { 0x150C02, "GameCardStateAsicInitialRequired" },
+            { 0x150E02, "GameCardStateAsicSecureRequired" },
+            { 0x151802, "GameCardGeneralIoFailure" },
+            { 0x151A02, "GameCardGeneralIoReleaseAsicResetFailure" },
+            { 0x151C02, "GameCardGeneralIoHoldAsicResetFailure" },
+            { 0x151E02, "GameCardSetVoltageFailure" },
+            { 0x152C02, "GameCardDataIoFailure" },
+            { 0x152E02, "GameCardDataIoActivateFailure" },
+            { 0x155402, "GameCardCardCommandFailure" },
+            { 0x155602, "GameCardCommandReadId1Failure" },
+            { 0x155802, "GameCardCommandReadId2Failure" },
+            { 0x155A02, "GameCardCommandReadId3Failure" },
+            { 0x155C02, "GameCardSendCardReadUidFailure" },
+            { 0x155E02, "GameCardCommandReadPageFailure" },
+            { 0x156002, "GameCardCommandReadPageUnalignedFailure" },
+            { 0x156202, "GameCardCommandWritePageFailure" },
+            { 0x156402, "GameCardCommandRefreshFailure" },
+            { 0x156602, "GameCardCommandUpdateKeyFailure" },
+            { 0x156802, "GameCardSendCardSelfRefreshFailure" },
+            { 0x156A02, "GameCardSendCardReadRefreshStatusFailure" },
+            { 0x156C02, "GameCardCommandReadCrcFailure" },
+            { 0x156E02, "GameCardCommandEraseFailure" },
+            { 0x157002, "GameCardCommandReadDevParamFailure" },
+            { 0x157202, "GameCardCommandWriteDevParamFailure" },
+            { 0x157402, "GameCardSendCardReadErrorCountFailure" },
+            { 0x16A802, "GameCardDevCardUnexpectedFailure" },
+            { 0x16AA02, "GameCardDebugParameterMismatch" },
+            { 0x16AC02, "GameCardDebugEraseFailure" },
+            { 0x16AE02, "GameCardDebugWriteCrcMismatch" },
+            { 0x16B002, "GameCardDebugCardReceivedIdMismatch" },
+            { 0x16B202, "GameCardDebugCardId1Mismatch" },
+            { 0x16B402, "GameCardDebugCardId2Mismatch" },
+            { 0x170C02, "GameCardFsFailure" },
+            { 0x170E02, "GameCardFsGetHandleFailure" },
+            { 0x171002, "GameCardFsCheckHandleInReadFailure" },
+            { 0x171202, "GameCardFsCheckHandleInWriteFailure" },
+            { 0x171402, "GameCardFsCheckHandleInGetStatusFailure" },
+            { 0x171602, "GameCardFsCheckHandleInGetDeviceCertFailure" },
+            { 0x171802, "GameCardFsCheckHandleInGetCardImageHashFailure" },
+            { 0x171A02, "GameCardFsCheckHandleInChallengeCardExistence" },
+            { 0x171C02, "GameCardFsCheckHandleInOnAcquireLock" },
+            { 0x171E02, "GameCardFsCheckModeInOnAcquireSecureLock" },
+            { 0x172002, "GameCardFsCheckHandleInCreateReadOnlyFailure" },
+            { 0x172202, "GameCardFsCheckHandleInCreateSecureReadOnlyFailure" },
+            { 0x172402, "GameCardFsInvalidCompatibilityType" },
+            { 0x172602, "GameCardNotSupportedOnDeviceModel" },
+            { 0x177002, "Internal" },
+            { 0x177202, "NotImplemented" },
+            { 0x177402, "UnsupportedVersion" },
+            { 0x177602, "AlreadyExists" },
+            { 0x177A02, "OutOfRange" },
+            { 0x183602, "StorageDeviceInvalidOperation" },
+            { 0x183802, "SystemPartitionNotReady" },
+            { 0x183A02, "StorageDeviceNotReady" },
+            { 0x190002, "AllocationMemoryFailed" },
+            { 0x190202, "AllocationMemoryFailedInFatFileSystemA" },
+            { 0x190602, "AllocationMemoryFailedInFatFileSystemC" },
+            { 0x190802, "AllocationMemoryFailedInFatFileSystemD" },
+            { 0x190A02, "AllocationMemoryFailedInFatFileSystemE" },
+            { 0x190C02, "AllocationMemoryFailedInFatFileSystemF" },
+            { 0x191002, "AllocationMemoryFailedInFatFileSystemH" },
+            { 0x191602, "AllocationMemoryFailedInFileSystemAccessorA" },
+            { 0x191802, "AllocationMemoryFailedInFileSystemAccessorB" },
+            { 0x191A02, "AllocationMemoryFailedInApplicationA" },
+            { 0x191C02, "AllocationMemoryFailedInBcatSaveDataA" },
+            { 0x191E02, "AllocationMemoryFailedInBisA" },
+            { 0x192002, "AllocationMemoryFailedInBisB" },
+            { 0x192202, "AllocationMemoryFailedInBisC" },
+            { 0x192402, "AllocationMemoryFailedInCodeA" },
+            { 0x192602, "AllocationMemoryFailedInContentA" },
+            { 0x192802, "AllocationMemoryFailedInContentStorageA" },
+            { 0x192A02, "AllocationMemoryFailedInContentStorageB" },
+            { 0x192C02, "AllocationMemoryFailedInDataA" },
+            { 0x192E02, "AllocationMemoryFailedInDataB" },
+            { 0x193002, "AllocationMemoryFailedInDeviceSaveDataA" },
+            { 0x193202, "AllocationMemoryFailedInGameCardA" },
+            { 0x193402, "AllocationMemoryFailedInGameCardB" },
+            { 0x193602, "AllocationMemoryFailedInGameCardC" },
+            { 0x193802, "AllocationMemoryFailedInGameCardD" },
+            { 0x193A02, "AllocationMemoryFailedInHostA" },
+            { 0x193C02, "AllocationMemoryFailedInHostB" },
+            { 0x193E02, "AllocationMemoryFailedInHostC" },
+            { 0x194002, "AllocationMemoryFailedInImageDirectoryA" },
+            { 0x194202, "AllocationMemoryFailedInLogoA" },
+            { 0x194402, "AllocationMemoryFailedInRomA" },
+            { 0x194602, "AllocationMemoryFailedInRomB" },
+            { 0x194802, "AllocationMemoryFailedInRomC" },
+            { 0x194A02, "AllocationMemoryFailedInRomD" },
+            { 0x194C02, "AllocationMemoryFailedInRomE" },
+            { 0x194E02, "AllocationMemoryFailedInRomF" },
+            { 0x195402, "AllocationMemoryFailedInSaveDataManagementA" },
+            { 0x195602, "AllocationMemoryFailedInSaveDataThumbnailA" },
+            { 0x195802, "AllocationMemoryFailedInSdCardA" },
+            { 0x195A02, "AllocationMemoryFailedInSdCardB" },
+            { 0x195C02, "AllocationMemoryFailedInSystemSaveDataA" },
+            { 0x195E02, "AllocationMemoryFailedInRomFsFileSystemA" },
+            { 0x196002, "AllocationMemoryFailedInRomFsFileSystemB" },
+            { 0x196202, "AllocationMemoryFailedInRomFsFileSystemC" },
+            { 0x196602, "AllocationMemoryFailedInGuidPartitionTableA" },
+            { 0x196802, "AllocationMemoryFailedInDeviceDetectionEventManagerA" },
+            { 0x196A02, "AllocationMemoryFailedInSaveDataFileSystemServiceImplA" },
+            { 0x196C02, "AllocationMemoryFailedInFileSystemProxyCoreImplB" },
+            { 0x196E02, "AllocationMemoryFailedInSdCardProxyFileSystemCreatorA" },
+            { 0x197002, "AllocationMemoryFailedInNcaFileSystemServiceImplA" },
+            { 0x197202, "AllocationMemoryFailedInNcaFileSystemServiceImplB" },
+            { 0x197402, "AllocationMemoryFailedInProgramRegistryManagerA" },
+            { 0x197602, "AllocationMemoryFailedInSdmmcStorageServiceA" },
+            { 0x197802, "AllocationMemoryFailedInBuiltInStorageCreatorA" },
+            { 0x197A02, "AllocationMemoryFailedInBuiltInStorageCreatorB" },
+            { 0x197C02, "AllocationMemoryFailedInBuiltInStorageCreatorC" },
+            { 0x198002, "AllocationMemoryFailedFatFileSystemWithBufferA" },
+            { 0x198202, "AllocationMemoryFailedInFatFileSystemCreatorA" },
+            { 0x198402, "AllocationMemoryFailedInFatFileSystemCreatorB" },
+            { 0x198602, "AllocationMemoryFailedInGameCardFileSystemCreatorA" },
+            { 0x198802, "AllocationMemoryFailedInGameCardFileSystemCreatorB" },
+            { 0x198A02, "AllocationMemoryFailedInGameCardFileSystemCreatorC" },
+            { 0x198C02, "AllocationMemoryFailedInGameCardFileSystemCreatorD" },
+            { 0x198E02, "AllocationMemoryFailedInGameCardFileSystemCreatorE" },
+            { 0x199002, "AllocationMemoryFailedInGameCardFileSystemCreatorF" },
+            { 0x199202, "AllocationMemoryFailedInGameCardManagerA" },
+            { 0x199402, "AllocationMemoryFailedInGameCardManagerB" },
+            { 0x199602, "AllocationMemoryFailedInGameCardManagerC" },
+            { 0x199802, "AllocationMemoryFailedInGameCardManagerD" },
+            { 0x199A02, "AllocationMemoryFailedInGameCardManagerE" },
+            { 0x199C02, "AllocationMemoryFailedInGameCardManagerF" },
+            { 0x199E02, "AllocationMemoryFailedInLocalFileSystemCreatorA" },
+            { 0x19A002, "AllocationMemoryFailedInPartitionFileSystemCreatorA" },
+            { 0x19A202, "AllocationMemoryFailedInRomFileSystemCreatorA" },
+            { 0x19A402, "AllocationMemoryFailedInSaveDataFileSystemCreatorA" },
+            { 0x19A602, "AllocationMemoryFailedInSaveDataFileSystemCreatorB" },
+            { 0x19A802, "AllocationMemoryFailedInSaveDataFileSystemCreatorC" },
+            { 0x19AA02, "AllocationMemoryFailedInSaveDataFileSystemCreatorD" },
+            { 0x19AC02, "AllocationMemoryFailedInSaveDataFileSystemCreatorE" },
+            { 0x19B002, "AllocationMemoryFailedInStorageOnNcaCreatorA" },
+            { 0x19B202, "AllocationMemoryFailedInStorageOnNcaCreatorB" },
+            { 0x19B402, "AllocationMemoryFailedInSubDirectoryFileSystemCreatorA" },
+            { 0x19B602, "AllocationMemoryFailedInTargetManagerFileSystemCreatorA" },
+            { 0x19B802, "AllocationMemoryFailedInSaveDataIndexerA" },
+            { 0x19BA02, "AllocationMemoryFailedInSaveDataIndexerB" },
+            { 0x19BC02, "AllocationMemoryFailedInFileSystemBuddyHeapA" },
+            { 0x19BE02, "AllocationMemoryFailedInFileSystemBufferManagerA" },
+            { 0x19C002, "AllocationMemoryFailedInBlockCacheBufferedStorageA" },
+            { 0x19C202, "AllocationMemoryFailedInBlockCacheBufferedStorageB" },
+            { 0x19C402, "AllocationMemoryFailedInDuplexStorageA" },
+            { 0x19D002, "AllocationMemoryFailedInIntegrityVerificationStorageA" },
+            { 0x19D202, "AllocationMemoryFailedInIntegrityVerificationStorageB" },
+            { 0x19D402, "AllocationMemoryFailedInJournalStorageA" },
+            { 0x19D602, "AllocationMemoryFailedInJournalStorageB" },
+            { 0x19DC02, "AllocationMemoryFailedInSaveDataFileSystemCoreA" },
+            { 0x19DE02, "AllocationMemoryFailedInSaveDataFileSystemCoreB" },
+            { 0x19E002, "AllocationMemoryFailedInAesXtsFileA" },
+            { 0x19E202, "AllocationMemoryFailedInAesXtsFileB" },
+            { 0x19E402, "AllocationMemoryFailedInAesXtsFileC" },
+            { 0x19E602, "AllocationMemoryFailedInAesXtsFileD" },
+            { 0x19E802, "AllocationMemoryFailedInAesXtsFileSystemA" },
+            { 0x19EE02, "AllocationMemoryFailedInConcatenationFileSystemA" },
+            { 0x19F002, "AllocationMemoryFailedInConcatenationFileSystemB" },
+            { 0x19F202, "AllocationMemoryFailedInDirectorySaveDataFileSystemA" },
+            { 0x19F402, "AllocationMemoryFailedInLocalFileSystemA" },
+            { 0x19F602, "AllocationMemoryFailedInLocalFileSystemB" },
+            { 0x1A1A02, "AllocationMemoryFailedInNcaFileSystemDriverI" },
+            { 0x1A2602, "AllocationMemoryFailedInPartitionFileSystemA" },
+            { 0x1A2802, "AllocationMemoryFailedInPartitionFileSystemB" },
+            { 0x1A2A02, "AllocationMemoryFailedInPartitionFileSystemC" },
+            { 0x1A2C02, "AllocationMemoryFailedInPartitionFileSystemMetaA" },
+            { 0x1A2E02, "AllocationMemoryFailedInPartitionFileSystemMetaB" },
+            { 0x1A3002, "AllocationMemoryFailedInRomFsFileSystemD" },
+            { 0x1A3602, "AllocationMemoryFailedInSubdirectoryFileSystemA" },
+            { 0x1A3802, "AllocationMemoryFailedInTmFileSystemA" },
+            { 0x1A3A02, "AllocationMemoryFailedInTmFileSystemB" },
+            { 0x1A3E02, "AllocationMemoryFailedInProxyFileSystemA" },
+            { 0x1A4002, "AllocationMemoryFailedInProxyFileSystemB" },
+            { 0x1A4402, "AllocationMemoryFailedInSaveDataExtraDataAccessorCacheManagerA" },
+            { 0x1A4602, "AllocationMemoryFailedInNcaReaderA" },
+            { 0x1A4A02, "AllocationMemoryFailedInRegisterA" },
+            { 0x1A4C02, "AllocationMemoryFailedInRegisterB" },
+            { 0x1A4E02, "AllocationMemoryFailedInPathNormalizer" },
+            { 0x1A5E02, "AllocationMemoryFailedInDbmRomKeyValueStorage" },
+            { 0x1A6002, "AllocationMemoryFailedInDbmHierarchicalRomFileTable" },
+            { 0x1A6202, "AllocationMemoryFailedInRomFsFileSystemE" },
+            { 0x1A6402, "AllocationMemoryFailedInISaveFileSystemA" },
+            { 0x1A6602, "AllocationMemoryFailedInISaveFileSystemB" },
+            { 0x1A6802, "AllocationMemoryFailedInRomOnFileA" },
+            { 0x1A6A02, "AllocationMemoryFailedInRomOnFileB" },
+            { 0x1A6C02, "AllocationMemoryFailedInRomOnFileC" },
+            { 0x1A6E02, "AllocationMemoryFailedInAesXtsFileE" },
+            { 0x1A7002, "AllocationMemoryFailedInAesXtsFileF" },
+            { 0x1A7202, "AllocationMemoryFailedInAesXtsFileG" },
+            { 0x1A7402, "AllocationMemoryFailedInReadOnlyFileSystemA" },
+            { 0x1A8402, "AllocationMemoryFailedInEncryptedFileSystemCreatorA" },
+            { 0x1A8E02, "AllocationMemoryFailedInAesCtrCounterExtendedStorageA" },
+            { 0x1A9002, "AllocationMemoryFailedInAesCtrCounterExtendedStorageB" },
+            { 0x1A9C02, "AllocationMemoryFailedInSdmmcStorageServiceB" },
+            { 0x1A9E02, "AllocationMemoryFailedInFileSystemInterfaceAdapterA" },
+            { 0x1AA002, "AllocationMemoryFailedInGameCardFileSystemCreatorG" },
+            { 0x1AA202, "AllocationMemoryFailedInGameCardFileSystemCreatorH" },
+            { 0x1AA402, "AllocationMemoryFailedInAesXtsFileSystemB" },
+            { 0x1AA602, "AllocationMemoryFailedInBufferedStorageA" },
+            { 0x1AA802, "AllocationMemoryFailedInIntegrityRomFsStorageA" },
+            { 0x1AB002, "AllocationMemoryFailedInSaveDataFileSystemServiceImplB" },
+            { 0x1AB802, "AllocationMemoryFailedNew" },
+            { 0x1ABA02, "AllocationMemoryFailedInFileSystemProxyImplA" },
+            { 0x1ABC02, "AllocationMemoryFailedMakeUnique" },
+            { 0x1ABE02, "AllocationMemoryFailedAllocateShared" },
+            { 0x1AC002, "AllocationPooledBufferNotEnoughSize" },
+            { 0x1AC802, "AllocationMemoryFailedInWriteThroughCacheStorageA" },
+            { 0x1ACA02, "AllocationMemoryFailedInSaveDataTransferManagerA" },
+            { 0x1ACC02, "AllocationMemoryFailedInSaveDataTransferManagerB" },
+            { 0x1ACE02, "AllocationMemoryFailedInHtcFileSystemA" },
+            { 0x1AD002, "AllocationMemoryFailedInHtcFileSystemB" },
+            { 0x1AD202, "AllocationMemoryFailedInGameCardManagerG" },
+            { 0x1B5802, "MmcAccessFailed" },
+            { 0x1B5A02, "PortMmcNoDevice" },
+            { 0x1B5C02, "PortMmcNotActivated" },
+            { 0x1B5E02, "PortMmcDeviceRemoved" },
+            { 0x1B6002, "PortMmcNotAwakened" },
+            { 0x1B9802, "PortMmcCommunicationError" },
+            { 0x1B9A02, "PortMmcCommunicationNotAttained" },
+            { 0x1B9C02, "PortMmcResponseIndexError" },
+            { 0x1B9E02, "PortMmcResponseEndBitError" },
+            { 0x1BA002, "PortMmcResponseCrcError" },
+            { 0x1BA202, "PortMmcResponseTimeoutError" },
+            { 0x1BA402, "PortMmcDataEndBitError" },
+            { 0x1BA602, "PortMmcDataCrcError" },
+            { 0x1BA802, "PortMmcDataTimeoutError" },
+            { 0x1BAA02, "PortMmcAutoCommandResponseIndexError" },
+            { 0x1BAC02, "PortMmcAutoCommandResponseEndBitError" },
+            { 0x1BAE02, "PortMmcAutoCommandResponseCrcError" },
+            { 0x1BB002, "PortMmcAutoCommandResponseTimeoutError" },
+            { 0x1BB202, "PortMmcCommandCompleteSwTimeout" },
+            { 0x1BB402, "PortMmcTransferCompleteSwTimeout" },
+            { 0x1BB802, "PortMmcDeviceStatusHasError" },
+            { 0x1BBA02, "PortMmcDeviceStatusAddressOutOfRange" },
+            { 0x1BBC02, "PortMmcDeviceStatusAddressMisalign" },
+            { 0x1BBE02, "PortMmcDeviceStatusBlockLenError" },
+            { 0x1BC002, "PortMmcDeviceStatusEraseSeqError" },
+            { 0x1BC202, "PortMmcDeviceStatusEraseParam" },
+            { 0x1BC402, "PortMmcDeviceStatusWpViolation" },
+            { 0x1BC602, "PortMmcDeviceStatusLockUnlockFailed" },
+            { 0x1BC802, "PortMmcDeviceStatusComCrcError" },
+            { 0x1BCA02, "PortMmcDeviceStatusIllegalCommand" },
+            { 0x1BCC02, "PortMmcDeviceStatusDeviceEccFailed" },
+            { 0x1BCE02, "PortMmcDeviceStatusCcError" },
+            { 0x1BD002, "PortMmcDeviceStatusError" },
+            { 0x1BD202, "PortMmcDeviceStatusCidCsdOverwrite" },
+            { 0x1BD402, "PortMmcDeviceStatusWpEraseSkip" },
+            { 0x1BD602, "PortMmcDeviceStatusEraseReset" },
+            { 0x1BD802, "PortMmcDeviceStatusSwitchError" },
+            { 0x1BE802, "PortMmcUnexpectedDeviceState" },
+            { 0x1BEA02, "PortMmcUnexpectedDeviceCsdValue" },
+            { 0x1BEC02, "PortMmcAbortTransactionSwTimeout" },
+            { 0x1BEE02, "PortMmcCommandInhibitCmdSwTimeout" },
+            { 0x1BF002, "PortMmcCommandInhibitDatSwTimeout" },
+            { 0x1BF202, "PortMmcBusySwTimeout" },
+            { 0x1BF402, "PortMmcIssueTuningCommandSwTimeout" },
+            { 0x1BF602, "PortMmcTuningFailed" },
+            { 0x1BF802, "PortMmcMmcInitializationSwTimeout" },
+            { 0x1BFA02, "PortMmcMmcNotSupportExtendedCsd" },
+            { 0x1BFC02, "PortMmcUnexpectedMmcExtendedCsdValue" },
+            { 0x1BFE02, "PortMmcMmcEraseSwTimeout" },
+            { 0x1C0002, "PortMmcSdCardValidationError" },
+            { 0x1C0202, "PortMmcSdCardInitializationSwTimeout" },
+            { 0x1C0402, "PortMmcSdCardGetValidRcaSwTimeout" },
+            { 0x1C0602, "PortMmcUnexpectedSdCardAcmdDisabled" },
+            { 0x1C0802, "PortMmcSdCardNotSupportSwitchFunctionStatus" },
+            { 0x1C0A02, "PortMmcUnexpectedSdCardSwitchFunctionStatus" },
+            { 0x1C0C02, "PortMmcSdCardNotSupportAccessMode" },
+            { 0x1C0E02, "PortMmcSdCardNot4BitBusWidthAtUhsIMode" },
+            { 0x1C1002, "PortMmcSdCardNotSupportSdr104AndSdr50" },
+            { 0x1C1202, "PortMmcSdCardCannotSwitchedAccessMode" },
+            { 0x1C1402, "PortMmcSdCardFailedSwitchedAccessMode" },
+            { 0x1C1602, "PortMmcSdCardUnacceptableCurrentConsumption" },
+            { 0x1C1802, "PortMmcSdCardNotReadyToVoltageSwitch" },
+            { 0x1C1A02, "PortMmcSdCardNotCompleteVoltageSwitch" },
+            { 0x1C5802, "PortMmcHostControllerUnexpected" },
+            { 0x1C5A02, "PortMmcInternalClockStableSwTimeout" },
+            { 0x1C5C02, "PortMmcSdHostStandardUnknownAutoCmdError" },
+            { 0x1C5E02, "PortMmcSdHostStandardUnknownError" },
+            { 0x1C6002, "PortMmcSdmmcDllCalibrationSwTimeout" },
+            { 0x1C6202, "PortMmcSdmmcDllApplicationSwTimeout" },
+            { 0x1C6402, "PortMmcSdHostStandardFailSwitchTo18V" },
+            { 0x1C9802, "PortMmcInternalError" },
+            { 0x1C9A02, "PortMmcNoWaitedInterrupt" },
+            { 0x1C9C02, "PortMmcWaitInterruptSwTimeout" },
+            { 0x1CD802, "PortMmcAbortCommandIssued" },
+            { 0x1CE802, "PortMmcNotSupported" },
+            { 0x1CEA02, "PortMmcNotImplemented" },
+            { 0x1F3C02, "PortMmcStorageDeviceInvalidated" },
+            { 0x1F3E02, "PortMmcUnexpected" },
+            { 0x1F4002, "DataCorrupted" },
+            { 0x1F4202, "RomCorrupted" },
+            { 0x1F4402, "UnsupportedRomVersion" },
+            { 0x1F5602, "AesCtrCounterExtendedStorageCorrupted" },
+            { 0x1F5802, "InvalidAesCtrCounterExtendedEntryOffset" },
+            { 0x1F5A02, "InvalidAesCtrCounterExtendedTableSize" },
+            { 0x1F5C02, "InvalidAesCtrCounterExtendedGeneration" },
+            { 0x1F5E02, "InvalidAesCtrCounterExtendedOffset" },
+            { 0x1F6002, "InvalidAesCtrCounterExtendedDataStorageSize" },
+            { 0x1F6202, "InvalidAesCtrCounterExtendedMetaStorageSize" },
+            { 0x1F6A02, "IndirectStorageCorrupted" },
+            { 0x1F6C02, "InvalidIndirectEntryOffset" },
+            { 0x1F6E02, "InvalidIndirectEntryStorageIndex" },
+            { 0x1F7002, "InvalidIndirectStorageSize" },
+            { 0x1F7202, "InvalidIndirectVirtualOffset" },
+            { 0x1F7402, "InvalidIndirectPhysicalOffset" },
+            { 0x1F7602, "InvalidIndirectStorageIndex" },
+            { 0x1F7802, "InvalidIndirectStorageBucketTreeSize" },
+            { 0x1F7E02, "BucketTreeCorrupted" },
+            { 0x1F8002, "InvalidBucketTreeSignature" },
+            { 0x1F8202, "InvalidBucketTreeEntryCount" },
+            { 0x1F8402, "InvalidBucketTreeNodeEntryCount" },
+            { 0x1F8602, "InvalidBucketTreeNodeOffset" },
+            { 0x1F8802, "InvalidBucketTreeEntryOffset" },
+            { 0x1F8A02, "InvalidBucketTreeEntrySetOffset" },
+            { 0x1F8C02, "InvalidBucketTreeNodeIndex" },
+            { 0x1F8E02, "InvalidBucketTreeVirtualOffset" },
+            { 0x1F9202, "RomNcaCorrupted" },
+            { 0x1FA602, "RomNcaFileSystemCorrupted" },
+            { 0x1FA802, "InvalidRomNcaFileSystemType" },
+            { 0x1FAA02, "InvalidRomAcidFileSize" },
+            { 0x1FAC02, "InvalidRomAcidSize" },
+            { 0x1FAE02, "InvalidRomAcid" },
+            { 0x1FB002, "RomAcidVerificationFailed" },
+            { 0x1FB202, "InvalidRomNcaSignature" },
+            { 0x1FB402, "RomNcaHeaderSignature1VerificationFailed" },
+            { 0x1FB602, "RomNcaHeaderSignature2VerificationFailed" },
+            { 0x1FB802, "RomNcaFsHeaderHashVerificationFailed" },
+            { 0x1FBA02, "InvalidRomNcaKeyIndex" },
+            { 0x1FBC02, "InvalidRomNcaFsHeaderHashType" },
+            { 0x1FBE02, "InvalidRomNcaFsHeaderEncryptionType" },
+            { 0x1FC002, "InvalidRomNcaPatchInfoIndirectSize" },
+            { 0x1FC202, "InvalidRomNcaPatchInfoAesCtrExSize" },
+            { 0x1FC402, "InvalidRomNcaPatchInfoAesCtrExOffset" },
+            { 0x1FC602, "InvalidRomNcaId" },
+            { 0x1FC802, "InvalidRomNcaHeader" },
+            { 0x1FCA02, "InvalidRomNcaFsHeader" },
+            { 0x1FCC02, "InvalidRomNcaPatchInfoIndirectOffset" },
+            { 0x1FCE02, "RomNcaHierarchicalSha256StorageCorrupted" },
+            { 0x1FD002, "InvalidRomHierarchicalSha256BlockSize" },
+            { 0x1FD202, "InvalidRomHierarchicalSha256LayerCount" },
+            { 0x1FD402, "RomHierarchicalSha256BaseStorageTooLarge" },
+            { 0x1FD602, "RomHierarchicalSha256HashVerificationFailed" },
+            { 0x1FE202, "InvalidRomHierarchicalIntegrityVerificationLayerCount" },
+            { 0x1FE402, "RomNcaIndirectStorageOutOfRange" },
+            { 0x1FE602, "RomNcaInvalidCompressionInfo" },
+            { 0x205A02, "RomIntegrityVerificationStorageCorrupted" },
+            { 0x205C02, "IncorrectRomIntegrityVerificationMagicCode" },
+            { 0x205E02, "InvalidRomZeroSignature" },
+            { 0x206002, "RomNonRealDataVerificationFailed" },
+            { 0x206E02, "RomRealDataVerificationFailed" },
+            { 0x207002, "ClearedRomRealDataVerificationFailed" },
+            { 0x207202, "UnclearedRomRealDataVerificationFailed" },
+            { 0x20AA02, "RomPartitionFileSystemCorrupted" },
+            { 0x20AC02, "InvalidRomSha256PartitionHashTarget" },
+            { 0x20AE02, "RomSha256PartitionHashVerificationFailed" },
+            { 0x20B002, "RomPartitionSignatureVerificationFailed" },
+            { 0x20B202, "RomSha256PartitionSignatureVerificationFailed" },
+            { 0x20B402, "InvalidRomPartitionEntryOffset" },
+            { 0x20B602, "InvalidRomSha256PartitionMetaDataSize" },
+            { 0x20D202, "RomBuiltInStorageCorrupted" },
+            { 0x20D402, "RomGptHeaderSignatureVerificationFailed" },
+            { 0x212202, "RomHostFileSystemCorrupted" },
+            { 0x212402, "RomHostEntryCorrupted" },
+            { 0x212602, "RomHostFileDataCorrupted" },
+            { 0x212802, "RomHostFileCorrupted" },
+            { 0x212A02, "InvalidRomHostHandle" },
+            { 0x214A02, "RomDatabaseCorrupted" },
+            { 0x214C02, "InvalidRomAllocationTableBlock" },
+            { 0x214E02, "InvalidRomKeyValueListElementIndex" },
+            { 0x217002, "RomStorageCorrupted" },
+            { 0x217202, "InvalidRomStorageSize" },
+            { 0x219A02, "SaveDataCorrupted" },
+            { 0x219C02, "UnsupportedSaveDataVersion" },
+            { 0x219E02, "InvalidSaveDataEntryType" },
+            { 0x21A002, "ReconstructibleSaveDataCorrupted" },
+            { 0x21AE02, "SaveDataFileSystemCorrupted" },
+            { 0x21B002, "InvalidJournalIntegritySaveDataHashSize" },
+            { 0x21B202, "InvalidJournalIntegritySaveDataCommitState" },
+            { 0x21B402, "InvalidJournalIntegritySaveDataControlAreaSize" },
+            { 0x21B602, "JournalIntegritySaveDataControlAreaVerificationFailed" },
+            { 0x21B802, "JournalIntegritySaveDataMasterSignatureVerificationFailed" },
+            { 0x21BA02, "IncorrectJournalIntegritySaveDataMagicCode" },
+            { 0x21C202, "SaveDataDuplexStorageCorrupted" },
+            { 0x21C402, "IncorrectDuplexMagicCode" },
+            { 0x21C602, "DuplexStorageAccessOutOfRange" },
+            { 0x21D602, "SaveDataMapCorrupted" },
+            { 0x21D802, "InvalidMapEntryCount" },
+            { 0x21DA02, "InvalidMapOffset" },
+            { 0x21DC02, "InvalidMapSize" },
+            { 0x21DE02, "InvalidMapAlignment" },
+            { 0x21E002, "InvalidMapStorageType" },
+            { 0x21E202, "MapAddressAlreadyRegistered" },
+            { 0x21E402, "MapStorageNotFound" },
+            { 0x21E602, "InvalidMapStorageSize" },
+            { 0x21EA02, "SaveDataLogCorrupted" },
+            { 0x21EC02, "InvalidLogBlockSize" },
+            { 0x21EE02, "InvalidLogOffset" },
+            { 0x21F002, "UnexpectedEndOfLog" },
+            { 0x21F202, "LogNotFound" },
+            { 0x220002, "ThumbnailHashVerificationFailed" },
+            { 0x220A02, "InvalidSaveDataInternalStorageIntegritySeedSize" },
+            { 0x220C02, "InvalidSaveDataInternalStorageAllocationTableFreeBitmapSizeA" },
+            { 0x220E02, "InvalidSaveDataInternalStorageAllocationTableFreeBitmapSizeB" },
+            { 0x221202, "SaveDataIntegrityVerificationStorageCorrupted" },
+            { 0x221402, "IncorrectSaveDataIntegrityVerificationMagicCode" },
+            { 0x221602, "InvalidSaveDataZeroHash" },
+            { 0x221802, "SaveDataNonRealDataVerificationFailed" },
+            { 0x222602, "SaveDataRealDataVerificationFailed" },
+            { 0x222802, "ClearedSaveDataRealDataVerificationFailed" },
+            { 0x222A02, "UnclearedSaveDataRealDataVerificationFailed" },
+            { 0x226202, "SaveDataBuiltInStorageCorrupted" },
+            { 0x226402, "SaveDataGptHeaderSignatureVerificationFailed" },
+            { 0x227602, "SaveDataCoreFileSystemCorrupted" },
+            { 0x227802, "IncorrectSaveDataFileSystemMagicCode" },
+            { 0x227A02, "InvalidSaveDataFileReadOffset" },
+            { 0x227C02, "InvalidSaveDataCoreDataStorageSize" },
+            { 0x229602, "IncompleteBlockInZeroBitmapHashStorageFileSaveData" },
+            { 0x229E02, "JournalStorageCorrupted" },
+            { 0x22A002, "JournalStorageAccessOutOfRange" },
+            { 0x22A202, "InvalidJournalStorageDataStorageSize" },
+            { 0x22B202, "SaveDataHostFileSystemCorrupted" },
+            { 0x22B402, "SaveDataHostEntryCorrupted" },
+            { 0x22B602, "SaveDataHostFileDataCorrupted" },
+            { 0x22B802, "SaveDataHostFileCorrupted" },
+            { 0x22BA02, "InvalidSaveDataHostHandle" },
+            { 0x22C602, "MappingTableCorrupted" },
+            { 0x22C802, "InvalidMappingTableEntryCount" },
+            { 0x22CA02, "InvalidMappingTablePhysicalIndex" },
+            { 0x22CC02, "InvalidMappingTableVirtualIndex" },
+            { 0x22DA02, "SaveDataDatabaseCorrupted" },
+            { 0x22DC02, "InvalidSaveDataAllocationTableBlock" },
+            { 0x22DE02, "InvalidSaveDataKeyValueListElementIndex" },
+            { 0x22E002, "InvalidSaveDataAllocationTableChainEntry" },
+            { 0x22E202, "InvalidSaveDataAllocationTableOffset" },
+            { 0x22E402, "InvalidSaveDataAllocationTableBlockCount" },
+            { 0x22E602, "InvalidSaveDataKeyValueListEntryIndex" },
+            { 0x22E802, "InvalidSaveDataBitmapIndex" },
+            { 0x230202, "SaveDataExtensionContextCorrupted" },
+            { 0x230402, "IncorrectSaveDataExtensionContextMagicCode" },
+            { 0x230602, "InvalidSaveDataExtensionContextState" },
+            { 0x230802, "DifferentSaveDataExtensionContextParameter" },
+            { 0x230A02, "InvalidSaveDataExtensionContextParameter" },
+            { 0x231602, "IntegritySaveDataCorrupted" },
+            { 0x231802, "InvalidIntegritySaveDataHashSize" },
+            { 0x231C02, "InvalidIntegritySaveDataControlAreaSize" },
+            { 0x231E02, "IntegritySaveDataControlAreaVerificationFailed" },
+            { 0x232002, "IntegritySaveDataMasterSignatureVerificationFailed" },
+            { 0x232202, "IncorrectIntegritySaveDataMagicCode" },
+            { 0x232A02, "NcaCorrupted" },
+            { 0x233802, "NcaBaseStorageOutOfRangeA" },
+            { 0x233A02, "NcaBaseStorageOutOfRangeB" },
+            { 0x233C02, "NcaBaseStorageOutOfRangeC" },
+            { 0x233E02, "NcaFileSystemCorrupted" },
+            { 0x234002, "InvalidNcaFileSystemType" },
+            { 0x234202, "InvalidAcidFileSize" },
+            { 0x234402, "InvalidAcidSize" },
+            { 0x234602, "InvalidAcid" },
+            { 0x234802, "AcidVerificationFailed" },
+            { 0x234A02, "InvalidNcaSignature" },
+            { 0x234C02, "NcaHeaderSignature1VerificationFailed" },
+            { 0x234E02, "NcaHeaderSignature2VerificationFailed" },
+            { 0x235002, "NcaFsHeaderHashVerificationFailed" },
+            { 0x235202, "InvalidNcaKeyIndex" },
+            { 0x235402, "InvalidNcaFsHeaderHashType" },
+            { 0x235602, "InvalidNcaFsHeaderEncryptionType" },
+            { 0x235802, "InvalidNcaPatchInfoIndirectSize" },
+            { 0x235A02, "InvalidNcaPatchInfoAesCtrExSize" },
+            { 0x235C02, "InvalidNcaPatchInfoAesCtrExOffset" },
+            { 0x235E02, "InvalidNcaId" },
+            { 0x236002, "InvalidNcaHeader" },
+            { 0x236202, "InvalidNcaFsHeader" },
+            { 0x236402, "InvalidNcaPatchInfoIndirectOffset" },
+            { 0x236602, "NcaHierarchicalSha256StorageCorrupted" },
+            { 0x236802, "InvalidHierarchicalSha256BlockSize" },
+            { 0x236A02, "InvalidHierarchicalSha256LayerCount" },
+            { 0x236C02, "HierarchicalSha256BaseStorageTooLarge" },
+            { 0x236E02, "HierarchicalSha256HashVerificationFailed" },
+            { 0x237A02, "InvalidHierarchicalIntegrityVerificationLayerCount" },
+            { 0x237C02, "NcaIndirectStorageOutOfRange" },
+            { 0x237E02, "InvalidNcaHeader1SignatureKeyGeneration" },
+            { 0x238202, "InvalidNspdVerificationData" },
+            { 0x238402, "MissingNspdVerificationData" },
+            { 0x238602, "NcaInvalidCompressionInfo" },
+            { 0x23F202, "IntegrityVerificationStorageCorrupted" },
+            { 0x23F402, "IncorrectIntegrityVerificationMagicCode" },
+            { 0x23F602, "InvalidZeroHash" },
+            { 0x23F802, "NonRealDataVerificationFailed" },
+            { 0x240602, "RealDataVerificationFailed" },
+            { 0x240802, "ClearedRealDataVerificationFailed" },
+            { 0x240A02, "UnclearedRealDataVerificationFailed" },
+            { 0x244202, "PartitionFileSystemCorrupted" },
+            { 0x244402, "InvalidSha256PartitionHashTarget" },
+            { 0x244602, "Sha256PartitionHashVerificationFailed" },
+            { 0x244802, "PartitionSignatureVerificationFailed" },
+            { 0x244A02, "Sha256PartitionSignatureVerificationFailed" },
+            { 0x244C02, "InvalidPartitionEntryOffset" },
+            { 0x244E02, "InvalidSha256PartitionMetaDataSize" },
+            { 0x246A02, "BuiltInStorageCorrupted" },
+            { 0x246C02, "GptHeaderSignatureVerificationFailed" },
+            { 0x247002, "GptHeaderInvalidPartitionSize" },
+            { 0x249202, "FatFileSystemCorrupted" },
+            { 0x249602, "InvalidFatFormat" },
+            { 0x249802, "InvalidFatFileNumber" },
+            { 0x249A02, "ExFatUnavailable" },
+            { 0x249C02, "InvalidFatFormatBisUser" },
+            { 0x249E02, "InvalidFatFormatBisSystem" },
+            { 0x24A002, "InvalidFatFormatBisSafe" },
+            { 0x24A202, "InvalidFatFormatBisCalibration" },
+            { 0x24A402, "InvalidFatFormatSd" },
+            { 0x24BA02, "HostFileSystemCorrupted" },
+            { 0x24BC02, "HostEntryCorrupted" },
+            { 0x24BE02, "HostFileDataCorrupted" },
+            { 0x24C002, "HostFileCorrupted" },
+            { 0x24C202, "InvalidHostHandle" },
+            { 0x24E202, "DatabaseCorrupted" },
+            { 0x24E402, "InvalidAllocationTableBlock" },
+            { 0x24E602, "InvalidKeyValueListElementIndex" },
+            { 0x24E802, "InvalidAllocationTableChainEntry" },
+            { 0x24EA02, "InvalidAllocationTableOffset" },
+            { 0x24EC02, "InvalidAllocationTableBlockCount" },
+            { 0x24EE02, "InvalidKeyValueListEntryIndex" },
+            { 0x24F002, "InvalidBitmapIndex" },
+            { 0x250A02, "AesXtsFileSystemCorrupted" },
+            { 0x250C02, "AesXtsFileSystemFileHeaderSizeCorruptedOnFileOpen" },
+            { 0x250E02, "AesXtsFileSystemFileHeaderCorruptedOnFileOpen" },
+            { 0x251002, "AesXtsFileSystemFileNoHeaderOnFileOpen" },
+            { 0x251202, "AesXtsFileSystemFileSizeCorruptedOnFileOpen" },
+            { 0x251402, "AesXtsFileSystemFileSizeCorruptedOnFileSetSize" },
+            { 0x251602, "AesXtsFileSystemFileHeaderCorruptedOnRename" },
+            { 0x251802, "AesXtsFileSystemFileHeaderCorruptedOnFileSetSize" },
+            { 0x253202, "SaveDataTransferDataCorrupted" },
+            { 0x253402, "SaveDataTransferTokenMacVerificationFailed" },
+            { 0x253602, "SaveDataTransferTokenSignatureVerificationFailed" },
+            { 0x253802, "SaveDataTransferTokenChallengeVerificationFailed" },
+            { 0x253A02, "SaveDataTransferImportMacVerificationFailed" },
+            { 0x253C02, "SaveDataTransferInitialDataMacVerificationFailed" },
+            { 0x253E02, "SaveDataTransferInitialDataVersionVerificationFailed" },
+            { 0x254602, "SignedSystemPartitionDataCorrupted" },
+            { 0x254802, "SignedSystemPartitionInvalidSize" },
+            { 0x254A02, "SignedSystemPartitionSignatureVerificationFailed" },
+            { 0x254C02, "SignedSystemPartitionHashVerificationFailed" },
+            { 0x254E02, "SignedSystemPartitionPackage2HashVerificationFailed" },
+            { 0x255002, "SignedSystemPartitionInvalidAppendHashCount" },
+            { 0x255A02, "GameCardLogoDataCorrupted" },
+            { 0x256202, "SimulatedDeviceDataCorrupted" },
+            { 0x256C02, "MultiCommitContextCorrupted" },
+            { 0x256E02, "InvalidMultiCommitContextVersion" },
+            { 0x257002, "InvalidMultiCommitContextState" },
+            { 0x258402, "ConcatenationFsInvalidInternalFileCount" },
+            { 0x259602, "ZeroBitmapFileCorrupted" },
+            { 0x259802, "IncompleteBlockInZeroBitmapHashStorageFile" },
+            { 0x271002, "Unexpected" },
+            { 0x271202, "FatFsUnexpected" },
+            { 0x271402, "FatFsUnclassified" },
+            { 0x271602, "FatFsStorageStateMissmatch" },
+            { 0x274002, "FatFsTooManyFilesOpenedS" },
+            { 0x274202, "FatFsTooManyFilesOpenedU" },
+            { 0x274402, "FatFsNotAFile" },
+            { 0x274802, "FatFsLockError" },
+            { 0x274A02, "FatFsInternalError" },
+            { 0x277E02, "FatFsModuleSafeError" },
+            { 0x27EC02, "FatFsUnexpectedSystemError" },
+            { 0x280002, "FatFsFormatUnexpected" },
+            { 0x280202, "FatFsFormatUnsupportedSize" },
+            { 0x280402, "FatFsFormatInvalidBpb" },
+            { 0x280602, "FatFsFormatInvalidParameter" },
+            { 0x280802, "FatFsFormatIllegalSectorsA" },
+            { 0x280A02, "FatFsFormatIllegalSectorsB" },
+            { 0x280C02, "FatFsFormatIllegalSectorsC" },
+            { 0x280E02, "FatFsFormatIllegalSectorsD" },
+            { 0x281602, "FatFsWriteVerifyError" },
+            { 0x296A02, "UnexpectedInMountTableA" },
+            { 0x296C02, "UnexpectedInJournalIntegritySaveDataFileSystemA" },
+            { 0x296E02, "UnexpectedInJournalIntegritySaveDataFileSystemB" },
+            { 0x297002, "UnexpectedInJournalIntegritySaveDataFileSystemC" },
+            { 0x297202, "UnexpectedInLocalFileSystemA" },
+            { 0x297402, "UnexpectedInLocalFileSystemB" },
+            { 0x297602, "UnexpectedInLocalFileSystemC" },
+            { 0x297802, "UnexpectedInLocalFileSystemD" },
+            { 0x297A02, "UnexpectedInLocalFileSystemE" },
+            { 0x297C02, "UnexpectedInLocalFileSystemF" },
+            { 0x297E02, "UnexpectedInPathToolA" },
+            { 0x298002, "UnexpectedInPathOnExecutionDirectoryA" },
+            { 0x298202, "UnexpectedInPathOnExecutionDirectoryB" },
+            { 0x298402, "UnexpectedInPathOnExecutionDirectoryC" },
+            { 0x298602, "UnexpectedInAesCtrStorageA" },
+            { 0x298802, "UnexpectedInAesXtsStorageA" },
+            { 0x298A02, "UnexpectedInSaveDataInternalStorageFileSystemA" },
+            { 0x298C02, "UnexpectedInSaveDataInternalStorageFileSystemB" },
+            { 0x298E02, "UnexpectedInMountUtilityA" },
+            { 0x299002, "UnexpectedInNcaFileSystemServiceImplA" },
+            { 0x299202, "UnexpectedInRamDiskFileSystemA" },
+            { 0x299402, "UnexpectedInBisWiperA" },
+            { 0x299602, "UnexpectedInBisWiperB" },
+            { 0x299802, "UnexpectedInCompressedStorageA" },
+            { 0x299A02, "UnexpectedInCompressedStorageB" },
+            { 0x299C02, "UnexpectedInCompressedStorageC" },
+            { 0x299E02, "UnexpectedInCompressedStorageD" },
+            { 0x29A002, "UnexpectedInPathA" },
+            { 0x2EE002, "PreconditionViolation" },
+            { 0x2EE202, "InvalidArgument" },
+            { 0x2EE402, "InvalidPath" },
+            { 0x2EE602, "TooLongPath" },
+            { 0x2EE802, "InvalidCharacter" },
+            { 0x2EEA02, "InvalidPathFormat" },
+            { 0x2EEC02, "DirectoryUnobtainable" },
+            { 0x2EEE02, "NotNormalized" },
+            { 0x2F1C02, "InvalidPathForOperation" },
+            { 0x2F1E02, "DirectoryUndeletable" },
+            { 0x2F2002, "DirectoryUnrenamable" },
+            { 0x2F2202, "IncompatiblePath" },
+            { 0x2F2402, "RenameToOtherFileSystem" },
+            { 0x2F5A02, "InvalidOffset" },
+            { 0x2F5C02, "InvalidSize" },
+            { 0x2F5E02, "NullptrArgument" },
+            { 0x2F6002, "InvalidAlignment" },
+            { 0x2F6202, "InvalidMountName" },
+            { 0x2F6402, "ExtensionSizeTooLarge" },
+            { 0x2F6602, "ExtensionSizeInvalid" },
+            { 0x2F6802, "InvalidHandle" },
+            { 0x2F6A02, "CacheStorageSizeTooLarge" },
+            { 0x2F6C02, "CacheStorageIndexTooLarge" },
+            { 0x2F6E02, "InvalidCommitNameCount" },
+            { 0x2F7002, "InvalidModeForFileOpen" },
+            { 0x2F7202, "InvalidFileSize" },
+            { 0x2F7402, "InvalidModeForDirectoryOpen" },
+            { 0x2F7602, "InvalidCommitOption" },
+            { 0x2F8002, "InvalidEnumValue" },
+            { 0x2F8202, "InvalidSaveDataState" },
+            { 0x2F8402, "InvalidSaveDataSpaceId" },
+            { 0x2FAA02, "GameCardLogoDataTooLarge" },
+            { 0x2FAC02, "FileDataCacheMemorySizeTooSmall" },
+            { 0x307002, "InvalidOperationForOpenMode" },
+            { 0x307202, "FileExtensionWithoutOpenModeAllowAppend" },
+            { 0x307402, "ReadUnpermitted" },
+            { 0x307602, "WriteUnpermitted" },
+            { 0x313802, "UnsupportedOperation" },
+            { 0x313A02, "UnsupportedCommitTarget" },
+            { 0x313C02, "UnsupportedSetSizeForNotResizableSubStorage" },
+            { 0x313E02, "UnsupportedSetSizeForResizableSubStorage" },
+            { 0x314002, "UnsupportedSetSizeForMemoryStorage" },
+            { 0x314202, "UnsupportedOperateRangeForMemoryStorage" },
+            { 0x314402, "UnsupportedOperateRangeForFileStorage" },
+            { 0x314602, "UnsupportedOperateRangeForFileHandleStorage" },
+            { 0x314802, "UnsupportedOperateRangeForSwitchStorage" },
+            { 0x314A02, "UnsupportedOperateRangeForStorageServiceObjectAdapter" },
+            { 0x314C02, "UnsupportedWriteForAesCtrCounterExtendedStorage" },
+            { 0x314E02, "UnsupportedSetSizeForAesCtrCounterExtendedStorage" },
+            { 0x315002, "UnsupportedOperateRangeForAesCtrCounterExtendedStorage" },
+            { 0x315202, "UnsupportedWriteForAesCtrStorageExternal" },
+            { 0x315402, "UnsupportedSetSizeForAesCtrStorageExternal" },
+            { 0x315602, "UnsupportedSetSizeForAesCtrStorage" },
+            { 0x315802, "UnsupportedSetSizeForHierarchicalIntegrityVerificationStorage" },
+            { 0x315A02, "UnsupportedOperateRangeForHierarchicalIntegrityVerificationStorage" },
+            { 0x315C02, "UnsupportedSetSizeForIntegrityVerificationStorage" },
+            { 0x315E02, "UnsupportedOperateRangeForWritableIntegrityVerificationStorage" },
+            { 0x316002, "UnsupportedOperateRangeForIntegrityVerificationStorage" },
+            { 0x316202, "UnsupportedSetSizeForBlockCacheBufferedStorage" },
+            { 0x316402, "UnsupportedOperateRangeForWritableBlockCacheBufferedStorage" },
+            { 0x316602, "UnsupportedOperateRangeForBlockCacheBufferedStorage" },
+            { 0x316802, "UnsupportedWriteForIndirectStorage" },
+            { 0x316A02, "UnsupportedSetSizeForIndirectStorage" },
+            { 0x316C02, "UnsupportedOperateRangeForIndirectStorage" },
+            { 0x316E02, "UnsupportedWriteForZeroStorage" },
+            { 0x317002, "UnsupportedSetSizeForZeroStorage" },
+            { 0x317202, "UnsupportedSetSizeForHierarchicalSha256Storage" },
+            { 0x317402, "UnsupportedWriteForReadOnlyBlockCacheStorage" },
+            { 0x317602, "UnsupportedSetSizeForReadOnlyBlockCacheStorage" },
+            { 0x317802, "UnsupportedSetSizeForIntegrityRomFsStorage" },
+            { 0x317A02, "UnsupportedSetSizeForDuplexStorage" },
+            { 0x317C02, "UnsupportedOperateRangeForDuplexStorage" },
+            { 0x317E02, "UnsupportedSetSizeForHierarchicalDuplexStorage" },
+            { 0x318002, "UnsupportedGetSizeForRemapStorage" },
+            { 0x318202, "UnsupportedSetSizeForRemapStorage" },
+            { 0x318402, "UnsupportedOperateRangeForRemapStorage" },
+            { 0x318602, "UnsupportedSetSizeForIntegritySaveDataStorage" },
+            { 0x318802, "UnsupportedOperateRangeForIntegritySaveDataStorage" },
+            { 0x318A02, "UnsupportedSetSizeForJournalIntegritySaveDataStorage" },
+            { 0x318C02, "UnsupportedOperateRangeForJournalIntegritySaveDataStorage" },
+            { 0x318E02, "UnsupportedGetSizeForJournalStorage" },
+            { 0x319002, "UnsupportedSetSizeForJournalStorage" },
+            { 0x319202, "UnsupportedOperateRangeForJournalStorage" },
+            { 0x319402, "UnsupportedSetSizeForUnionStorage" },
+            { 0x319602, "UnsupportedSetSizeForAllocationTableStorage" },
+            { 0x319802, "UnsupportedReadForWriteOnlyGameCardStorage" },
+            { 0x319A02, "UnsupportedSetSizeForWriteOnlyGameCardStorage" },
+            { 0x319C02, "UnsupportedWriteForReadOnlyGameCardStorage" },
+            { 0x319E02, "UnsupportedSetSizeForReadOnlyGameCardStorage" },
+            { 0x31A002, "UnsupportedOperateRangeForReadOnlyGameCardStorage" },
+            { 0x31A202, "UnsupportedSetSizeForSdmmcStorage" },
+            { 0x31A402, "UnsupportedOperateRangeForSdmmcStorage" },
+            { 0x31A602, "UnsupportedOperateRangeForFatFile" },
+            { 0x31A802, "UnsupportedOperateRangeForStorageFile" },
+            { 0x31AA02, "UnsupportedSetSizeForInternalStorageConcatenationFile" },
+            { 0x31AC02, "UnsupportedOperateRangeForInternalStorageConcatenationFile" },
+            { 0x31AE02, "UnsupportedQueryEntryForConcatenationFileSystem" },
+            { 0x31B002, "UnsupportedOperateRangeForConcatenationFile" },
+            { 0x31B202, "UnsupportedSetSizeForZeroBitmapFile" },
+            { 0x31B402, "UnsupportedOperateRangeForFileServiceObjectAdapter" },
+            { 0x31B602, "UnsupportedOperateRangeForAesXtsFile" },
+            { 0x31B802, "UnsupportedWriteForRomFsFileSystem" },
+            { 0x31BA02, "UnsupportedCommitProvisionallyForRomFsFileSystem" },
+            { 0x31BC02, "UnsupportedGetTotalSpaceSizeForRomFsFileSystem" },
+            { 0x31BE02, "UnsupportedWriteForRomFsFile" },
+            { 0x31C002, "UnsupportedOperateRangeForRomFsFile" },
+            { 0x31C202, "UnsupportedWriteForReadOnlyFileSystem" },
+            { 0x31C402, "UnsupportedCommitProvisionallyForReadOnlyFileSystem" },
+            { 0x31C602, "UnsupportedGetTotalSpaceSizeForReadOnlyFileSystem" },
+            { 0x31C802, "UnsupportedWriteForReadOnlyFile" },
+            { 0x31CA02, "UnsupportedOperateRangeForReadOnlyFile" },
+            { 0x31CC02, "UnsupportedWriteForPartitionFileSystem" },
+            { 0x31CE02, "UnsupportedCommitProvisionallyForPartitionFileSystem" },
+            { 0x31D002, "UnsupportedWriteForPartitionFile" },
+            { 0x31D202, "UnsupportedOperateRangeForPartitionFile" },
+            { 0x31D402, "UnsupportedOperateRangeForTmFileSystemFile" },
+            { 0x31D602, "UnsupportedWriteForSaveDataInternalStorageFileSystem" },
+            { 0x31DC02, "UnsupportedCommitProvisionallyForApplicationTemporaryFileSystem" },
+            { 0x31DE02, "UnsupportedCommitProvisionallyForSaveDataFileSystem" },
+            { 0x31E002, "UnsupportedCommitProvisionallyForDirectorySaveDataFileSystem" },
+            { 0x31E202, "UnsupportedWriteForZeroBitmapHashStorageFile" },
+            { 0x31E402, "UnsupportedSetSizeForZeroBitmapHashStorageFile" },
+            { 0x31E602, "UnsupportedWriteForCompressedStorage" },
+            { 0x31E802, "UnsupportedOperateRangeForCompressedStorage" },
+            { 0x31F602, "UnsupportedRollbackOnlyModifiedForApplicationTemporaryFileSystem" },
+            { 0x31F802, "UnsupportedRollbackOnlyModifiedForDirectorySaveDataFileSystem" },
+            { 0x31FA02, "UnsupportedOperateRangeForRegionSwitchStorage" },
+            { 0x320002, "PermissionDenied" },
+            { 0x320602, "HostFileSystemOperationDisabled" },
+            { 0x326402, "PortAcceptableCountLimited" },
+            { 0x326802, "NcaExternalKeyInconsistent" },
+            { 0x326C02, "NeedFlush" },
+            { 0x326E02, "FileNotClosed" },
+            { 0x327002, "DirectoryNotClosed" },
+            { 0x327202, "WriteModeFileNotClosed" },
+            { 0x327402, "AllocatorAlreadyRegistered" },
+            { 0x327602, "DefaultAllocatorAlreadyUsed" },
+            { 0x327802, "GameCardLogoDataSizeInvalid" },
+            { 0x327A02, "AllocatorAlignmentViolation" },
+            { 0x327C02, "GlobalFileDataCacheAlreadyEnabled" },
+            { 0x327E02, "MultiCommitHasOverlappingTargets" },
+            { 0x328002, "MultiCommitAlreadyInProgress" },
+            { 0x328202, "UserNotExist" },
+            { 0x328402, "DefaultGlobalFileDataCacheEnabled" },
+            { 0x328602, "SaveDataRootPathUnavailable" },
+            { 0x339002, "NotFound" },
+            { 0x339402, "FileNotFound" },
+            { 0x339602, "DirectoryNotFound" },
+            { 0x339802, "DatabaseKeyNotFound" },
+            { 0x339A02, "ProgramInfoNotFound" },
+            { 0x339C02, "ProgramIndexNotFound" },
+            { 0x345802, "OutOfResource" },
+            { 0x346202, "BufferAllocationFailed" },
+            { 0x346402, "MappingTableFull" },
+            { 0x346602, "AllocationTableFull" },
+            { 0x346A02, "OpenCountLimit" },
+            { 0x346C02, "MultiCommitFileSystemLimit" },
+            { 0x352002, "MappingFailed" },
+            { 0x353602, "MapFull" },
+            { 0x35E802, "BadState" },
+            { 0x35EC02, "NotInitialized" },
+            { 0x35EE02, "BisProxyInvalidated" },
+            { 0x35F002, "NcaDigestInconsistent" },
+            { 0x35F202, "NotMounted" },
+            { 0x35F402, "SaveDataExtending" },
+            { 0x35F602, "SaveDataToExpandIsProvisionallyCommitted" },
+            { 0x36B402, "SaveDataTransferV2KeySeedPackageMacVerificationFailed" },
+            { 0x36B602, "SaveDataTransferV2KeySeedPackageSignatureVerificationFailed" },
+            { 0x36B802, "SaveDataTransferV2KeySeedPackageChallengeVerificationFailed" },
+            { 0x36BA02, "SaveDataTransferV2ImportDataVerificationFailed" },
+            { 0x36BC02, "SaveDataTransferV2InitialDataGcmMacVerificationFailed" },
+            { 0x36C202, "SaveDataTransferV2InitialDataMacVerificationFailed" },
+            { 0x36C402, "SaveDataTransferV2ImportDataDecompressionFailed" },
+            { 0x36C602, "SaveDataTransferV2PortContextMacVerificationFailed" },
+            { 0x36EE02, "SaveDataPorterInvalidated" },
+            { 0x36F002, "SaveDataDivisionExporterChunkExportIncomplete" },
+            { 0x36F202, "SaveDataDivisionImporterChunkImportIncomplete" },
+            { 0x36F402, "SaveDataPorterInitialDataVersionVerificationFailed" },
+            { 0x36F602, "SaveDataChunkDecryptorGcmStreamVersionVerificationFailed" },
+            { 0x36F802, "SaveDataPorterSaveDataModified" },
+            { 0x36FA02, "SaveDataPorterVersionUnsupported" },
+            { 0x36FC02, "SaveDataTransferV2SecondarySaveCorrupted" },
+            { 0x372C02, "SaveDataTransferForSaveDataRepairKeyPackageMacVerificationFailed" },
+            { 0x372E02, "SaveDataTransferForSaveDataRepairKeyPackageSignatureVerificationFailed" },
+            { 0x373002, "SaveDataTransferForSaveDataRepairKeyPackageChallengeVerificationFailed" },
+            { 0x373202, "SaveDataTransferForSaveDataRepairUnsupportedKeyGeneration" },
+            { 0x373402, "SaveDataTransferForSaveDataRepairInitialDataMacVerificationFailed" },
+            { 0x373A02, "SaveDataTransferForSaveDataRepairIncorrectInitialData" },
+            { 0x373C02, "SaveDataTransferForSaveDataRepairInconsistentInitialData" },
+            { 0x373E02, "SaveDataTransferForSaveDataRepairInitialDataIncorrectUserId" },
+            { 0x377802, "RamDiskCorrupted" },
+            { 0x377A02, "RamDiskVerifiedStorageVerificationFailed" },
+            { 0x378E02, "RamDiskSaveDataCoreFileSystemCorrupted" },
+            { 0x379002, "IncorrectRamDiskSaveDataFileSystemMagicCode" },
+            { 0x379202, "InvalidRamDiskSaveDataFileReadOffset" },
+            { 0x379402, "InvalidRamDiskSaveDataCoreDataStorageSize" },
+            { 0x37A202, "RamDiskDatabaseCorrupted" },
+            { 0x37A402, "InvalidRamDiskAllocationTableBlock" },
+            { 0x37A602, "InvalidRamDiskKeyValueListElementIndex" },
+            { 0x37A802, "InvalidRamDiskAllocationTableChainEntry" },
+            { 0x37AA02, "InvalidRamDiskAllocationTableOffset" },
+            { 0x37AC02, "InvalidRamDiskAllocationTableBlockCount" },
+            { 0x37AE02, "InvalidRamDiskKeyValueListEntryIndex" },
+            { 0x37CC02, "SaveDataTransferForRepairInitialDataMacVerificationFailed" },
+            { 0x3DB802, "Unknown" },
+            { 0x3DBA02, "DbmNotFound" },
+            { 0x3DBC02, "DbmKeyNotFound" },
+            { 0x3DBE02, "DbmFileNotFound" },
+            { 0x3DC002, "DbmDirectoryNotFound" },
+            { 0x3DC402, "DbmAlreadyExists" },
+            { 0x3DC602, "DbmKeyFull" },
+            { 0x3DC802, "DbmDirectoryEntryFull" },
+            { 0x3DCA02, "DbmFileEntryFull" },
+            { 0x3DCC02, "DbmFindFinished" },
+            { 0x3DCE02, "DbmFindKeyFinished" },
+            { 0x3DD002, "DbmIterationFinished" },
+            { 0x3DD402, "DbmInvalidOperation" },
+            { 0x3DD602, "DbmInvalidPathFormat" },
+            { 0x3DD802, "DbmDirectoryNameTooLong" },
+            { 0x3DDA02, "DbmFileNameTooLong" },
+            { 0x803, "Busy" },
+            { 0x1003, "OutOfMemory" },
+            { 0x1203, "OutOfResource" },
+            { 0x1803, "OutOfVirtualAddressSpace" },
+            { 0x1A03, "ResourceLimit" },
+            { 0x3E803, "OutOfHandles" },
+            { 0x3EA03, "InvalidHandle" },
+            { 0x3EC03, "InvalidCurrentMemoryState" },
+            { 0x3EE03, "InvalidTransferMemoryState" },
+            { 0x3F003, "InvalidTransferMemorySize" },
+            { 0x3F203, "OutOfTransferMemory" },
+            { 0x3F403, "OutOfAddressSpace" },
+            { 0x3FC03, "SessionClosedForReceive" },
+            { 0x3FE03, "SessionClosedForReply" },
+            { 0x40003, "ReceiveListBroken" },
+            { 0x1204, "InvalidHandle" },
+            { 0xFA204, "InvalidArgument" },
+            { 0xFA604, "InvalidServerHandle" },
+            { 0xFBC04, "InvalidSize" },
+            { 0xFCA04, "Cancelled" },
+            { 0xFCE04, "Completed" },
+            { 0x106E04, "InvalidTask" },
+            { 0x205, "InvalidContentStorageBase" },
+            { 0x405, "PlaceHolderAlreadyExists" },
+            { 0x605, "PlaceHolderNotFound" },
+            { 0x805, "ContentAlreadyExists" },
+            { 0xA05, "ContentNotFound" },
+            { 0xE05, "ContentMetaNotFound" },
+            { 0x1005, "AllocationFailed" },
+            { 0x1805, "UnknownStorage" },
+            { 0xC805, "InvalidContentStorage" },
+            { 0xDC05, "InvalidContentMetaDatabase" },
+            { 0x10405, "InvalidPackageFormat" },
+            { 0x11805, "InvalidContentHash" },
+            { 0x14005, "InvalidInstallTaskState" },
+            { 0x15405, "InvalidPlaceHolderFile" },
+            { 0x16805, "BufferInsufficient" },
+            { 0x17C05, "WriteToReadOnlyContentStorage" },
+            { 0x19005, "NotEnoughInstallSpace" },
+            { 0x1A405, "SystemUpdateNotFoundInPackage" },
+            { 0x1B805, "ContentInfoNotFound" },
+            { 0x1DA05, "DeltaNotFound" },
+            { 0x1E005, "InvalidContentMetaKey" },
+            { 0x1F405, "ContentStorageNotActive" },
+            { 0x1F605, "GameCardContentStorageNotActive" },
+            { 0x1F805, "BuiltInSystemContentStorageNotActive" },
+            { 0x1FA05, "BuiltInUserContentStorageNotActive" },
+            { 0x1FC05, "SdCardContentStorageNotActive" },
+            { 0x20405, "UnknownContentStorageNotActive" },
+            { 0x20805, "ContentMetaDatabaseNotActive" },
+            { 0x20A05, "GameCardContentMetaDatabaseNotActive" },
+            { 0x20C05, "BuiltInSystemContentMetaDatabaseNotActive" },
+            { 0x20E05, "BuiltInUserContentMetaDatabaseNotActive" },
+            { 0x21005, "SdCardContentMetaDatabaseNotActive" },
+            { 0x21805, "UnknownContentMetaDatabaseNotActive" },
+            { 0x23005, "IgnorableInstallTicketFailure" },
+            { 0x24405, "InstallTaskCancelled" },
+            { 0x24605, "CreatePlaceHolderCancelled" },
+            { 0x24805, "WritePlaceHolderCancelled" },
+            { 0x26C05, "ContentStorageBaseNotFound" },
+            { 0x29405, "ListPartiallyNotCommitted" },
+            { 0x2D005, "UnexpectedContentMetaPrepared" },
+            { 0x2F805, "InvalidFirmwareVariation" },
+            { 0x3FEA05, "InvalidArgument" },
+            { 0x3FEC05, "InvalidOffset" },
+            { 0x206, "EndOfQuery" },
+            { 0x406, "InvalidCurrentMemory" },
+            { 0x606, "NotSingleRegion" },
+            { 0x806, "InvalidMemoryState" },
+            { 0xA06, "OutOfMemory" },
+            { 0xC06, "OutOfResource" },
+            { 0xE06, "NotSupported" },
+            { 0x1006, "InvalidHandle" },
+            { 0x7FE06, "InternalError" },
+            { 0x208, "ResolverNotFound" },
+            { 0x408, "ProgramNotFound" },
+            { 0x608, "DataNotFound" },
+            { 0x808, "UnknownResolver" },
+            { 0xA08, "ApplicationNotFound" },
+            { 0xC08, "HtmlDocumentNotFound" },
+            { 0xE08, "AddOnContentNotFound" },
+            { 0x1008, "ControlNotFound" },
+            { 0x1208, "LegalInformationNotFound" },
+            { 0x1408, "DebugProgramNotFound" },
+            { 0xB408, "TooManyRegisteredPaths" },
+            { 0x209, "TooLongArgument" },
+            { 0x409, "TooManyArguments" },
+            { 0x609, "TooLargeMeta" },
+            { 0x809, "InvalidMeta" },
+            { 0xA09, "InvalidNso" },
+            { 0xC09, "InvalidPath" },
+            { 0xE09, "TooManyProcesses" },
+            { 0x1009, "NotPinned" },
+            { 0x1209, "InvalidProgramId" },
+            { 0x1409, "InvalidVersion" },
+            { 0x1609, "InvalidAcidSignature" },
+            { 0x1809, "InvalidNcaSignature" },
+            { 0x6609, "InsufficientAddressSpace" },
+            { 0x6809, "InvalidNro" },
+            { 0x6A09, "InvalidNrr" },
+            { 0x6C09, "InvalidSignature" },
+            { 0x6E09, "InsufficientNroRegistrations" },
+            { 0x7009, "InsufficientNrrRegistrations" },
+            { 0x7209, "NroAlreadyLoaded" },
+            { 0xA209, "InvalidAddress" },
+            { 0xA409, "InvalidSize" },
+            { 0xA809, "NotLoaded" },
+            { 0xAA09, "NotRegistered" },
+            { 0xAC09, "InvalidSession" },
+            { 0xAE09, "InvalidProcess" },
+            { 0xC809, "UnknownCapability" },
+            { 0xCE09, "InvalidCapabilityKernelFlags" },
+            { 0xD009, "InvalidCapabilitySyscallMask" },
+            { 0xD409, "InvalidCapabilityMapRange" },
+            { 0xD609, "InvalidCapabilityMapPage" },
+            { 0xDE09, "InvalidCapabilityInterruptPair" },
+            { 0xE209, "InvalidCapabilityApplicationType" },
+            { 0xE409, "InvalidCapabilityKernelVersion" },
+            { 0xE609, "InvalidCapabilityHandleTable" },
+            { 0xE809, "InvalidCapabilityDebugFlags" },
+            { 0x19009, "InternalError" },
+            { 0x20A, "NotSupported" },
+            { 0x60A, "PreconditionViolation" },
+            { 0x140A, "MemoryAllocationFailed" },
+            { 0x160A, "CmifProxyAllocationFailed" },
+            { 0x1940A, "InvalidCmifHeaderSize" },
+            { 0x1A60A, "InvalidCmifInHeader" },
+            { 0x1A80A, "InvalidCmifOutHeader" },
+            { 0x1BA0A, "UnknownMethodId" },
+            { 0x1CE0A, "InvalidInRawSize" },
+            { 0x1D00A, "InvalidOutRawSize" },
+            { 0x1D60A, "InvalidInObjectCount" },
+            { 0x1D80A, "InvalidOutObjectCount" },
+            { 0x1DE0A, "InvalidInObject" },
+            { 0x20A0A, "TargetObjectNotFound" },
+            { 0x25A0A, "OutOfDomainEntry" },
+            { 0x6400A, "RequestContextChanged" },
+            { 0x6420A, "RequestInvalidated" },
+            { 0x6440A, "RequestInvalidatedByUser" },
+            { 0x6560A, "RequestDeferred" },
+            { 0x6580A, "RequestDeferredByUser" },
+            { 0x20B, "NotSupported" },
+            { 0xC80B, "OutOfResource" },
+            { 0xCC0B, "OutOfSessionMemory" },
+            { 0x1060B, "OutOfSessions" },
+            { 0x11A0B, "InsufficientPointerTransferBuffer" },
+            { 0x1900B, "OutOfDomains" },
+            { 0x2580B, "CommunicationError" },
+            { 0x25A0B, "SessionClosed" },
+            { 0x3240B, "InvalidRequestSize" },
+            { 0x3260B, "UnknownCommandType" },
+            { 0x3480B, "InvalidCmifRequest" },
+            { 0x3D60B, "TargetNotDomain" },
+            { 0x3D80B, "DomainObjectNotFound" },
+            { 0x20C, "Unknown" },
+            { 0x20D, "Unknown" },
+            { 0x40D, "DebuggingDisabled" },
+            { 0x20F, "ProcessNotFound" },
+            { 0x40F, "AlreadyStarted" },
+            { 0x60F, "NotTerminated" },
+            { 0x80F, "DebugHookInUse" },
+            { 0xA0F, "ApplicationRunning" },
+            { 0xC0F, "InvalidSize" },
+            { 0xB410, "Canceled" },
+            { 0xDC10, "OutOfMaxRunningTask" },
+            { 0x21C10, "CardUpdateNotSetup" },
+            { 0x23010, "CardUpdateNotPrepared" },
+            { 0x24410, "CardUpdateAlreadySetup" },
+            { 0x39810, "PrepareCardUpdateAlreadyRequested" },
+            { 0x212, "ConnectionFailure" },
+            { 0x412, "NotFound" },
+            { 0x612, "NotEnoughBuffer" },
+            { 0xCA12, "Cancelled" },
+            { 0x7FE12, "" },
+            { 0xFA212, "" },
+            { 0xFA612, "InvalidTaskId" },
+            { 0xFB612, "InvalidSize" },
+            { 0xFCA12, "TaskCancelled" },
+            { 0xFCC12, "TaskNotCompleted" },
+            { 0xFCE12, "TaskQueueNotAvailable" },
+            { 0x106A12, "" },
+            { 0x106C12, "OutOfRpcTask" },
+            { 0x109612, "InvalidCategory" },
+            { 0x214, "OutOfKeyResource" },
+            { 0x414, "KeyNotFound" },
+            { 0x814, "AllocationFailed" },
+            { 0xA14, "InvalidKeyValue" },
+            { 0xC14, "BufferInsufficient" },
+            { 0x1014, "InvalidFileSystemState" },
+            { 0x1214, "NotCreated" },
+            { 0x215, "OutOfProcesses" },
+            { 0x415, "InvalidClient" },
+            { 0x615, "OutOfSessions" },
+            { 0x815, "AlreadyRegistered" },
+            { 0xA15, "OutOfServices" },
+            { 0xC15, "InvalidServiceName" },
+            { 0xE15, "NotRegistered" },
+            { 0x1015, "NotAllowed" },
+            { 0x1215, "TooLargeAccessControl" },
+            { 0x216, "RoError" },
+            { 0x416, "OutOfAddressSpace" },
+            { 0x616, "AlreadyLoaded" },
+            { 0x816, "InvalidNro" },
+            { 0xC16, "InvalidNrr" },
+            { 0xE16, "TooManyNro" },
+            { 0x1016, "TooManyNrr" },
+            { 0x1216, "NotAuthorized" },
+            { 0x1416, "InvalidNrrKind" },
+            { 0x7FE16, "InternalError" },
+            { 0x80216, "InvalidAddress" },
+            { 0x80416, "InvalidSize" },
+            { 0x80816, "NotLoaded" },
+            { 0x80A16, "NotRegistered" },
+            { 0x80C16, "InvalidSession" },
+            { 0x80E16, "InvalidProcess" },
+            { 0x218, "NoDevice" },
+            { 0x418, "NotActivated" },
+            { 0x618, "DeviceRemoved" },
+            { 0x818, "NotAwakened" },
+            { 0x4018, "CommunicationError" },
+            { 0x4218, "CommunicationNotAttained" },
+            { 0x4418, "ResponseIndexError" },
+            { 0x4618, "ResponseEndBitError" },
+            { 0x4818, "ResponseCrcError" },
+            { 0x4A18, "ResponseTimeoutError" },
+            { 0x4C18, "DataEndBitError" },
+            { 0x4E18, "DataCrcError" },
+            { 0x5018, "DataTimeoutError" },
+            { 0x5218, "AutoCommandResponseIndexError" },
+            { 0x5418, "AutoCommandResponseEndBitError" },
+            { 0x5618, "AutoCommandResponseCrcError" },
+            { 0x5818, "AutoCommandResponseTimeoutError" },
+            { 0x5A18, "CommandCompleteSoftwareTimeout" },
+            { 0x5C18, "TransferCompleteSoftwareTimeout" },
+            { 0x6018, "DeviceStatusHasError" },
+            { 0x6218, "DeviceStatusAddressOutOfRange" },
+            { 0x6418, "DeviceStatusAddressMisaligned" },
+            { 0x6618, "DeviceStatusBlockLenError" },
+            { 0x6818, "DeviceStatusEraseSeqError" },
+            { 0x6A18, "DeviceStatusEraseParam" },
+            { 0x6C18, "DeviceStatusWpViolation" },
+            { 0x6E18, "DeviceStatusLockUnlockFailed" },
+            { 0x7018, "DeviceStatusComCrcError" },
+            { 0x7218, "DeviceStatusIllegalCommand" },
+            { 0x7418, "DeviceStatusDeviceEccFailed" },
+            { 0x7618, "DeviceStatusCcError" },
+            { 0x7818, "DeviceStatusError" },
+            { 0x7A18, "DeviceStatusCidCsdOverwrite" },
+            { 0x7C18, "DeviceStatusWpEraseSkip" },
+            { 0x7E18, "DeviceStatusEraseReset" },
+            { 0x8018, "DeviceStatusSwitchError" },
+            { 0x9018, "UnexpectedDeviceState" },
+            { 0x9218, "UnexpectedDeviceCsdValue" },
+            { 0x9418, "AbortTransactionSoftwareTimeout" },
+            { 0x9618, "CommandInhibitCmdSoftwareTimeout" },
+            { 0x9818, "CommandInhibitDatSoftwareTimeout" },
+            { 0x9A18, "BusySoftwareTimeout" },
+            { 0x9C18, "IssueTuningCommandSoftwareTimeout" },
+            { 0x9E18, "TuningFailed" },
+            { 0xA018, "MmcInitializationSoftwareTimeout" },
+            { 0xA218, "MmcNotSupportExtendedCsd" },
+            { 0xA418, "UnexpectedMmcExtendedCsdValue" },
+            { 0xA618, "MmcEraseSoftwareTimeout" },
+            { 0xA818, "SdCardValidationError" },
+            { 0xAA18, "SdCardInitializationSoftwareTimeout" },
+            { 0xAC18, "SdCardGetValidRcaSoftwareTimeout" },
+            { 0xAE18, "UnexpectedSdCardAcmdDisabled" },
+            { 0xB018, "SdCardNotSupportSwitchFunctionStatus" },
+            { 0xB218, "UnexpectedSdCardSwitchFunctionStatus" },
+            { 0xB418, "SdCardNotSupportAccessMode" },
+            { 0xB618, "SdCardNot4BitBusWidthAtUhsIMode" },
+            { 0xB818, "SdCardNotSupportSdr104AndSdr50" },
+            { 0xBA18, "SdCardCannotSwitchAccessMode" },
+            { 0xBC18, "SdCardFailedSwitchAccessMode" },
+            { 0xBE18, "SdCardUnacceptableCurrentConsumption" },
+            { 0xC018, "SdCardNotReadyToVoltageSwitch" },
+            { 0xC218, "SdCardNotCompleteVoltageSwitch" },
+            { 0x10018, "HostControllerUnexpected" },
+            { 0x10218, "InternalClockStableSoftwareTimeout" },
+            { 0x10418, "SdHostStandardUnknownAutoCmdError" },
+            { 0x10618, "SdHostStandardUnknownError" },
+            { 0x10818, "SdmmcDllCalibrationSoftwareTimeout" },
+            { 0x10A18, "SdmmcDllApplicationSoftwareTimeout" },
+            { 0x10C18, "SdHostStandardFailSwitchTo18V" },
+            { 0x10E18, "DriveStrengthCalibrationNotCompleted" },
+            { 0x11018, "DriveStrengthCalibrationSoftwareTimeout" },
+            { 0x11218, "SdmmcCompShortToGnd" },
+            { 0x11418, "SdmmcCompOpen" },
+            { 0x14018, "InternalError" },
+            { 0x14218, "NoWaitedInterrupt" },
+            { 0x14418, "WaitInterruptSoftwareTimeout" },
+            { 0x18018, "AbortCommandIssued" },
+            { 0x19018, "NotSupported" },
+            { 0x19218, "NotImplemented" },
+            { 0x1A, "SecureMonitorError" },
+            { 0x21A, "SecureMonitorNotImplemented" },
+            { 0x41A, "SecureMonitorInvalidArgument" },
+            { 0x61A, "SecureMonitorBusy" },
+            { 0x81A, "SecureMonitorNoAsyncOperation" },
+            { 0xA1A, "SecureMonitorInvalidAsyncOperation" },
+            { 0xC1A, "SecureMonitorNotPermitted" },
+            { 0xE1A, "SecureMonitorNotInitialized" },
+            { 0xC81A, "InvalidSize" },
+            { 0xCA1A, "UnknownSecureMonitorError" },
+            { 0xCC1A, "DecryptionFailed" },
+            { 0xD01A, "OutOfKeySlots" },
+            { 0xD21A, "InvalidKeySlot" },
+            { 0xD41A, "BootReasonAlreadySet" },
+            { 0xD61A, "BootReasonNotSet" },
+            { 0xD81A, "InvalidArgument" },
+            { 0x21B, "InsufficientProvidedMemory" },
+            { 0x21D, "ConnectionFailure" },
+            { 0x61D, "UnknownDriverType" },
+            { 0xA1D, "NonBlockingReceiveFailed" },
+            { 0x101D, "ChannelWaitCancelled" },
+            { 0x121D, "ChannelAlreadyExist" },
+            { 0x141D, "ChannelNotExist" },
+            { 0x12E1D, "OutOfChannel" },
+            { 0x1301D, "OutOfTask" },
+            { 0x1901D, "InvalidChannelState" },
+            { 0x1921D, "InvalidChannelStateDisconnected" },
+            { 0x7D01D, "InternalError" },
+            { 0x7D21D, "Overflow" },
+            { 0x7D41D, "OutOfMemory" },
+            { 0x7D61D, "InvalidArgument" },
+            { 0x7D81D, "ProtocolError" },
+            { 0x7DA1D, "Cancelled" },
+            { 0x8981D, "MuxError" },
+            { 0x89A1D, "ChannelBufferOverflow" },
+            { 0x89C1D, "ChannelBufferHasNotEnoughData" },
+            { 0x89E1D, "ChannelVersionNotMatched" },
+            { 0x8A01D, "ChannelStateTransitionError" },
+            { 0x8A41D, "ChannelReceiveBufferEmpty" },
+            { 0x8A61D, "ChannelSequenceIdNotMatched" },
+            { 0x8A81D, "ChannelCannotDiscard" },
+            { 0x9601D, "DriverError" },
+            { 0x9621D, "DriverOpened" },
+            { 0xA281D, "SocketDriverError" },
+            { 0xA2A1D, "SocketSocketExemptError" },
+            { 0xA2C1D, "SocketBindError" },
+            { 0xA301D, "SocketListenError" },
+            { 0xA321D, "SocketAcceptError" },
+            { 0xA341D, "SocketReceiveError" },
+            { 0xA361D, "SocketSendError" },
+            { 0xA381D, "SocketReceiveFromError" },
+            { 0xA3A1D, "SocketSendToError" },
+            { 0xA3C1D, "SocketSetSockOptError" },
+            { 0xA3E1D, "SocketGetSockNameError" },
+            { 0xAF01D, "UsbDriverError" },
+            { 0xAF21D, "UsbDriverUnknownError" },
+            { 0xAF41D, "UsbDriverBusyError" },
+            { 0xAF61D, "UsbDriverReceiveError" },
+            { 0xAF81D, "UsbDriverSendError" },
+            { 0xFA01D, "HtcctrlError" },
+            { 0xFA21D, "HtcctrlStateTransitionNotAllowed" },
+            { 0xFA41D, "HtcctrlReceiveUnexpectedPacket" },
+            { 0x21E, "OutOfResource" },
+            { 0x41E, "NotSupported" },
+            { 0x61E, "InvalidArgument" },
+            { 0x81E, "PermissionDenied" },
+            { 0xA1E, "AccessModeDenied" },
+            { 0xC1E, "DeviceCodeNotFound" },
+            { 0x61F, "InvalidArgument" },
+            { 0xC81F, "ConnectionFailure" },
+            { 0xCA1F, "HtclowChannelClosed" },
+            { 0xDC1F, "UnexpectedResponse" },
+            { 0xDE1F, "UnexpectedResponseProtocolId" },
+            { 0xE01F, "UnexpectedResponseProtocolVersion" },
+            { 0xE21F, "UnexpectedResponsePacketCategory" },
+            { 0xE41F, "UnexpectedResponsePacketType" },
+            { 0xE61F, "UnexpectedResponseBodySize" },
+            { 0xE81F, "UnexpectedResponseBody" },
+            { 0x1901F, "InternalError" },
+            { 0x1921F, "InvalidSize" },
+            { 0x1A61F, "UnknownError" },
+            { 0x1A81F, "UnsupportedProtocolVersion" },
+            { 0x1AA1F, "InvalidRequest" },
+            { 0x1AC1F, "InvalidHandle" },
+            { 0x1AE1F, "OutOfHandle" },
+            { 0x265, "NoAck" },
+            { 0x465, "BusBusy" },
+            { 0x665, "CommandListFull" },
+            { 0xA65, "UnknownDevice" },
+            { 0x1FA65, "Timeout" },
+            { 0x266, "AlreadyBound" },
+            { 0x466, "AlreadyOpen" },
+            { 0x666, "DeviceNotFound" },
+            { 0x866, "InvalidArgument" },
+            { 0xC66, "NotOpen" },
+            { 0x1669, "SettingsItemNotFound" },
+            { 0xC869, "InternalError" },
+            { 0xCA69, "SettingsItemKeyAllocationFailed" },
+            { 0xCC69, "SettingsItemValueAllocationFailed" },
+            { 0x19069, "InvalidArgument" },
+            { 0x19269, "SettingsNameNull" },
+            { 0x19469, "SettingsItemKeyNull" },
+            { 0x19669, "SettingsItemValueNull" },
+            { 0x19869, "SettingsItemKeyBufferNull" },
+            { 0x19A69, "SettingsItemValueBufferNull" },
+            { 0x1BA69, "SettingsNameEmpty" },
+            { 0x1BC69, "SettingsItemKeyEmpty" },
+            { 0x1E269, "SettingsNameTooLong" },
+            { 0x1E469, "SettingsItemKeyTooLong" },
+            { 0x20A69, "SettingsNameInvalidFormat" },
+            { 0x20C69, "SettingsItemKeyInvalidFormat" },
+            { 0x20E69, "SettingsItemValueInvalidFormat" },
+            { 0x48869, "CalibrationDataError" },
+            { 0x48A69, "CalibrationDataFileSystemCorrupted" },
+            { 0x48C69, "CalibrationDataCrcError" },
+            { 0x48E69, "CalibrationDataShaError" },
+            { 0x272, "OperationFailed" },
+            { 0xC72, "NotSupported" },
+            { 0xE72, "NotFound" },
+            { 0x74, "NotInitialized" },
+            { 0x274, "NoCapability" },
+            { 0xCC74, "OffsetInvalid" },
+            { 0xCE74, "UninitializedClock" },
+            { 0x19074, "NotComparable" },
+            { 0x19274, "Overflowed" },
+            { 0x64274, "OutOfMemory" },
+            { 0x70874, "InvalidArgument" },
+            { 0x70A74, "InvalidPointer" },
+            { 0x70C74, "OutOfRange" },
+            { 0x70E74, "InvalidTimeZoneBinary" },
+            { 0x7BA74, "NotFound" },
+            { 0x7BC74, "NotImplemented" },
+            { 0x27A, "InvalidArgument" },
+            { 0x47A, "NotFound" },
+            { 0x67A, "TargetLocked" },
+            { 0x87A, "TargetAlreadyMounted" },
+            { 0xA7A, "TargetNotMounted" },
+            { 0xC7A, "AlreadyOpen" },
+            { 0xE7A, "NotOpen" },
+            { 0x107A, "InternetRequestDenied" },
+            { 0x127A, "ServiceOpenLimitReached" },
+            { 0x147A, "SaveDataNotFound" },
+            { 0x3E7A, "NetworkServiceAccountNotAvailable" },
+            { 0xA07A, "PassphrasePathNotFound" },
+            { 0xA27A, "DataVerificationFailed" },
+            { 0xB47A, "PermissionDenied" },
+            { 0xB67A, "AllocationFailed" },
+            { 0xC47A, "InvalidOperation" },
+            { 0x1987A, "InvalidDeliveryCacheStorageFile" },
+            { 0x19A7A, "StorageOpenLimitReached" },
+            { 0x7B, "SslService" },
+            { 0x7C, "Cancelled" },
+            { 0x27C, "CancelledByUser" },
+            { 0xC87C, "UserNotExist" },
+            { 0x1907C, "NetworkServiceAccountUnavailable" },
+            { 0x35C7C, "TokenCacheUnavailable" },
+            { 0x17707C, "NetworkCommunicationError" },
+            { 0x2085, "IllegalRequest" },
+            { 0x8C89, "HttpConnectionCanceled" },
+            { 0x48A, "AlreadyInitialized" },
+            { 0x68A, "NotInitialized" },
+            { 0x8C, "NotInitialized" },
+            { 0x28C, "AlreadyInitialized" },
+            { 0xC88C, "InvalidParameter" },
+            { 0xCE8C, "AlignmentError" },
+            { 0x1928C, "OperationDenied" },
+            { 0x1948C, "MemAllocFailure" },
+            { 0x19C8C, "ResourceBusy" },
+            { 0x19E8C, "InternalStateError" },
+            { 0x3228C, "TransactionError" },
+            { 0x3328C, "Interrupted" },
+            { 0x293, "NotInitialized" },
+            { 0x493, "AlreadyInitialized" },
+            { 0x693, "OutOfArraySpace" },
+            { 0x893, "OutOfFieldSpace" },
+            { 0xA93, "OutOfMemory" },
+            { 0xC93, "NotSupported" },
+            { 0xE93, "InvalidArgument" },
+            { 0x1093, "NotFound" },
+            { 0x1293, "FieldCategoryMismatch" },
+            { 0x1493, "FieldTypeMismatch" },
+            { 0x1693, "AlreadyExists" },
+            { 0x1893, "CorruptJournal" },
+            { 0x1A93, "CategoryNotFound" },
+            { 0x1C93, "RequiredContextMissing" },
+            { 0x1E93, "RequiredFieldMissing" },
+            { 0x2093, "FormatterError" },
+            { 0x2293, "InvalidPowerState" },
+            { 0x2493, "ArrayFieldTooLarge" },
+            { 0x2693, "AlreadyOwned" },
+            { 0x49E, "BootImagePackageNotFound" },
+            { 0x69E, "InvalidBootImagePackage" },
+            { 0x89E, "TooSmallWorkBuffer" },
+            { 0xA9E, "NotAlignedWorkBuffer" },
+            { 0xC9E, "NeedsRepairBootImages" },
+            { 0x2A2, "ApplicationAborted" },
+            { 0x4A2, "SystemModuleAborted" },
+            { 0x2A3, "AllocationFailed" },
+            { 0x4A3, "NullGraphicsBuffer" },
+            { 0x6A3, "AlreadyThrown" },
+            { 0x8A3, "TooManyEvents" },
+            { 0xAA3, "InRepairWithoutVolHeld" },
+            { 0xCA3, "InRepairWithoutTimeReviserCartridge" },
+            { 0xA8, "UndefinedInstruction" },
+            { 0x2A8, "InstructionAbort" },
+            { 0x4A8, "DataAbort" },
+            { 0x6A8, "AlignmentFault" },
+            { 0x8A8, "DebuggerAttached" },
+            { 0xAA8, "BreakPoint" },
+            { 0xCA8, "UserBreak" },
+            { 0xEA8, "DebuggerBreak" },
+            { 0x10A8, "UndefinedSystemCall" },
+            { 0x12A8, "MemorySystemError" },
+            { 0xC6A8, "IncompleteReport" },
+            { 0x2B7, "CannotDebug" },
+            { 0x4B7, "AlreadyAttached" },
+            { 0x6B7, "Cancelled" },
+            { 0x4BD, "InvalidArgument" },
+            { 0x2C6, "NotSupported" },
+            { 0x4C6, "InvalidArgument" },
+            { 0x6C6, "NotAvailable" },
+            { 0xCAC6, "CalibrationDataCrcError" },
+            { 0x118CA, "Invalid" },
+            { 0x4B2CA, "DualConnected" },
+            { 0x4B4CA, "SameJoyTypeConnected" },
+            { 0x4B6CA, "ColorNotAvailable" },
+            { 0x4B8CA, "ControllerNotConnected" },
+            { 0x183ACA, "Canceled" },
+            { 0x183CCA, "NotSupportedNpadStyle" },
+            { 0x1900CA, "ControllerFirmwareUpdateError" },
+            { 0x1902CA, "ControllerFirmwareUpdateFailed" },
+            { 0x4CC, "UnknownCommand" },
+            { 0x8CC, "OutOfResource" },
+            { 0xECC, "NoSocket" },
+            { 0xDCCD, "IrsensorUnavailable" },
+            { 0xDECD, "IrsensorUnsupported" },
+            { 0xF0CD, "IrsensorNotReady" },
+            { 0xF4CD, "IrsensorDeviceError" },
+            { 0x4CE, "AlbumError" },
+            { 0x6CE, "AlbumWorkMemoryError" },
+            { 0xECE, "AlbumAlreadyOpened" },
+            { 0x10CE, "AlbumOutOfRange" },
+            { 0x14CE, "AlbumInvalidFileId" },
+            { 0x16CE, "AlbumInvalidApplicationId" },
+            { 0x18CE, "AlbumInvalidTimestamp" },
+            { 0x1ACE, "AlbumInvalidStorage" },
+            { 0x1CCE, "AlbumInvalidFileContents" },
+            { 0x2ACE, "AlbumIsNotMounted" },
+            { 0x2CCE, "AlbumIsFull" },
+            { 0x2ECE, "AlbumFileNotFound" },
+            { 0x30CE, "AlbumInvalidFileData" },
+            { 0x32CE, "AlbumFileCountLimit" },
+            { 0x34CE, "AlbumFileNoThumbnail" },
+            { 0x3CCE, "AlbumReadBufferShortage" },
+            { 0xB4CE, "AlbumFileSystemError" },
+            { 0xBCCE, "AlbumAccessCorrupted" },
+            { 0xC0CE, "AlbumDestinationAccessCorrupted" },
+            { 0x640CE, "ControlError" },
+            { 0x668CE, "ControlResourceLimit" },
+            { 0x66CCE, "ControlNotOpened" },
+            { 0x7FECE, "NotSupported" },
+            { 0x800CE, "InternalError" },
+            { 0x974CE, "InternalJpegEncoderError" },
+            { 0x978CE, "InternalJpegWorkMemoryShortage" },
+            { 0xA28CE, "InternalFileDataVerificationError" },
+            { 0xA2ACE, "InternalFileDataVerificationEmptyFileData" },
+            { 0xA2CCE, "InternalFileDataVerificationExifExtractionFailed" },
+            { 0xA2ECE, "InternalFileDataVerificationExifAnalyzationFailed" },
+            { 0xA30CE, "InternalFileDataVerificationDateTimeExtractionFailed" },
+            { 0xA32CE, "InternalFileDataVerificationInvalidDateTimeLength" },
+            { 0xA34CE, "InternalFileDataVerificationInconsistentDateTime" },
+            { 0xA36CE, "InternalFileDataVerificationMakerNoteExtractionFailed" },
+            { 0xA38CE, "InternalFileDataVerificationInconsistentApplicationId" },
+            { 0xA3ACE, "InternalFileDataVerificationInconsistentSignature" },
+            { 0xA3CCE, "InternalFileDataVerificationUnsupportedOrientation" },
+            { 0xA3ECE, "InternalFileDataVerificationInvalidDataDimension" },
+            { 0xA40CE, "InternalFileDataVerificationInconsistentOrientation" },
+            { 0xAF0CE, "InternalAlbumLimitationError" },
+            { 0xAF2CE, "InternalAlbumLimitationFileCountLimit" },
+            { 0xBB8CE, "InternalSignatureError" },
+            { 0xBBACE, "InternalSignatureExifExtractionFailed" },
+            { 0xBBCCE, "InternalSignatureMakerNoteExtractionFailed" },
+            { 0xD48CE, "InternalAlbumSessionError" },
+            { 0xD4ACE, "InternalAlbumLimitationSessionCountLimit" },
+            { 0xED8CE, "InternalAlbumTemporaryFileError" },
+            { 0xEDACE, "InternalAlbumTemporaryFileCountLimit" },
+            { 0xEDCCE, "InternalAlbumTemporaryFileCreateError" },
+            { 0xEDECE, "InternalAlbumTemporaryFileCreateRetryCountLimit" },
+            { 0xEE0CE, "InternalAlbumTemporaryFileOpenError" },
+            { 0xEE2CE, "InternalAlbumTemporaryFileGetFileSizeError" },
+            { 0xEE4CE, "InternalAlbumTemporaryFileSetFileSizeError" },
+            { 0xEE6CE, "InternalAlbumTemporaryFileReadFileError" },
+            { 0xEE8CE, "InternalAlbumTemporaryFileWriteFileError" },
+            { 0x2E4, "NotImplemented" },
+            { 0x4E4, "NotAvailable" },
+            { 0x6E4, "ApplicationNotRunning" },
+            { 0x8E4, "BufferNotEnough" },
+            { 0xAE4, "ApplicationContentNotFound" },
+            { 0xCE4, "ContentMetaNotFound" },
+            { 0xEE4, "OutOfMemory" },
+            { 0x3AC, "InvalidArgument" },
+            { 0x5AC, "NullArgument" },
+            { 0x7AC, "ArgumentOutOfRange" },
+            { 0x9AC, "BufferTooSmall" },
+            { 0x67AC, "ServiceNotInitialized" },
+            { 0xCBAC, "NotImplemented" },
+            { 0x7D1AC, "InvalidData" },
+            { 0x7D3AC, "InvalidInitialProcessData" },
+            { 0x7D5AC, "InvalidKip" },
+            { 0x7D7AC, "InvalidKipFileSize" },
+            { 0x7D9AC, "InvalidKipMagic" },
+            { 0x7DBAC, "InvalidKipSegmentSize" },
+            { 0x7DDAC, "KipSegmentDecompressionFailed" },
+            { 0x7E5AC, "InvalidIni" },
+            { 0x7E7AC, "InvalidIniFileSize" },
+            { 0x7E9AC, "InvalidIniMagic" },
+            { 0x7EBAC, "InvalidIniProcessCount" },
+            { 0x7F9AC, "InvalidPackage2" },
+            { 0x7FBAC, "InvalidPackage2HeaderSignature" },
+            { 0x7FDAC, "InvalidPackage2MetaSizeA" },
+            { 0x7FFAC, "InvalidPackage2MetaSizeB" },
+            { 0x801AC, "InvalidPackage2MetaKeyGeneration" },
+            { 0x803AC, "InvalidPackage2MetaMagic" },
+            { 0x805AC, "InvalidPackage2MetaEntryPointAlignment" },
+            { 0x807AC, "InvalidPackage2MetaPayloadAlignment" },
+            { 0x809AC, "InvalidPackage2MetaPayloadSizeAlignment" },
+            { 0x80BAC, "InvalidPackage2MetaTotalSize" },
+            { 0x80DAC, "InvalidPackage2MetaPayloadSize" },
+            { 0x80FAC, "InvalidPackage2MetaPayloadsOverlap" },
+            { 0x811AC, "InvalidPackage2MetaEntryPointNotFound" },
+            { 0x813AC, "InvalidPackage2PayloadCorrupted" },
+            { 0x821AC, "InvalidPackage1" },
+            { 0x823AC, "InvalidPackage1SectionSize" },
+            { 0x825AC, "InvalidPackage1MarikoBodySize" },
+            { 0x827AC, "InvalidPackage1Pk11Size" }
+        };
+
+        public static bool TryGet(int errorCode, out string name)
+        {
+            return _names.TryGetValue(errorCode, out name);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj b/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj
new file mode 100644
index 0000000000..d04c5a9b6d
--- /dev/null
+++ b/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
+  </ItemGroup>
+
+</Project>
diff --git a/Ryujinx.Horizon.Common/ThreadTerminatedException.cs b/Ryujinx.Horizon.Common/ThreadTerminatedException.cs
new file mode 100644
index 0000000000..c86cb05fab
--- /dev/null
+++ b/Ryujinx.Horizon.Common/ThreadTerminatedException.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Ryujinx.Horizon.Common
+{
+    public class ThreadTerminatedException : Exception
+    {
+        public ThreadTerminatedException() : base("The thread has been terminated.")
+        {
+        }
+
+        public ThreadTerminatedException(string message) : base(message)
+        {
+        }
+
+        public ThreadTerminatedException(string message, Exception innerException) : base(message, innerException)
+        {
+        }
+    }
+}
diff --git a/Ryujinx.Horizon.Generators/CodeGenerator.cs b/Ryujinx.Horizon.Generators/CodeGenerator.cs
index 80a33c66cf..3a479eb74c 100644
--- a/Ryujinx.Horizon.Generators/CodeGenerator.cs
+++ b/Ryujinx.Horizon.Generators/CodeGenerator.cs
@@ -24,10 +24,10 @@ namespace Ryujinx.Horizon.Generators
             IncreaseIndentation();
         }
 
-        public void LeaveScope()
+        public void LeaveScope(string suffix = "")
         {
             DecreaseIndentation();
-            AppendLine("}");
+            AppendLine($"}}{suffix}");
         }
 
         public void IncreaseIndentation()
diff --git a/Ryujinx.Horizon.Generators/Hipc/CommandArgType.cs b/Ryujinx.Horizon.Generators/Hipc/CommandArgType.cs
new file mode 100644
index 0000000000..b859f1f372
--- /dev/null
+++ b/Ryujinx.Horizon.Generators/Hipc/CommandArgType.cs
@@ -0,0 +1,18 @@
+namespace Ryujinx.Horizon.Generators.Hipc
+{
+    enum CommandArgType : byte
+    {
+        Invalid,
+
+        Buffer,
+        InArgument,
+        InCopyHandle,
+        InMoveHandle,
+        InObject,
+        OutArgument,
+        OutCopyHandle,
+        OutMoveHandle,
+        OutObject,
+        ProcessId
+    }
+}
diff --git a/Ryujinx.Horizon.Generators/Hipc/CommandInterface.cs b/Ryujinx.Horizon.Generators/Hipc/CommandInterface.cs
new file mode 100644
index 0000000000..2ee192820e
--- /dev/null
+++ b/Ryujinx.Horizon.Generators/Hipc/CommandInterface.cs
@@ -0,0 +1,17 @@
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Generators.Hipc
+{
+    class CommandInterface
+    {
+        public ClassDeclarationSyntax ClassDeclarationSyntax { get; }
+        public List<MethodDeclarationSyntax> CommandImplementations { get; }
+
+        public CommandInterface(ClassDeclarationSyntax classDeclarationSyntax)
+        {
+            ClassDeclarationSyntax = classDeclarationSyntax;
+            CommandImplementations = new List<MethodDeclarationSyntax>();
+        }
+    }
+}
diff --git a/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs b/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs
new file mode 100644
index 0000000000..a66d57a3b1
--- /dev/null
+++ b/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs
@@ -0,0 +1,749 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Ryujinx.Horizon.Generators.Hipc
+{
+    [Generator]
+    class HipcGenerator : ISourceGenerator
+    {
+        private const string ArgVariablePrefix = "arg";
+        private const string ResultVariableName = "result";
+        private const string IsBufferMapAliasVariableName = "isBufferMapAlias";
+        private const string InObjectsVariableName = "inObjects";
+        private const string OutObjectsVariableName = "outObjects";
+        private const string ResponseVariableName = "response";
+        private const string OutRawDataVariableName = "outRawData";
+
+        private const string TypeSystemReadOnlySpan = "System.ReadOnlySpan";
+        private const string TypeSystemSpan = "System.Span";
+        private const string TypeStructLayoutAttribute = "System.Runtime.InteropServices.StructLayoutAttribute";
+
+        public const string CommandAttributeName = "CmifCommandAttribute";
+
+        private const string TypeResult = "Ryujinx.Horizon.Common.Result";
+        private const string TypeBufferAttribute = "Ryujinx.Horizon.Sdk.Sf.BufferAttribute";
+        private const string TypeCopyHandleAttribute = "Ryujinx.Horizon.Sdk.Sf.CopyHandleAttribute";
+        private const string TypeMoveHandleAttribute = "Ryujinx.Horizon.Sdk.Sf.MoveHandleAttribute";
+        private const string TypeClientProcessIdAttribute = "Ryujinx.Horizon.Sdk.Sf.ClientProcessIdAttribute";
+        private const string TypeCommandAttribute = "Ryujinx.Horizon.Sdk.Sf." + CommandAttributeName;
+        private const string TypeIServiceObject = "Ryujinx.Horizon.Sdk.Sf.IServiceObject";
+
+        private enum Modifier
+        {
+            None,
+            Ref,
+            Out,
+            In
+        }
+
+        private struct OutParameter
+        {
+            public readonly string Name;
+            public readonly string TypeName;
+            public readonly int Index;
+            public readonly CommandArgType Type;
+
+            public OutParameter(string name, string typeName, int index, CommandArgType type)
+            {
+                Name = name;
+                TypeName = typeName;
+                Index = index;
+                Type = type;
+            }
+        }
+
+        public void Execute(GeneratorExecutionContext context)
+        {
+            HipcSyntaxReceiver syntaxReceiver = (HipcSyntaxReceiver)context.SyntaxReceiver;
+
+            foreach (var commandInterface in syntaxReceiver.CommandInterfaces)
+            {
+                if (!NeedsIServiceObjectImplementation(context.Compilation, commandInterface.ClassDeclarationSyntax))
+                {
+                    continue;
+                }
+
+                CodeGenerator generator = new CodeGenerator();
+                string className = commandInterface.ClassDeclarationSyntax.Identifier.ToString();
+
+                generator.AppendLine("using Ryujinx.Horizon.Common;");
+                generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf;");
+                generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf.Cmif;");
+                generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf.Hipc;");
+                generator.AppendLine("using System;");
+                generator.AppendLine("using System.Collections.Generic;");
+                generator.AppendLine("using System.Runtime.CompilerServices;");
+                generator.AppendLine("using System.Runtime.InteropServices;");
+                generator.AppendLine();
+                generator.EnterScope($"namespace {GetNamespaceName(commandInterface.ClassDeclarationSyntax)}");
+                generator.EnterScope($"partial class {className}");
+
+                GenerateMethodTable(generator, context.Compilation, commandInterface);
+
+                foreach (var method in commandInterface.CommandImplementations)
+                {
+                    generator.AppendLine();
+
+                    GenerateMethod(generator, context.Compilation, method);
+                }
+
+                generator.LeaveScope();
+                generator.LeaveScope();
+
+                context.AddSource($"{className}.g.cs", generator.ToString());
+            }
+        }
+
+        private static string GetNamespaceName(SyntaxNode syntaxNode)
+        {
+            while (syntaxNode != null && !(syntaxNode is NamespaceDeclarationSyntax))
+            {
+                syntaxNode = syntaxNode.Parent;
+            }
+
+            if (syntaxNode == null)
+            {
+                return string.Empty;
+            }
+
+            return ((NamespaceDeclarationSyntax)syntaxNode).Name.ToString();
+        }
+
+        private static void GenerateMethodTable(CodeGenerator generator, Compilation compilation, CommandInterface commandInterface)
+        {
+            generator.EnterScope($"public IReadOnlyDictionary<int, CommandHandler> GetCommandHandlers()");
+            generator.EnterScope($"return new Dictionary<int, CommandHandler>()");
+
+            foreach (var method in commandInterface.CommandImplementations)
+            {
+                foreach (var commandId in GetAttributeAguments(compilation, method, TypeCommandAttribute, 0))
+                {
+                    string[] args = new string[method.ParameterList.Parameters.Count];
+
+                    int index = 0;
+
+                    foreach (var parameter in method.ParameterList.Parameters)
+                    {
+                        string canonicalTypeName = GetCanonicalTypeNameWithGenericArguments(compilation, parameter.Type);
+                        CommandArgType argType = GetCommandArgType(compilation, parameter);
+
+                        string arg;
+
+                        if (argType == CommandArgType.Buffer)
+                        {
+                            string bufferFlags = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 0);
+                            string bufferFixedSize = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 1);
+
+                            if (bufferFixedSize != null)
+                            {
+                                arg = $"new CommandArg({bufferFlags}, {bufferFixedSize})";
+                            }
+                            else
+                            {
+                                arg = $"new CommandArg({bufferFlags})";
+                            }
+                        }
+                        else if (argType == CommandArgType.InArgument || argType == CommandArgType.OutArgument)
+                        {
+                            string alignment = GetTypeAlignmentExpression(compilation, parameter.Type);
+
+                            arg = $"new CommandArg(CommandArgType.{argType}, Unsafe.SizeOf<{canonicalTypeName}>(), {alignment})";
+                        }
+                        else
+                        {
+                            arg = $"new CommandArg(CommandArgType.{argType})";
+                        }
+
+                        args[index++] = arg;
+                    }
+
+                    generator.AppendLine($"{{ {commandId}, new CommandHandler({method.Identifier.Text}, {string.Join(", ", args)}) }},");
+                }
+            }
+
+            generator.LeaveScope(";");
+            generator.LeaveScope();
+        }
+
+        private static IEnumerable<string> GetAttributeAguments(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex)
+        {
+            ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
+
+            foreach (var attribute in symbol.GetAttributes())
+            {
+                if (attribute.AttributeClass.ToDisplayString() == attributeName && (uint)argIndex < (uint)attribute.ConstructorArguments.Length)
+                {
+                    yield return attribute.ConstructorArguments[argIndex].ToCSharpString();
+                }
+            }
+        }
+
+        private static string GetFirstAttributeAgument(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex)
+        {
+            return GetAttributeAguments(compilation, syntaxNode, attributeName, argIndex).FirstOrDefault();
+        }
+
+        private static void GenerateMethod(CodeGenerator generator, Compilation compilation, MethodDeclarationSyntax method)
+        {
+            int inObjectsCount = 0;
+            int outObjectsCount = 0;
+            int buffersCount = 0;
+
+            foreach (var parameter in method.ParameterList.Parameters)
+            {
+                if (IsObject(compilation, parameter))
+                {
+                    if (IsIn(parameter))
+                    {
+                        inObjectsCount++;
+                    }
+                    else
+                    {
+                        outObjectsCount++;
+                    }
+                }
+                else if (IsBuffer(compilation, parameter))
+                {
+                    buffersCount++;
+                }
+            }
+
+            generator.EnterScope($"private Result {method.Identifier.Text}(" +
+                "ref ServiceDispatchContext context, " +
+                "HipcCommandProcessor processor, " +
+                "ServerMessageRuntimeMetadata runtimeMetadata, " +
+                "ReadOnlySpan<byte> inRawData, " +
+                "ref Span<CmifOutHeader> outHeader)");
+
+            bool returnsResult = method.ReturnType != null && GetCanonicalTypeName(compilation, method.ReturnType) == TypeResult;
+
+            if (returnsResult || buffersCount != 0 || inObjectsCount != 0)
+            {
+                generator.AppendLine($"Result {ResultVariableName};");
+
+                if (buffersCount != 0)
+                {
+                    generator.AppendLine($"bool[] {IsBufferMapAliasVariableName} = new bool[{method.ParameterList.Parameters.Count}];");
+                    generator.AppendLine();
+
+                    generator.AppendLine($"{ResultVariableName} = processor.ProcessBuffers(ref context, {IsBufferMapAliasVariableName}, runtimeMetadata);");
+                    generator.EnterScope($"if ({ResultVariableName}.IsFailure)");
+                    generator.AppendLine($"return {ResultVariableName};");
+                    generator.LeaveScope();
+                }
+
+                generator.AppendLine();
+            }
+
+            List<OutParameter> outParameters = new List<OutParameter>();
+
+            string[] args = new string[method.ParameterList.Parameters.Count];
+
+            if (inObjectsCount != 0)
+            {
+                generator.AppendLine($"var {InObjectsVariableName} = new IServiceObject[{inObjectsCount}];");
+                generator.AppendLine();
+
+                generator.AppendLine($"{ResultVariableName} = processor.GetInObjects(context.Processor, {InObjectsVariableName});");
+                generator.EnterScope($"if ({ResultVariableName}.IsFailure)");
+                generator.AppendLine($"return {ResultVariableName};");
+                generator.LeaveScope();
+                generator.AppendLine();
+            }
+
+            if (outObjectsCount != 0)
+            {
+                generator.AppendLine($"var {OutObjectsVariableName} = new IServiceObject[{outObjectsCount}];");
+            }
+
+            int index = 0;
+            int inCopyHandleIndex = 0;
+            int inMoveHandleIndex = 0;
+            int inObjectIndex = 0;
+
+            foreach (var parameter in method.ParameterList.Parameters)
+            {
+                string name = parameter.Identifier.Text;
+                string argName = GetPrefixedArgName(name);
+                string canonicalTypeName = GetCanonicalTypeNameWithGenericArguments(compilation, parameter.Type);
+                CommandArgType argType = GetCommandArgType(compilation, parameter);
+                Modifier modifier = GetModifier(parameter);
+                bool isNonSpanBuffer = false;
+
+                if (modifier == Modifier.Out)
+                {
+                    if (IsNonSpanOutBuffer(compilation, parameter))
+                    {
+                        generator.AppendLine($"using var {argName} = CommandSerialization.GetWritableRegion(processor.GetBufferRange({index}));");
+
+                        argName = $"out {GenerateSpanCastElement0(canonicalTypeName, $"{argName}.Memory.Span")}";
+                    }
+                    else
+                    {
+                        outParameters.Add(new OutParameter(argName, canonicalTypeName, index, argType));
+
+                        argName = $"out {canonicalTypeName} {argName}";
+                    }
+                }
+                else
+                {
+                    string value = $"default({canonicalTypeName})";
+
+                    switch (argType)
+                    {
+                        case CommandArgType.InArgument:
+                            value = $"CommandSerialization.DeserializeArg<{canonicalTypeName}>(inRawData, processor.GetInArgOffset({index}))";
+                            break;
+                        case CommandArgType.InCopyHandle:
+                            value = $"CommandSerialization.DeserializeCopyHandle(ref context, {inCopyHandleIndex++})";
+                            break;
+                        case CommandArgType.InMoveHandle:
+                            value = $"CommandSerialization.DeserializeMoveHandle(ref context, {inMoveHandleIndex++})";
+                            break;
+                        case CommandArgType.ProcessId:
+                            value = "CommandSerialization.DeserializeClientProcessId(ref context)";
+                            break;
+                        case CommandArgType.InObject:
+                            value = $"{InObjectsVariableName}[{inObjectIndex++}]";
+                            break;
+                        case CommandArgType.Buffer:
+                            if (IsReadOnlySpan(compilation, parameter))
+                            {
+                                string spanGenericTypeName = GetCanonicalTypeNameOfGenericArgument(compilation, parameter.Type, 0);
+                                value = GenerateSpanCast(spanGenericTypeName, $"CommandSerialization.GetReadOnlySpan(processor.GetBufferRange({index}))");
+                            }
+                            else if (IsSpan(compilation, parameter))
+                            {
+                                value = $"CommandSerialization.GetWritableRegion(processor.GetBufferRange({index}))";
+                            }
+                            else
+                            {
+                                value = $"CommandSerialization.GetRef<{canonicalTypeName}>(processor.GetBufferRange({index}))";
+                                isNonSpanBuffer = true;
+                            }
+                            break;
+                    }
+
+                    if (IsSpan(compilation, parameter))
+                    {
+                        generator.AppendLine($"using var {argName} = {value};");
+
+                        string spanGenericTypeName = GetCanonicalTypeNameOfGenericArgument(compilation, parameter.Type, 0);
+                        argName = GenerateSpanCast(spanGenericTypeName, $"{argName}.Memory.Span"); ;
+                    }
+                    else if (isNonSpanBuffer)
+                    {
+                        generator.AppendLine($"ref var {argName} = ref {value};");
+                    }
+                    else if (argType == CommandArgType.InObject)
+                    {
+                        generator.EnterScope($"if (!({value} is {canonicalTypeName} {argName}))");
+                        generator.AppendLine("return SfResult.InvalidInObject;");
+                        generator.LeaveScope();
+                    }
+                    else
+                    {
+                        generator.AppendLine($"var {argName} = {value};");
+                    }
+                }
+
+                if (modifier == Modifier.Ref)
+                {
+                    argName = $"ref {argName}";
+                }
+                else if (modifier == Modifier.In)
+                {
+                    argName = $"in {argName}";
+                }
+
+                args[index++] = argName;
+            }
+
+            if (args.Length - outParameters.Count > 0)
+            {
+                generator.AppendLine();
+            }
+
+            if (returnsResult)
+            {
+                generator.AppendLine($"{ResultVariableName} = {method.Identifier.Text}({string.Join(", ", args)});");
+                generator.AppendLine();
+
+                generator.AppendLine($"Span<byte> {OutRawDataVariableName};");
+                generator.AppendLine();
+
+                generator.EnterScope($"if ({ResultVariableName}.IsFailure)");
+                generator.AppendLine($"context.Processor.PrepareForErrorReply(ref context, out {OutRawDataVariableName}, runtimeMetadata);");
+                generator.AppendLine($"CommandHandler.GetCmifOutHeaderPointer(ref outHeader, ref {OutRawDataVariableName});");
+                generator.AppendLine($"return {ResultVariableName};");
+                generator.LeaveScope();
+            }
+            else
+            {
+                generator.AppendLine($"{method.Identifier.Text}({string.Join(", ", args)});");
+
+                generator.AppendLine();
+                generator.AppendLine($"Span<byte> {OutRawDataVariableName};");
+            }
+
+            generator.AppendLine();
+
+            generator.AppendLine($"var {ResponseVariableName} = context.Processor.PrepareForReply(ref context, out {OutRawDataVariableName}, runtimeMetadata);");
+            generator.AppendLine($"CommandHandler.GetCmifOutHeaderPointer(ref outHeader, ref {OutRawDataVariableName});");
+            generator.AppendLine();
+
+            generator.EnterScope($"if ({OutRawDataVariableName}.Length < processor.OutRawDataSize)");
+            generator.AppendLine("return SfResult.InvalidOutRawSize;");
+            generator.LeaveScope();
+
+            if (outParameters.Count != 0)
+            {
+                generator.AppendLine();
+
+                int outCopyHandleIndex = 0;
+                int outMoveHandleIndex = outObjectsCount;
+                int outObjectIndex = 0;
+
+                for (int outIndex = 0; outIndex < outParameters.Count; outIndex++)
+                {
+                    OutParameter outParameter = outParameters[outIndex];
+
+                    switch (outParameter.Type)
+                    {
+                        case CommandArgType.OutArgument:
+                            generator.AppendLine($"CommandSerialization.SerializeArg<{outParameter.TypeName}>({OutRawDataVariableName}, processor.GetOutArgOffset({outParameter.Index}), {outParameter.Name});");
+                            break;
+                        case CommandArgType.OutCopyHandle:
+                            generator.AppendLine($"CommandSerialization.SerializeCopyHandle({ResponseVariableName}, {outCopyHandleIndex++}, {outParameter.Name});");
+                            break;
+                        case CommandArgType.OutMoveHandle:
+                            generator.AppendLine($"CommandSerialization.SerializeMoveHandle({ResponseVariableName}, {outMoveHandleIndex++}, {outParameter.Name});");
+                            break;
+                        case CommandArgType.OutObject:
+                            generator.AppendLine($"{OutObjectsVariableName}[{outObjectIndex++}] = {outParameter.Name};");
+                            break;
+                    }
+                }
+            }
+
+            generator.AppendLine();
+
+            if (outObjectsCount != 0 || buffersCount != 0)
+            {
+                if (outObjectsCount != 0)
+                {
+                    generator.AppendLine($"processor.SetOutObjects(ref context, {ResponseVariableName}, {OutObjectsVariableName});");
+                }
+
+                if (buffersCount != 0)
+                {
+                    generator.AppendLine($"processor.SetOutBuffers({ResponseVariableName}, {IsBufferMapAliasVariableName});");
+                }
+
+                generator.AppendLine();
+            }
+
+            generator.AppendLine("return Result.Success;");
+            generator.LeaveScope();
+        }
+
+        private static string GetPrefixedArgName(string name)
+        {
+            return ArgVariablePrefix + name[0].ToString().ToUpperInvariant() + name.Substring(1);
+        }
+
+        private static string GetCanonicalTypeNameOfGenericArgument(Compilation compilation, SyntaxNode syntaxNode, int argIndex)
+        {
+            if (syntaxNode is GenericNameSyntax genericNameSyntax)
+            {
+                if ((uint)argIndex < (uint)genericNameSyntax.TypeArgumentList.Arguments.Count)
+                {
+                    return GetCanonicalTypeNameWithGenericArguments(compilation, genericNameSyntax.TypeArgumentList.Arguments[argIndex]);
+                }
+            }
+
+            return GetCanonicalTypeName(compilation, syntaxNode);
+        }
+
+        private static string GetCanonicalTypeNameWithGenericArguments(Compilation compilation, SyntaxNode syntaxNode)
+        {
+            TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+
+            return typeInfo.Type.ToDisplayString();
+        }
+
+        private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode)
+        {
+            TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+            string typeName = typeInfo.Type.ToDisplayString();
+
+            int genericArgsStartIndex = typeName.IndexOf('<');
+            if (genericArgsStartIndex >= 0)
+            {
+                return typeName.Substring(0, genericArgsStartIndex);
+            }
+
+            return typeName;
+        }
+
+        private static SpecialType GetSpecialTypeName(Compilation compilation, SyntaxNode syntaxNode)
+        {
+            TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+
+            return typeInfo.Type.SpecialType;
+        }
+
+        private static string GetTypeAlignmentExpression(Compilation compilation, SyntaxNode syntaxNode)
+        {
+            TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+
+            // Since there's no way to get the alignment for a arbitrary type here, let's assume that all
+            // "special" types are primitive types aligned to their own length.
+            // Otherwise, assume that the type is a custom struct, that either defines an explicit alignment
+            // or has an alignment of 1 which is the lowest possible value.
+            if (typeInfo.Type.SpecialType == SpecialType.None)
+            {
+                string pack = GetTypeFirstNamedAttributeAgument(compilation, syntaxNode, TypeStructLayoutAttribute, "Pack");
+
+                return pack ?? "1";
+            }
+            else
+            {
+                return $"Unsafe.SizeOf<{typeInfo.Type.ToDisplayString()}>()";
+            }
+        }
+
+        private static string GetTypeFirstNamedAttributeAgument(Compilation compilation, SyntaxNode syntaxNode, string attributeName, string argName)
+        {
+            ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode).Type;
+
+            foreach (var attribute in symbol.GetAttributes())
+            {
+                if (attribute.AttributeClass.ToDisplayString() == attributeName)
+                {
+                    foreach (var kv in attribute.NamedArguments)
+                    {
+                        if (kv.Key == argName)
+                        {
+                            return kv.Value.ToCSharpString();
+                        }
+                    }
+                }
+            }
+
+            return null;
+        }
+
+        private static CommandArgType GetCommandArgType(Compilation compilation, ParameterSyntax parameter)
+        {
+            CommandArgType type = CommandArgType.Invalid;
+
+            if (IsIn(parameter))
+            {
+                if (IsArgument(compilation, parameter))
+                {
+                    type = CommandArgType.InArgument;
+                }
+                else if (IsBuffer(compilation, parameter))
+                {
+                    type = CommandArgType.Buffer;
+                }
+                else if (IsCopyHandle(compilation, parameter))
+                {
+                    type = CommandArgType.InCopyHandle;
+                }
+                else if (IsMoveHandle(compilation, parameter))
+                {
+                    type = CommandArgType.InMoveHandle;
+                }
+                else if (IsObject(compilation, parameter))
+                {
+                    type = CommandArgType.InObject;
+                }
+                else if (IsProcessId(compilation, parameter))
+                {
+                    type = CommandArgType.ProcessId;
+                }
+            }
+            else if (IsOut(parameter))
+            {
+                if (IsArgument(compilation, parameter))
+                {
+                    type = CommandArgType.OutArgument;
+                }
+                else if (IsNonSpanOutBuffer(compilation, parameter))
+                {
+                    type = CommandArgType.Buffer;
+                }
+                else if (IsCopyHandle(compilation, parameter))
+                {
+                    type = CommandArgType.OutCopyHandle;
+                }
+                else if (IsMoveHandle(compilation, parameter))
+                {
+                    type = CommandArgType.OutMoveHandle;
+                }
+                else if (IsObject(compilation, parameter))
+                {
+                    type = CommandArgType.OutObject;
+                }
+            }
+
+            return type;
+        }
+
+        private static bool IsArgument(Compilation compilation,ParameterSyntax parameter)
+        {
+            return !IsBuffer(compilation, parameter) &&
+                   !IsHandle(compilation, parameter) &&
+                   !IsObject(compilation, parameter) &&
+                   !IsProcessId(compilation, parameter) &&
+                   IsUnmanagedType(compilation, parameter.Type);
+        }
+
+        private static bool IsBuffer(Compilation compilation, ParameterSyntax parameter)
+        {
+            return HasAttribute(compilation, parameter, TypeBufferAttribute) &&
+                   IsValidTypeForBuffer(compilation, parameter);
+        }
+
+        private static bool IsNonSpanOutBuffer(Compilation compilation, ParameterSyntax parameter)
+        {
+            return HasAttribute(compilation, parameter, TypeBufferAttribute) &&
+                   IsUnmanagedType(compilation, parameter.Type);
+        }
+
+        private static bool IsValidTypeForBuffer(Compilation compilation, ParameterSyntax parameter)
+        {
+            return IsReadOnlySpan(compilation, parameter) ||
+                   IsSpan(compilation, parameter) ||
+                   IsUnmanagedType(compilation, parameter.Type);
+        }
+
+        private static bool IsUnmanagedType(Compilation compilation, SyntaxNode syntaxNode)
+        {
+            TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+
+            return typeInfo.Type.IsUnmanagedType;
+        }
+
+        private static bool IsReadOnlySpan(Compilation compilation, ParameterSyntax parameter)
+        {
+            return GetCanonicalTypeName(compilation, parameter.Type) == TypeSystemReadOnlySpan;
+        }
+
+        private static bool IsSpan(Compilation compilation, ParameterSyntax parameter)
+        {
+            return GetCanonicalTypeName(compilation, parameter.Type) == TypeSystemSpan;
+        }
+
+        private static bool IsHandle(Compilation compilation, ParameterSyntax parameter)
+        {
+            return IsCopyHandle(compilation, parameter) || IsMoveHandle(compilation, parameter);
+        }
+
+        private static bool IsCopyHandle(Compilation compilation, ParameterSyntax parameter)
+        {
+            return HasAttribute(compilation, parameter, TypeCopyHandleAttribute) &&
+                   GetSpecialTypeName(compilation, parameter.Type) == SpecialType.System_Int32;
+        }
+
+        private static bool IsMoveHandle(Compilation compilation, ParameterSyntax parameter)
+        {
+            return HasAttribute(compilation, parameter, TypeMoveHandleAttribute) &&
+                   GetSpecialTypeName(compilation, parameter.Type) == SpecialType.System_Int32;
+        }
+
+        private static bool IsObject(Compilation compilation, ParameterSyntax parameter)
+        {
+            SyntaxNode syntaxNode = parameter.Type;
+            TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+
+            return typeInfo.Type.ToDisplayString() == TypeIServiceObject ||
+                   typeInfo.Type.AllInterfaces.Any(x => x.ToDisplayString() == TypeIServiceObject);
+        }
+
+        private static bool IsProcessId(Compilation compilation, ParameterSyntax parameter)
+        {
+            return HasAttribute(compilation, parameter, TypeClientProcessIdAttribute) &&
+                   GetSpecialTypeName(compilation, parameter.Type) == SpecialType.System_UInt64;
+        }
+
+        private static bool IsIn(ParameterSyntax parameter)
+        {
+            return !IsOut(parameter);
+        }
+
+        private static bool IsOut(ParameterSyntax parameter)
+        {
+            return parameter.Modifiers.Any(SyntaxKind.OutKeyword);
+        }
+
+        private static Modifier GetModifier(ParameterSyntax parameter)
+        {
+            foreach (SyntaxToken syntaxToken in parameter.Modifiers)
+            {
+                if (syntaxToken.IsKind(SyntaxKind.RefKeyword))
+                {
+                    return Modifier.Ref;
+                }
+                else if (syntaxToken.IsKind(SyntaxKind.OutKeyword))
+                {
+                    return Modifier.Out;
+                }
+                else if (syntaxToken.IsKind(SyntaxKind.InKeyword))
+                {
+                    return Modifier.In;
+                }
+            }
+
+            return Modifier.None;
+        }
+
+        private static string GenerateSpanCastElement0(string targetType, string input)
+        {
+            return $"{GenerateSpanCast(targetType, input)}[0]";
+        }
+
+        private static string GenerateSpanCast(string targetType, string input)
+        {
+            return $"MemoryMarshal.Cast<byte, {targetType}>({input})";
+        }
+
+        private static bool HasAttribute(Compilation compilation, ParameterSyntax parameterSyntax, string fullAttributeName)
+        {
+            foreach (var attributeList in parameterSyntax.AttributeLists)
+            {
+                foreach (var attribute in attributeList.Attributes)
+                {
+                    if (GetCanonicalTypeName(compilation, attribute) == fullAttributeName)
+                    {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        private static bool NeedsIServiceObjectImplementation(Compilation compilation, ClassDeclarationSyntax classDeclarationSyntax)
+        {
+            ITypeSymbol type = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree).GetDeclaredSymbol(classDeclarationSyntax);
+            var serviceObjectInterface = type.AllInterfaces.FirstOrDefault(x => x.ToDisplayString() == TypeIServiceObject);
+            var interfaceMember = serviceObjectInterface?.GetMembers().FirstOrDefault(x => x.Name == "GetCommandHandlers");
+
+            // Return true only if the class implements IServiceObject but does not actually implement the method
+            // that the interface defines, since this is the only case we want to handle, if the method already exists
+            // we have nothing to do.
+            return serviceObjectInterface != null && type.FindImplementationForInterfaceMember(interfaceMember) == null;
+        }
+
+        public void Initialize(GeneratorInitializationContext context)
+        {
+            context.RegisterForSyntaxNotifications(() => new HipcSyntaxReceiver());
+        }
+    }
+}
diff --git a/Ryujinx.Horizon.Generators/Hipc/HipcSyntaxReceiver.cs b/Ryujinx.Horizon.Generators/Hipc/HipcSyntaxReceiver.cs
new file mode 100644
index 0000000000..4b998dbe2f
--- /dev/null
+++ b/Ryujinx.Horizon.Generators/Hipc/HipcSyntaxReceiver.cs
@@ -0,0 +1,58 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Ryujinx.Horizon.Generators.Hipc
+{
+    class HipcSyntaxReceiver : ISyntaxReceiver
+    {
+        public List<CommandInterface> CommandInterfaces { get; }
+
+        public HipcSyntaxReceiver()
+        {
+            CommandInterfaces = new List<CommandInterface>();
+        }
+
+        public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
+        {
+            if (syntaxNode is ClassDeclarationSyntax classDeclaration)
+            {
+                if (!classDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword) || classDeclaration.BaseList == null)
+                {
+                    return;
+                }
+
+                CommandInterface commandInterface = new CommandInterface(classDeclaration);
+
+                foreach (var memberDeclaration in classDeclaration.Members)
+                {
+                    if (memberDeclaration is MethodDeclarationSyntax methodDeclaration)
+                    {
+                        VisitMethod(commandInterface, methodDeclaration);
+                    }
+                }
+
+                CommandInterfaces.Add(commandInterface);
+            }
+        }
+
+        private void VisitMethod(CommandInterface commandInterface, MethodDeclarationSyntax methodDeclaration)
+        {
+            string attributeName = HipcGenerator.CommandAttributeName.Replace("Attribute", string.Empty);
+
+            if (methodDeclaration.AttributeLists.Count != 0)
+            {
+                foreach (var attributeList in methodDeclaration.AttributeLists)
+                {
+                    if (attributeList.Attributes.Any(x => x.Name.ToString().Contains(attributeName)))
+                    {
+                        commandInterface.CommandImplementations.Add(methodDeclaration);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon.Kernel.Generators/CodeGenerator.cs b/Ryujinx.Horizon.Kernel.Generators/CodeGenerator.cs
new file mode 100644
index 0000000000..80a33c66cf
--- /dev/null
+++ b/Ryujinx.Horizon.Kernel.Generators/CodeGenerator.cs
@@ -0,0 +1,58 @@
+using System.Text;
+
+namespace Ryujinx.Horizon.Generators
+{
+    class CodeGenerator
+    {
+        private const string Indent = "    ";
+        private readonly StringBuilder _sb;
+        private string _currentIndent;
+
+        public CodeGenerator()
+        {
+            _sb = new StringBuilder();
+        }
+
+        public void EnterScope(string header = null)
+        {
+            if (header != null)
+            {
+                AppendLine(header);
+            }
+
+            AppendLine("{");
+            IncreaseIndentation();
+        }
+
+        public void LeaveScope()
+        {
+            DecreaseIndentation();
+            AppendLine("}");
+        }
+
+        public void IncreaseIndentation()
+        {
+            _currentIndent += Indent;
+        }
+
+        public void DecreaseIndentation()
+        {
+            _currentIndent = _currentIndent.Substring(0, _currentIndent.Length - Indent.Length);
+        }
+
+        public void AppendLine()
+        {
+            _sb.AppendLine();
+        }
+
+        public void AppendLine(string text)
+        {
+            _sb.AppendLine(_currentIndent + text);
+        }
+
+        public override string ToString()
+        {
+            return _sb.ToString();
+        }
+    }
+}
diff --git a/Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs b/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs
similarity index 93%
rename from Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs
rename to Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs
index 2562cd46cf..f2a8770306 100644
--- a/Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs
+++ b/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs
@@ -25,15 +25,17 @@ namespace Ryujinx.Horizon.Generators.Kernel
         private const string TypeSystemUInt64 = "System.UInt64";
 
         private const string NamespaceKernel = "Ryujinx.HLE.HOS.Kernel";
+        private const string NamespaceHorizonCommon = "Ryujinx.Horizon.Common";
         private const string TypeSvcAttribute = NamespaceKernel + ".SupervisorCall.SvcAttribute";
         private const string TypePointerSizedAttribute = NamespaceKernel + ".SupervisorCall.PointerSizedAttribute";
+        private const string TypeResultName = "Result";
         private const string TypeKernelResultName = "KernelResult";
-        private const string TypeKernelResult = NamespaceKernel + ".Common." + TypeKernelResultName;
+        private const string TypeResult = NamespaceHorizonCommon + "." + TypeResultName;
         private const string TypeExecutionContext = "IExecutionContext";
 
         private static readonly string[] _expectedResults = new string[]
         {
-            $"{TypeKernelResultName}.Success",
+            $"{TypeResultName}.Success",
             $"{TypeKernelResultName}.TimedOut",
             $"{TypeKernelResultName}.Cancelled",
             $"{TypeKernelResultName}.PortRemoteClosed",
@@ -133,6 +135,7 @@ namespace Ryujinx.Horizon.Generators.Kernel
             generator.AppendLine($"using {NamespaceKernel}.Memory;");
             generator.AppendLine($"using {NamespaceKernel}.Process;");
             generator.AppendLine($"using {NamespaceKernel}.Threading;");
+            generator.AppendLine($"using {NamespaceHorizonCommon};");
             generator.AppendLine("using System;");
             generator.AppendLine();
             generator.EnterScope($"namespace {ClassNamespace}");
@@ -183,7 +186,7 @@ namespace Ryujinx.Horizon.Generators.Kernel
 
         private static void GenerateResultCheckHelper(CodeGenerator generator)
         {
-            generator.EnterScope($"private static bool {ResultCheckHelperName}({TypeKernelResultName} {ResultVariableName})");
+            generator.EnterScope($"private static bool {ResultCheckHelperName}({TypeResultName} {ResultVariableName})");
 
             string[] expectedChecks = new string[_expectedResults.Length];
 
@@ -266,19 +269,25 @@ namespace Ryujinx.Horizon.Generators.Kernel
 
             GenerateLogPrintBeforeCall(generator, method.Identifier.Text, logInArgs);
 
-            string returnTypeName = method.ReturnType.ToString();
             string argsList = string.Join(", ", args);
             int returnRegisterIndex = 0;
             string result = null;
             string canonicalReturnTypeName = null;
 
-            if (returnTypeName != "void")
+            if (method.ReturnType.ToString() != "void")
             {
                 generator.AppendLine($"var {ResultVariableName} = syscall.{method.Identifier.Text}({argsList});");
-                generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){ResultVariableName});");
-
                 canonicalReturnTypeName = GetCanonicalTypeName(compilation, method.ReturnType);
 
+                if (canonicalReturnTypeName == TypeResult)
+                {
+                    generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){ResultVariableName}.ErrorCode);");
+                }
+                else
+                {
+                    generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){ResultVariableName});");
+                }
+
                 if (Is64BitInteger(canonicalReturnTypeName))
                 {
                     generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint)({ResultVariableName} >> 32));");
@@ -358,8 +367,17 @@ namespace Ryujinx.Horizon.Generators.Kernel
             if (method.ReturnType.ToString() != "void")
             {
                 generator.AppendLine($"var {ResultVariableName} = syscall.{method.Identifier.Text}({argsList});");
-                generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){ResultVariableName});");
                 canonicalReturnTypeName = GetCanonicalTypeName(compilation, method.ReturnType);
+
+                if (canonicalReturnTypeName == TypeResult)
+                {
+                    generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){ResultVariableName}.ErrorCode);");
+                }
+                else
+                {
+                    generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){ResultVariableName});");
+                }
+  
                 result = GetFormattedLogValue(ResultVariableName, canonicalReturnTypeName);
             }
             else
@@ -433,7 +451,7 @@ namespace Ryujinx.Horizon.Generators.Kernel
                 log += $" = {result}";
             }
 
-            if (canonicalResultTypeName == TypeKernelResult)
+            if (canonicalResultTypeName == TypeResult)
             {
                 generator.EnterScope($"if ({ResultCheckHelperName}({ResultVariableName}))");
                 GenerateLogPrint(generator, "Trace", "KernelSvc", log);
diff --git a/Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs b/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallSyntaxReceiver.cs
similarity index 100%
rename from Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs
rename to Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallSyntaxReceiver.cs
diff --git a/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj b/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj
new file mode 100644
index 0000000000..67fab2d55c
--- /dev/null
+++ b/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj
@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
+  </ItemGroup>
+
+</Project>
diff --git a/Ryujinx.Horizon/HeapAllocator.cs b/Ryujinx.Horizon/HeapAllocator.cs
new file mode 100644
index 0000000000..867c96770e
--- /dev/null
+++ b/Ryujinx.Horizon/HeapAllocator.cs
@@ -0,0 +1,143 @@
+using Ryujinx.Common;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Ryujinx.Horizon
+{
+    class HeapAllocator
+    {
+        private const ulong InvalidAddress = ulong.MaxValue;
+
+        private struct Range : IComparable<Range>
+        {
+            public ulong Offset { get; }
+            public ulong Size { get; }
+
+            public Range(ulong offset, ulong size)
+            {
+                Offset = offset;
+                Size = size;
+            }
+
+            public int CompareTo(Range other)
+            {
+                return Offset.CompareTo(other.Offset);
+            }
+        }
+
+        private readonly List<Range> _freeRanges;
+        private ulong _currentHeapSize;
+
+        public HeapAllocator()
+        {
+            _freeRanges = new List<Range>();
+            _currentHeapSize = 0;
+        }
+
+        public ulong Allocate(ulong size, ulong alignment = 1UL)
+        {
+            ulong address = AllocateImpl(size, alignment);
+
+            if (address == InvalidAddress)
+            {
+                ExpandHeap(size + alignment - 1UL);
+
+                address = AllocateImpl(size, alignment);
+
+                Debug.Assert(address != InvalidAddress);
+            }
+
+            return address;
+        }
+
+        private void ExpandHeap(ulong expansionSize)
+        {
+            ulong oldHeapSize = _currentHeapSize;
+            ulong newHeapSize = BitUtils.AlignUp(oldHeapSize + expansionSize, 0x200000UL);
+
+            _currentHeapSize = newHeapSize;
+
+            HorizonStatic.Syscall.SetHeapSize(out ulong heapAddress, newHeapSize).AbortOnFailure();
+
+            Free(heapAddress + oldHeapSize, newHeapSize - oldHeapSize);
+        }
+
+        private ulong AllocateImpl(ulong size, ulong alignment)
+        {
+            for (int i = 0; i < _freeRanges.Count; i++)
+            {
+                var range = _freeRanges[i];
+
+                ulong alignedOffset = BitUtils.AlignUp(range.Offset, alignment);
+                ulong sizeDelta = alignedOffset - range.Offset;
+                ulong usableSize = range.Size - sizeDelta;
+
+                if (sizeDelta < range.Size && usableSize >= size)
+                {
+                    _freeRanges.RemoveAt(i);
+
+                    if (sizeDelta != 0)
+                    {
+                        InsertFreeRange(range.Offset, sizeDelta);
+                    }
+
+                    ulong endOffset = range.Offset + range.Size;
+                    ulong remainingSize = endOffset - (alignedOffset + size);
+                    if (remainingSize != 0)
+                    {
+                        InsertFreeRange(endOffset - remainingSize, remainingSize);
+                    }
+
+                    return alignedOffset;
+                }
+            }
+
+            return InvalidAddress;
+        }
+
+        public void Free(ulong offset, ulong size)
+        {
+            InsertFreeRangeComingled(offset, size);
+        }
+
+        private void InsertFreeRange(ulong offset, ulong size)
+        {
+            var range = new Range(offset, size);
+            int index = _freeRanges.BinarySearch(range);
+            if (index < 0)
+            {
+                index = ~index;
+            }
+
+            _freeRanges.Insert(index, range);
+        }
+
+        private void InsertFreeRangeComingled(ulong offset, ulong size)
+        {
+            ulong endOffset = offset + size;
+            var range = new Range(offset, size);
+            int index = _freeRanges.BinarySearch(range);
+            if (index < 0)
+            {
+                index = ~index;
+            }
+
+            if (index < _freeRanges.Count && _freeRanges[index].Offset == endOffset)
+            {
+                endOffset = _freeRanges[index].Offset + _freeRanges[index].Size;
+                _freeRanges.RemoveAt(index);
+            }
+
+            if (index > 0 && _freeRanges[index - 1].Offset + _freeRanges[index - 1].Size == offset)
+            {
+                offset = _freeRanges[index - 1].Offset;
+                _freeRanges.RemoveAt(--index);
+            }
+
+            range = new Range(offset, endOffset - offset);
+
+            _freeRanges.Insert(index, range);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Horizon/HorizonOptions.cs b/Ryujinx.Horizon/HorizonOptions.cs
new file mode 100644
index 0000000000..b1567c6a4b
--- /dev/null
+++ b/Ryujinx.Horizon/HorizonOptions.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Horizon
+{
+    public struct HorizonOptions
+    {
+        public bool IgnoreMissingServices { get; }
+
+        public HorizonOptions(bool ignoreMissingServices)
+        {
+            IgnoreMissingServices = ignoreMissingServices;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/HorizonStatic.cs b/Ryujinx.Horizon/HorizonStatic.cs
new file mode 100644
index 0000000000..1e483cd44b
--- /dev/null
+++ b/Ryujinx.Horizon/HorizonStatic.cs
@@ -0,0 +1,44 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Memory;
+using System;
+
+namespace Ryujinx.Horizon
+{
+    static class HorizonStatic
+    {
+        [ThreadStatic]
+        private static HorizonOptions _options;
+
+        [ThreadStatic]
+        private static ISyscallApi _syscall;
+
+        [ThreadStatic]
+        private static IVirtualMemoryManager _addressSpace;
+
+        [ThreadStatic]
+        private static IThreadContext _threadContext;
+
+        [ThreadStatic]
+        private static int _threadHandle;
+
+        public static HorizonOptions Options => _options;
+        public static ISyscallApi Syscall => _syscall;
+        public static IVirtualMemoryManager AddressSpace => _addressSpace;
+        public static IThreadContext ThreadContext => _threadContext;
+        public static int CurrentThreadHandle => _threadHandle;
+
+        public static void Register(
+            HorizonOptions options,
+            ISyscallApi syscallApi,
+            IVirtualMemoryManager addressSpace,
+            IThreadContext threadContext,
+            int threadHandle)
+        {
+            _options = options;
+            _syscall = syscallApi;
+            _addressSpace = addressSpace;
+            _threadContext = threadContext;
+            _threadHandle = threadHandle;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/IService.cs b/Ryujinx.Horizon/IService.cs
new file mode 100644
index 0000000000..67c12cef64
--- /dev/null
+++ b/Ryujinx.Horizon/IService.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.Horizon
+{
+    interface IService
+    {
+        abstract static void Main();
+    }
+}
diff --git a/Ryujinx.Horizon/LogManager/LmIpcServer.cs b/Ryujinx.Horizon/LogManager/LmIpcServer.cs
new file mode 100644
index 0000000000..7b757fe988
--- /dev/null
+++ b/Ryujinx.Horizon/LogManager/LmIpcServer.cs
@@ -0,0 +1,54 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using Ryujinx.Horizon.Sdk.Sm;
+using Ryujinx.Horizon.Sm;
+
+namespace Ryujinx.Horizon.LogManager
+{
+    class LmIpcServer
+    {
+        private const int LogMaxSessionsCount = 42;
+
+        private const int PointerBufferSize = 0x400;
+        private const int MaxDomains = 31;
+        private const int MaxDomainObjects = 61;
+
+        private const int MaxPortsCount = 1;
+
+        private static readonly ManagerOptions _logManagerOptions = new ManagerOptions(
+            PointerBufferSize,
+            MaxDomains,
+            MaxDomainObjects,
+            false);
+
+        private static readonly ServiceName _logServiceName = ServiceName.Encode("lm");
+
+        private SmApi _sm;
+        private ServerManager _serverManager;
+
+        private LmLog _logServiceObject;
+
+        public void Initialize()
+        {
+            HeapAllocator allocator = new HeapAllocator();
+
+            _sm = new SmApi();
+            _sm.Initialize().AbortOnFailure();
+
+            _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _logManagerOptions, LogMaxSessionsCount);
+
+            _logServiceObject = new LmLog();
+
+            _serverManager.RegisterObjectForServer(_logServiceObject, _logServiceName, LogMaxSessionsCount);
+        }
+
+        public void ServiceRequests()
+        {
+            _serverManager.ServiceRequests();
+        }
+
+        public void Shutdown()
+        {
+            _serverManager.Dispose();
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/LogManager/LmLog.cs b/Ryujinx.Horizon/LogManager/LmLog.cs
new file mode 100644
index 0000000000..772465c459
--- /dev/null
+++ b/Ryujinx.Horizon/LogManager/LmLog.cs
@@ -0,0 +1,19 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Lm;
+using Ryujinx.Horizon.Sdk.Sf;
+
+namespace Ryujinx.Horizon.LogManager
+{
+    partial class LmLog : IServiceObject
+    {
+        public LogDestination LogDestination { get; set; } = LogDestination.TargetManager;
+
+        [CmifCommand(0)]
+        public Result OpenLogger(out LmLogger logger, [ClientProcessId] ulong clientProcessId)
+        {
+            logger = new LmLogger(this, clientProcessId);
+
+            return Result.Success;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/LogManager/LmLogger.cs b/Ryujinx.Horizon/LogManager/LmLogger.cs
new file mode 100644
index 0000000000..461776cd89
--- /dev/null
+++ b/Ryujinx.Horizon/LogManager/LmLogger.cs
@@ -0,0 +1,139 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.Common.Memory;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Lm;
+using Ryujinx.Horizon.Sdk.Sf;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Ryujinx.Horizon.LogManager
+{
+    partial class LmLogger : IServiceObject
+    {
+        private readonly LmLog _log;
+        private readonly ulong _clientProcessId;
+
+        public LmLogger(LmLog log, ulong clientProcessId)
+        {
+            _log = log;
+            _clientProcessId = clientProcessId;
+        }
+
+        [CmifCommand(0)]
+        public Result Log([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] Span<byte> message)
+        {
+            if (!SetProcessId(message, _clientProcessId))
+            {
+                return Result.Success;
+            }
+
+            Logger.Guest?.Print(LogClass.ServiceLm, LogImpl(message));
+
+            return Result.Success;
+        }
+
+        [CmifCommand(1)]
+        public Result SetDestination(LogDestination destination)
+        {
+            _log.LogDestination = destination;
+
+            return Result.Success;
+        }
+
+        private static bool SetProcessId(Span<byte> message, ulong processId)
+        {
+            ref LogPacketHeader header = ref MemoryMarshal.Cast<byte, LogPacketHeader>(message)[0];
+
+            uint expectedMessageSize = (uint)Unsafe.SizeOf<LogPacketHeader>() + header.PayloadSize;
+
+            if (expectedMessageSize != (uint)message.Length)
+            {
+                Logger.Warning?.Print(LogClass.ServiceLm, $"Invalid message size (expected 0x{expectedMessageSize:X} but got 0x{message.Length:X}).");
+
+                return false;
+            }
+
+            header.ProcessId = processId;
+
+            return true;
+        }
+
+        private static string LogImpl(ReadOnlySpan<byte> message)
+        {
+            SpanReader reader = new SpanReader(message);
+
+            LogPacketHeader header = reader.Read<LogPacketHeader>();
+
+            StringBuilder sb = new StringBuilder();
+
+            sb.AppendLine($"Guest Log:\n  Log level: {header.Severity}");
+
+            while (reader.Length > 0)
+            {
+                int type = ReadUleb128(ref reader);
+                int size = ReadUleb128(ref reader);
+
+                LogDataChunkKey field = (LogDataChunkKey)type;
+
+                string fieldStr = string.Empty;
+
+                if (field == LogDataChunkKey.Start)
+                {
+                    reader.Skip(size);
+
+                    continue;
+                }
+                else if (field == LogDataChunkKey.Stop)
+                {
+                    break;
+                }
+                else if (field == LogDataChunkKey.Line)
+                {
+                    fieldStr = $"{field}: {reader.Read<int>()}";
+                }
+                else if (field == LogDataChunkKey.DropCount)
+                {
+                    fieldStr = $"{field}: {reader.Read<long>()}";
+                }
+                else if (field == LogDataChunkKey.Time)
+                {
+                    fieldStr = $"{field}: {reader.Read<long>()}s";
+                }
+                else if (field < LogDataChunkKey.Count)
+                {
+                    fieldStr = $"{field}: '{Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd()}'";
+                }
+                else
+                {
+                    fieldStr = $"Field{field}: '{Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd()}'";
+                }
+
+                sb.AppendLine($"    {fieldStr}");
+            }
+
+            return sb.ToString();
+        }
+
+        private static int ReadUleb128(ref SpanReader reader)
+        {
+            int result = 0;
+            int count = 0;
+
+            byte encoded;
+
+            do
+            {
+                encoded = reader.Read<byte>();
+
+                result += (encoded & 0x7F) << (7 * count);
+
+                count++;
+            } while ((encoded & 0x80) != 0);
+
+            return result;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/LogManager/LmMain.cs b/Ryujinx.Horizon/LogManager/LmMain.cs
new file mode 100644
index 0000000000..8c0262ac67
--- /dev/null
+++ b/Ryujinx.Horizon/LogManager/LmMain.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.Horizon.LogManager
+{
+    class LmMain : IService
+    {
+        public static void Main()
+        {
+            LmIpcServer ipcServer = new LmIpcServer();
+
+            ipcServer.Initialize();
+            ipcServer.ServiceRequests();
+            ipcServer.Shutdown();
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Ryujinx.Horizon.csproj b/Ryujinx.Horizon/Ryujinx.Horizon.csproj
new file mode 100644
index 0000000000..e4591c6f93
--- /dev/null
+++ b/Ryujinx.Horizon/Ryujinx.Horizon.csproj
@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
+    <ProjectReference Include="..\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj" />
+    <ProjectReference Include="..\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+    <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
+  </ItemGroup>
+
+</Project>
diff --git a/Ryujinx.Horizon/Sdk/DebugUtil.cs b/Ryujinx.Horizon/Sdk/DebugUtil.cs
new file mode 100644
index 0000000000..f56a50ec57
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/DebugUtil.cs
@@ -0,0 +1,12 @@
+using System.Diagnostics;
+
+namespace Ryujinx.Horizon.Sdk
+{
+    static class DebugUtil
+    {
+        public static void Assert(bool condition)
+        {
+            Debug.Assert(condition);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Diag/LogSeverity.cs b/Ryujinx.Horizon/Sdk/Diag/LogSeverity.cs
new file mode 100644
index 0000000000..72acf7896f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Diag/LogSeverity.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Horizon.Sdk.Diag
+{
+    enum LogSeverity : byte
+    {
+        Trace = 0,
+        Info = 1,
+        Warn = 2,
+        Error = 3,
+        Fatal = 4
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Horizon/Sdk/Lm/LogDataChunkKey.cs b/Ryujinx.Horizon/Sdk/Lm/LogDataChunkKey.cs
new file mode 100644
index 0000000000..90756ece2e
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Lm/LogDataChunkKey.cs
@@ -0,0 +1,19 @@
+namespace Ryujinx.Horizon.Sdk.Lm
+{
+    enum LogDataChunkKey
+    {
+        Start = 0,
+        Stop = 1,
+        Message = 2,
+        Line = 3,
+        Filename = 4,
+        Function = 5,
+        Module = 6,
+        Thread = 7,
+        DropCount = 8,
+        Time = 9,
+        ProgramName = 10,
+
+        Count
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Horizon/Sdk/Lm/LogDestination.cs b/Ryujinx.Horizon/Sdk/Lm/LogDestination.cs
new file mode 100644
index 0000000000..8b08548d6e
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Lm/LogDestination.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Lm
+{
+    [Flags]
+    enum LogDestination
+    {
+        TargetManager = 1 << 0,
+        Uart = 1 << 1,
+        UartIfSleep = 1 << 2,
+
+        All = 0xffff
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Lm/LogPacketFlags.cs b/Ryujinx.Horizon/Sdk/Lm/LogPacketFlags.cs
new file mode 100644
index 0000000000..75d9f40b9b
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Lm/LogPacketFlags.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Lm
+{
+    [Flags]
+    enum LogPacketFlags : byte
+    {
+        IsHead = 1 << 0,
+        IsTail = 1 << 1,
+        IsLittleEndian = 1 << 2
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Lm/LogPacketHeader.cs b/Ryujinx.Horizon/Sdk/Lm/LogPacketHeader.cs
new file mode 100644
index 0000000000..022ba8dade
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Lm/LogPacketHeader.cs
@@ -0,0 +1,15 @@
+using Ryujinx.Horizon.Sdk.Diag;
+
+namespace Ryujinx.Horizon.Sdk.Lm
+{
+    struct LogPacketHeader
+    {
+        public ulong ProcessId;
+        public ulong ThreadId;
+        public LogPacketFlags Flags;
+        public byte Padding;
+        public LogSeverity Severity;
+        public byte Verbosity;
+        public uint PayloadSize;
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Event.cs b/Ryujinx.Horizon/Sdk/OsTypes/Event.cs
new file mode 100644
index 0000000000..79d7408e31
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/Event.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    class Event : IDisposable
+    {
+        private EventType _event;
+
+        public object EventLock => _event.Lock;
+        public LinkedList<MultiWaitHolderBase> MultiWaitHolders => _event.MultiWaitHolders;
+
+        public Event(EventClearMode clearMode)
+        {
+            Os.InitializeEvent(out _event, signaled: false, clearMode);
+        }
+
+        public TriBool IsSignaledThreadUnsafe()
+        {
+            return _event.Signaled ? TriBool.True : TriBool.False;
+        }
+
+        public void Wait()
+        {
+            Os.WaitEvent(ref _event);
+        }
+
+        public bool TryWait()
+        {
+            return Os.TryWaitEvent(ref _event);
+        }
+
+        public bool TimedWait(TimeSpan timeout)
+        {
+            return Os.TimedWaitEvent(ref _event, timeout);
+        }
+
+        public void Signal()
+        {
+            Os.SignalEvent(ref _event);
+        }
+
+        public void Clear()
+        {
+            Os.ClearEvent(ref _event);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                Os.FinalizeEvent(ref _event);
+            }
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs b/Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs
new file mode 100644
index 0000000000..b500e6b3ce
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    enum EventClearMode
+    {
+        ManualClear,
+        AutoClear
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/EventType.cs b/Ryujinx.Horizon/Sdk/OsTypes/EventType.cs
new file mode 100644
index 0000000000..b4b1a275c7
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/EventType.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    struct EventType
+    {
+        public LinkedList<MultiWaitHolderBase> MultiWaitHolders;
+        public bool Signaled;
+        public bool InitiallySignaled;
+        public EventClearMode ClearMode;
+        public InitializationState State;
+        public ulong BroadcastCounter;
+        public object Lock;
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs
new file mode 100644
index 0000000000..62b5bf066d
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs
@@ -0,0 +1,89 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes.Impl
+{
+    static class InterProcessEvent
+    {
+        public static Result Create(ref InterProcessEventType ipEvent, EventClearMode clearMode)
+        {
+            Result result = InterProcessEventImpl.Create(out int writableHandle, out int readableHandle);
+
+            if (result != Result.Success)
+            {
+                return result;
+            }
+
+            ipEvent = new InterProcessEventType(
+                clearMode == EventClearMode.AutoClear,
+                true,
+                true,
+                readableHandle,
+                writableHandle);
+
+            return Result.Success;
+        }
+
+        public static void Destroy(ref InterProcessEventType ipEvent)
+        {
+            ipEvent.State = InitializationState.NotInitialized;
+
+            if (ipEvent.ReadableHandleManaged)
+            {
+                if (ipEvent.ReadableHandle != 0)
+                {
+                    InterProcessEventImpl.Close(ipEvent.ReadableHandle);
+                }
+                ipEvent.ReadableHandleManaged = false;
+            }
+
+            if (ipEvent.WritableHandleManaged)
+            {
+                if (ipEvent.WritableHandle != 0)
+                {
+                    InterProcessEventImpl.Close(ipEvent.WritableHandle);
+                }
+                ipEvent.WritableHandleManaged = false;
+            }
+        }
+
+        public static int DetachReadableHandle(ref InterProcessEventType ipEvent)
+        {
+            int handle = ipEvent.ReadableHandle;
+
+            ipEvent.ReadableHandle = 0;
+            ipEvent.ReadableHandleManaged = false;
+
+            return handle;
+        }
+
+        public static int DetachWritableHandle(ref InterProcessEventType ipEvent)
+        {
+            int handle = ipEvent.WritableHandle;
+
+            ipEvent.WritableHandle = 0;
+            ipEvent.WritableHandleManaged = false;
+
+            return handle;
+        }
+
+        public static int GetReadableHandle(ref InterProcessEventType ipEvent)
+        {
+            return ipEvent.ReadableHandle;
+        }
+
+        public static int GetWritableHandle(ref InterProcessEventType ipEvent)
+        {
+            return ipEvent.WritableHandle;
+        }
+
+        public static void Signal(ref InterProcessEventType ipEvent)
+        {
+            InterProcessEventImpl.Signal(ipEvent.WritableHandle);
+        }
+
+        public static void Clear(ref InterProcessEventType ipEvent)
+        {
+            InterProcessEventImpl.Clear(ipEvent.ReadableHandle == 0 ? ipEvent.WritableHandle : ipEvent.ReadableHandle);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs
new file mode 100644
index 0000000000..a8aeacc920
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs
@@ -0,0 +1,136 @@
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes.Impl
+{
+    static class InterProcessEventImpl
+    {
+        public static Result Create(out int writableHandle, out int readableHandle)
+        {
+            Result result = HorizonStatic.Syscall.CreateEvent(out writableHandle, out readableHandle);
+
+            if (result == KernelResult.OutOfResource)
+            {
+                return OsResult.OutOfResource;
+            }
+
+            result.AbortOnFailure();
+
+            return Result.Success;
+        }
+
+        public static void Close(int handle)
+        {
+            if (handle != 0)
+            {
+                HorizonStatic.Syscall.CloseHandle(handle).AbortOnFailure();
+            }
+        }
+
+        public static void Signal(int handle)
+        {
+            HorizonStatic.Syscall.SignalEvent(handle).AbortOnFailure();
+        }
+
+        public static void Clear(int handle)
+        {
+            HorizonStatic.Syscall.ClearEvent(handle).AbortOnFailure();
+        }
+
+        public static void Wait(int handle, bool autoClear)
+        {
+            Span<int> handles = stackalloc int[1];
+
+            handles[0] = handle;
+
+            while (true)
+            {
+                Result result = HorizonStatic.Syscall.WaitSynchronization(out _, handles, -1L);
+
+                if (result == Result.Success)
+                {
+                    if (autoClear)
+                    {
+                        result = HorizonStatic.Syscall.ResetSignal(handle);
+
+                        if (result == KernelResult.InvalidState)
+                        {
+                            continue;
+                        }
+
+                        result.AbortOnFailure();
+                    }
+
+                    return;
+                }
+
+                result.AbortUnless(KernelResult.Cancelled);
+            }
+        }
+
+        public static bool TryWait(int handle, bool autoClear)
+        {
+            if (autoClear)
+            {
+                return HorizonStatic.Syscall.ResetSignal(handle) == Result.Success;
+            }
+
+            Span<int> handles = stackalloc int[1];
+
+            handles[0] = handle;
+
+            while (true)
+            {
+                Result result = HorizonStatic.Syscall.WaitSynchronization(out _, handles, 0);
+
+                if (result == Result.Success)
+                {
+                    return true;
+                }
+                else if (result == KernelResult.TimedOut)
+                {
+                    return false;
+                }
+
+                result.AbortUnless(KernelResult.Cancelled);
+            }
+        }
+
+        public static bool TimedWait(int handle, bool autoClear, TimeSpan timeout)
+        {
+            Span<int> handles = stackalloc int[1];
+
+            handles[0] = handle;
+
+            long timeoutNs = timeout.Milliseconds * 1000000L;
+
+            while (true)
+            {
+                Result result = HorizonStatic.Syscall.WaitSynchronization(out _, handles, timeoutNs);
+
+                if (result == Result.Success)
+                {
+                    if (autoClear)
+                    {
+                        result = HorizonStatic.Syscall.ResetSignal(handle);
+
+                        if (result == KernelResult.InvalidState)
+                        {
+                            continue;
+                        }
+
+                        result.AbortOnFailure();
+                    }
+
+                    return true;
+                }
+                else if (result == KernelResult.TimedOut)
+                {
+                    return false;
+                }
+
+                result.AbortUnless(KernelResult.Cancelled);
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs b/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs
new file mode 100644
index 0000000000..fd45792d70
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs
@@ -0,0 +1,250 @@
+using Ryujinx.Common;
+using Ryujinx.Horizon.Common;
+using System.Collections.Generic;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes.Impl
+{
+    class MultiWaitImpl
+    {
+        private const int WaitTimedOut  = -1;
+        private const int WaitCancelled = -2;
+        private const int WaitInvalid   = -3;
+
+        private readonly List<MultiWaitHolderBase> _multiWaits;
+
+        private object _lock;
+
+        private int _waitingThreadHandle;
+
+        private MultiWaitHolderBase _signaledHolder;
+
+        public long CurrentTime { get; private set; }
+
+        public MultiWaitImpl()
+        {
+            _multiWaits = new List<MultiWaitHolderBase>();
+
+            _lock = new object();
+        }
+
+        public void LinkMultiWaitHolder(MultiWaitHolderBase multiWaitHolder)
+        {
+            _multiWaits.Add(multiWaitHolder);
+        }
+
+        public void UnlinkMultiWaitHolder(MultiWaitHolderBase multiWaitHolder)
+        {
+            _multiWaits.Remove(multiWaitHolder);
+        }
+
+        public void MoveAllFrom(MultiWaitImpl other)
+        {
+            foreach (MultiWaitHolderBase multiWait in other._multiWaits)
+            {
+                multiWait.SetMultiWait(this);
+            }
+
+            _multiWaits.AddRange(other._multiWaits);
+
+            other._multiWaits.Clear();
+        }
+
+        public MultiWaitHolderBase WaitAnyImpl(bool infinite, long timeout)
+        {
+            _signaledHolder = null;
+            _waitingThreadHandle = Os.GetCurrentThreadHandle();
+
+            MultiWaitHolderBase result = LinkHoldersToObjectList();
+
+            lock (_lock)
+            {
+                if (_signaledHolder != null)
+                {
+                    result = _signaledHolder;
+                }
+            }
+
+            if (result == null)
+            {
+                result = WaitAnyHandleImpl(infinite, timeout);
+            }
+
+            UnlinkHoldersFromObjectsList();
+            _waitingThreadHandle = 0;
+
+            return result;
+        }
+
+        private MultiWaitHolderBase WaitAnyHandleImpl(bool infinite, long timeout)
+        {
+            Span<int> objectHandles = new int[64];
+
+            Span<MultiWaitHolderBase> objects = new MultiWaitHolderBase[64];
+
+            int count = FillObjectsArray(objectHandles, objects);
+
+            long endTime = infinite ? long.MaxValue : PerformanceCounter.ElapsedMilliseconds * 1000000;
+
+            while (true)
+            {
+                CurrentTime = PerformanceCounter.ElapsedMilliseconds * 1000000;
+
+                MultiWaitHolderBase minTimeoutObject = RecalcMultiWaitTimeout(endTime, out long minTimeout);
+
+                int index;
+
+                if (count == 0 && minTimeout == 0)
+                {
+                    index = WaitTimedOut;
+                }
+                else
+                {
+                    index = WaitSynchronization(objectHandles.Slice(0, count), minTimeout);
+
+                    DebugUtil.Assert(index != WaitInvalid);
+                }
+
+                switch (index)
+                {
+                    case WaitTimedOut:
+                        if (minTimeoutObject != null)
+                        {
+                            CurrentTime = PerformanceCounter.ElapsedMilliseconds * 1000000;
+
+                            if (minTimeoutObject.Signaled == TriBool.True)
+                            {
+                                lock (_lock)
+                                {
+                                    _signaledHolder = minTimeoutObject;
+
+                                    return _signaledHolder;
+                                }
+                            }
+                        }
+                        else
+                        {
+                            return null;
+                        }
+                        break;
+                    case WaitCancelled:
+                        lock (_lock)
+                        {
+                            if (_signaledHolder != null)
+                            {
+                                return _signaledHolder;
+                            }
+                        }
+                        break;
+                    default:
+                        lock (_lock)
+                        {
+                            _signaledHolder = objects[index];
+
+                            return _signaledHolder;
+                        }
+                }
+            }
+        }
+
+        private int FillObjectsArray(Span<int> handles, Span<MultiWaitHolderBase> objects)
+        {
+            int count = 0;
+
+            foreach (MultiWaitHolderBase holder in _multiWaits)
+            {
+                int handle = holder.Handle;
+
+                if (handle != 0)
+                {
+                    handles[count] = handle;
+                    objects[count] = holder;
+
+                    count++;
+                }
+            }
+
+            return count;
+        }
+
+        private MultiWaitHolderBase RecalcMultiWaitTimeout(long endTime, out long minTimeout)
+        {
+            MultiWaitHolderBase minTimeHolder = null;
+
+            long minTime = endTime;
+
+            foreach (MultiWaitHolder holder in _multiWaits)
+            {
+                long currentTime = holder.GetAbsoluteTimeToWakeup();
+
+                if ((ulong)currentTime < (ulong)minTime)
+                {
+                    minTimeHolder = holder;
+
+                    minTime = currentTime;
+                }
+            }
+
+            minTimeout = (ulong)minTime < (ulong)CurrentTime ? 0 : minTime - CurrentTime;
+
+            return minTimeHolder;
+        }
+
+        private static int WaitSynchronization(ReadOnlySpan<int> handles, long timeout)
+        {
+            Result result = HorizonStatic.Syscall.WaitSynchronization(out int index, handles, timeout);
+
+            if (result == KernelResult.TimedOut)
+            {
+                return WaitTimedOut;
+            }
+            else if (result == KernelResult.Cancelled)
+            {
+                return WaitCancelled;
+            }
+            else
+            {
+                result.AbortOnFailure();
+            }
+
+            return index;
+        }
+
+        public void NotifyAndWakeUpThread(MultiWaitHolderBase holder)
+        {
+            lock (_lock)
+            {
+                if (_signaledHolder == null)
+                {
+                    _signaledHolder = holder;
+                    HorizonStatic.Syscall.CancelSynchronization(_waitingThreadHandle).AbortOnFailure();
+                }
+            }
+        }
+
+        private MultiWaitHolderBase LinkHoldersToObjectList()
+        {
+            MultiWaitHolderBase signaledHolder = null;
+
+            foreach (MultiWaitHolderBase holder in _multiWaits)
+            {
+                TriBool isSignaled = holder.LinkToObjectList();
+
+                if (signaledHolder == null && isSignaled == TriBool.True)
+                {
+                    signaledHolder = holder;
+                }
+            }
+
+            return signaledHolder;
+        }
+
+        private void UnlinkHoldersFromObjectsList()
+        {
+            foreach (MultiWaitHolderBase holder in _multiWaits)
+            {
+                holder.UnlinkFromObjectList();
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs b/Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs
new file mode 100644
index 0000000000..45ffd2587e
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    enum InitializationState : byte
+    {
+        NotInitialized,
+        Initialized
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs b/Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs
new file mode 100644
index 0000000000..5f6824fea3
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs
@@ -0,0 +1,27 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    struct InterProcessEventType
+    {
+        public readonly bool AutoClear;
+        public InitializationState State;
+        public bool ReadableHandleManaged;
+        public bool WritableHandleManaged;
+        public int ReadableHandle;
+        public int WritableHandle;
+
+        public InterProcessEventType(
+            bool autoClear,
+            bool readableHandleManaged,
+            bool writableHandleManaged,
+            int readableHandle,
+            int writableHandle)
+        {
+            AutoClear = autoClear;
+            State = InitializationState.Initialized;
+            ReadableHandleManaged = readableHandleManaged;
+            WritableHandleManaged = writableHandleManaged;
+            ReadableHandle = readableHandle;
+            WritableHandle = writableHandle;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs
new file mode 100644
index 0000000000..5a91f6c36b
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs
@@ -0,0 +1,43 @@
+using Ryujinx.Horizon.Sdk.OsTypes.Impl;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    class MultiWait
+    {
+        private readonly MultiWaitImpl _impl;
+
+        public MultiWait()
+        {
+            _impl = new MultiWaitImpl();
+        }
+
+        public void LinkMultiWaitHolder(MultiWaitHolderBase multiWaitHolder)
+        {
+            DebugUtil.Assert(!multiWaitHolder.IsLinked);
+
+            _impl.LinkMultiWaitHolder(multiWaitHolder);
+
+            multiWaitHolder.SetMultiWait(_impl);
+        }
+
+        public void MoveAllFrom(MultiWait other)
+        {
+            _impl.MoveAllFrom(other._impl);
+        }
+
+        public MultiWaitHolder WaitAny()
+        {
+            return (MultiWaitHolder)_impl.WaitAnyImpl(true, -1L);
+        }
+
+        public MultiWaitHolder TryWaitAny()
+        {
+            return (MultiWaitHolder)_impl.WaitAnyImpl(false, 0);
+        }
+
+        public MultiWaitHolder TimedWaitAny(long timeout)
+        {
+            return (MultiWaitHolder)_impl.WaitAnyImpl(false, timeout);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs
new file mode 100644
index 0000000000..a24b19064f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs
@@ -0,0 +1,16 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    class MultiWaitHolder : MultiWaitHolderBase
+    {
+        public object UserData { get; set; }
+
+        public void UnlinkFromMultiWaitHolder()
+        {
+            DebugUtil.Assert(IsLinked);
+
+            MultiWait.UnlinkMultiWaitHolder(this);
+
+            SetMultiWait(null);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs
new file mode 100644
index 0000000000..018305ba6c
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs
@@ -0,0 +1,39 @@
+using Ryujinx.Horizon.Sdk.OsTypes.Impl;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    class MultiWaitHolderBase
+    {
+        protected MultiWaitImpl MultiWait;
+
+        public bool IsLinked => MultiWait != null;
+
+        public virtual TriBool Signaled => TriBool.False;
+
+        public virtual int Handle => 0;
+
+        public void SetMultiWait(MultiWaitImpl multiWait)
+        {
+            MultiWait = multiWait;
+        }
+
+        public MultiWaitImpl GetMultiWait()
+        {
+            return MultiWait;
+        }
+
+        public virtual TriBool LinkToObjectList()
+        {
+            return TriBool.Undefined;
+        }
+
+        public virtual void UnlinkFromObjectList()
+        {
+        }
+
+        public virtual long GetAbsoluteTimeToWakeup()
+        {
+            return long.MaxValue;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs
new file mode 100644
index 0000000000..37ac22f0bd
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    class MultiWaitHolderOfEvent : MultiWaitHolder
+    {
+        private Event _event;
+        private LinkedListNode<MultiWaitHolderBase> _node;
+
+        public override TriBool Signaled
+        {
+            get
+            {
+                lock (_event.EventLock)
+                {
+                    return _event.IsSignaledThreadUnsafe();
+                }
+            }
+        }
+
+        public MultiWaitHolderOfEvent(Event evnt)
+        {
+            _event = evnt;
+        }
+
+        public override TriBool LinkToObjectList()
+        {
+            lock (_event.EventLock)
+            {
+                _node = _event.MultiWaitHolders.AddLast(this);
+
+                return _event.IsSignaledThreadUnsafe();
+            }
+        }
+
+        public override void UnlinkFromObjectList()
+        {
+            lock (_event.EventLock)
+            {
+                _event.MultiWaitHolders.Remove(_node);
+                _node = null;
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs
new file mode 100644
index 0000000000..6fc5c75b9e
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    class MultiWaitHolderOfHandle : MultiWaitHolder
+    {
+        private int _handle;
+
+        public override int Handle => _handle;
+
+        public MultiWaitHolderOfHandle(int handle)
+        {
+            _handle = handle;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs
new file mode 100644
index 0000000000..cc7e848368
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    static partial class Os
+    {
+        public static void InitializeEvent(out EventType evnt, bool signaled, EventClearMode clearMode)
+        {
+            evnt = new EventType
+            {
+                MultiWaitHolders = new LinkedList<MultiWaitHolderBase>(),
+                Signaled = signaled,
+                InitiallySignaled = signaled,
+                ClearMode = clearMode,
+                State = InitializationState.Initialized,
+                Lock = new object()
+            };
+        }
+
+        public static void FinalizeEvent(ref EventType evnt)
+        {
+            evnt.State = InitializationState.NotInitialized;
+        }
+
+        public static void WaitEvent(ref EventType evnt)
+        {
+            lock (evnt.Lock)
+            {
+                ulong currentCounter = evnt.BroadcastCounter;
+
+                while (!evnt.Signaled)
+                {
+                    if (currentCounter != evnt.BroadcastCounter)
+                    {
+                        break;
+                    }
+
+                    Monitor.Wait(evnt.Lock);
+                }
+
+                if (evnt.ClearMode == EventClearMode.AutoClear)
+                {
+                    evnt.Signaled = false;
+                }
+            }
+        }
+
+        public static bool TryWaitEvent(ref EventType evnt)
+        {
+            lock (evnt.Lock)
+            {
+                bool signaled = evnt.Signaled;
+
+                if (evnt.ClearMode == EventClearMode.AutoClear)
+                {
+                    evnt.Signaled = false;
+                }
+
+                return signaled;
+            }
+        }
+
+        public static bool TimedWaitEvent(ref EventType evnt, TimeSpan timeout)
+        {
+            lock (evnt.Lock)
+            {
+                ulong currentCounter = evnt.BroadcastCounter;
+
+                while (!evnt.Signaled)
+                {
+                    if (currentCounter != evnt.BroadcastCounter)
+                    {
+                        break;
+                    }
+
+                    bool wasSignaledInTime = Monitor.Wait(evnt.Lock, timeout);
+                    if (!wasSignaledInTime)
+                    {
+                        return false;
+                    }
+                }
+
+                if (evnt.ClearMode == EventClearMode.AutoClear)
+                {
+                    evnt.Signaled = false;
+                }
+            }
+
+            return true;
+        }
+
+        public static void SignalEvent(ref EventType evnt)
+        {
+            lock (evnt.Lock)
+            {
+                if (evnt.Signaled)
+                {
+                    return;
+                }
+
+                evnt.Signaled = true;
+
+                if (evnt.ClearMode == EventClearMode.ManualClear)
+                {
+                    evnt.BroadcastCounter++;
+                    Monitor.PulseAll(evnt.Lock);
+                }
+                else
+                {
+                    Monitor.Pulse(evnt.Lock);
+                }
+
+                foreach (MultiWaitHolderBase holder in evnt.MultiWaitHolders)
+                {
+                    holder.GetMultiWait().NotifyAndWakeUpThread(holder);
+                }
+            }
+        }
+
+        public static void ClearEvent(ref EventType evnt)
+        {
+            lock (evnt.Lock)
+            {
+                evnt.Signaled = false;
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs
new file mode 100644
index 0000000000..827de23138
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    static partial class Os
+    {
+        public static void FinalizeMultiWaitHolder(MultiWaitHolderBase holder)
+        {
+            DebugUtil.Assert(!holder.IsLinked);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs
new file mode 100644
index 0000000000..6a6d9bf23d
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs
@@ -0,0 +1,33 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    static partial class Os
+    {
+        private const int SelfProcessHandle = (0x1ffff << 15) | 1;
+
+        public static int GetCurrentProcessHandle()
+        {
+            return SelfProcessHandle;
+        }
+
+        public static ulong GetCurrentProcessId()
+        {
+            return GetProcessId(GetCurrentProcessHandle());
+        }
+
+        private static ulong GetProcessId(int handle)
+        {
+            Result result = TryGetProcessId(handle, out ulong pid);
+
+            result.AbortOnFailure();
+
+            return pid;
+        }
+
+        private static Result TryGetProcessId(int handle, out ulong pid)
+        {
+            return HorizonStatic.Syscall.GetProcessId(out pid, handle);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs
new file mode 100644
index 0000000000..86dcd1fad9
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs
@@ -0,0 +1,11 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    static class OsResult
+    {
+        private const int ModuleId = 3;
+
+        public static Result OutOfResource => new Result(ModuleId, 9);
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs
new file mode 100644
index 0000000000..061d7a3cd1
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs
@@ -0,0 +1,85 @@
+using Ryujinx.Horizon.Sdk.OsTypes.Impl;
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    static partial class Os
+    {
+        public static Result CreateSystemEvent(out SystemEventType sysEvent, EventClearMode clearMode, bool interProcess)
+        {
+            sysEvent = new SystemEventType();
+
+            if (interProcess)
+            {
+                Result result = InterProcessEvent.Create(ref sysEvent.InterProcessEvent, clearMode);
+
+                if (result != Result.Success)
+                {
+                    return result;
+                }
+
+                sysEvent.State = SystemEventType.InitializationState.InitializedAsInterProcess;
+            }
+            else
+            {
+                throw new NotImplementedException();
+            }
+
+            return Result.Success;
+        }
+
+        public static void DestroySystemEvent(ref SystemEventType sysEvent)
+        {
+            var oldState = sysEvent.State;
+            sysEvent.State = SystemEventType.InitializationState.NotInitialized;
+
+            switch (oldState)
+            {
+                case SystemEventType.InitializationState.InitializedAsInterProcess:
+                    InterProcessEvent.Destroy(ref sysEvent.InterProcessEvent);
+                    break;
+            }
+        }
+
+        public static int DetachReadableHandleOfSystemEvent(ref SystemEventType sysEvent)
+        {
+            return InterProcessEvent.DetachReadableHandle(ref sysEvent.InterProcessEvent);
+        }
+
+        public static int DetachWritableHandleOfSystemEvent(ref SystemEventType sysEvent)
+        {
+            return InterProcessEvent.DetachWritableHandle(ref sysEvent.InterProcessEvent);
+        }
+
+        public static int GetReadableHandleOfSystemEvent(ref SystemEventType sysEvent)
+        {
+            return InterProcessEvent.GetReadableHandle(ref sysEvent.InterProcessEvent);
+        }
+
+        public static int GetWritableHandleOfSystemEvent(ref SystemEventType sysEvent)
+        {
+            return InterProcessEvent.GetWritableHandle(ref sysEvent.InterProcessEvent);
+        }
+
+        public static void SignalSystemEvent(ref SystemEventType sysEvent)
+        {
+            switch (sysEvent.State)
+            {
+                case SystemEventType.InitializationState.InitializedAsInterProcess:
+                    InterProcessEvent.Signal(ref sysEvent.InterProcessEvent);
+                    break;
+            }
+        }
+
+        public static void ClearSystemEvent(ref SystemEventType sysEvent)
+        {
+            switch (sysEvent.State)
+            {
+                case SystemEventType.InitializationState.InitializedAsInterProcess:
+                    InterProcessEvent.Clear(ref sysEvent.InterProcessEvent);
+                    break;
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs
new file mode 100644
index 0000000000..2037cd7fe1
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    static partial class Os
+    {
+        public static int GetCurrentThreadHandle()
+        {
+            return HorizonStatic.CurrentThreadHandle;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs b/Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs
new file mode 100644
index 0000000000..338493d237
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs
@@ -0,0 +1,17 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    struct SystemEventType
+    {
+        public enum InitializationState : byte
+        {
+            NotInitialized,
+            InitializedAsEvent,
+            InitializedAsInterProcess
+        }
+
+        public InterProcessEventType InterProcessEvent;
+        public InitializationState State;
+
+        public bool NotInitialized => State == InitializationState.NotInitialized;
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs b/Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs
new file mode 100644
index 0000000000..7debd9e27f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+    enum TriBool
+    {
+        False,
+        True,
+        Undefined
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/ServiceUtil.cs b/Ryujinx.Horizon/Sdk/ServiceUtil.cs
new file mode 100644
index 0000000000..413ac1f6b7
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/ServiceUtil.cs
@@ -0,0 +1,38 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Sdk
+{
+    static class ServiceUtil
+    {
+        public static Result SendRequest(out CmifResponse response, int sessionHandle, uint requestId, bool sendPid, scoped ReadOnlySpan<byte> data)
+        {
+            ulong tlsAddress = HorizonStatic.ThreadContext.TlsAddress;
+            int tlsSize = Api.TlsMessageBufferSize;
+
+            using (var tlsRegion = HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize))
+            {
+                CmifRequest request = CmifMessage.CreateRequest(tlsRegion.Memory.Span, new CmifRequestFormat()
+                {
+                    DataSize = data.Length,
+                    RequestId = requestId,
+                    SendPid = sendPid
+                });
+
+                data.CopyTo(request.Data);
+            }
+
+            Result result = HorizonStatic.Syscall.SendSyncRequest(sessionHandle);
+
+            if (result.IsFailure)
+            {
+                response = default;
+                return result;
+            }
+
+            return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainInHeader.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainInHeader.cs
new file mode 100644
index 0000000000..8821150139
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainInHeader.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    struct CmifDomainInHeader
+    {
+        public CmifDomainRequestType Type;
+        public byte ObjectsCount;
+        public ushort DataSize;
+        public int ObjectId;
+        public uint Padding;
+        public uint Token;
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainOutHeader.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainOutHeader.cs
new file mode 100644
index 0000000000..2086d24c17
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainOutHeader.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    struct CmifDomainOutHeader
+    {
+#pragma warning disable CS0649
+        public uint ObjectsCount;
+        public uint Padding;
+        public uint Padding2;
+        public uint Padding3;
+#pragma warning restore CS0649
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainRequestType.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainRequestType.cs
new file mode 100644
index 0000000000..b913db94e0
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainRequestType.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    enum CmifDomainRequestType : byte
+    {
+        Invalid = 0,
+        SendMessage = 1,
+        Close = 2
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifInHeader.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifInHeader.cs
new file mode 100644
index 0000000000..55b859fcaf
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifInHeader.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    struct CmifInHeader
+    {
+        public uint Magic;
+        public uint Version;
+        public uint CommandId;
+        public uint Token;
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifMessage.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifMessage.cs
new file mode 100644
index 0000000000..781452e309
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifMessage.cs
@@ -0,0 +1,128 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    static class CmifMessage
+    {
+        public const uint CmifInHeaderMagic = 0x49434653; // SFCI
+        public const uint CmifOutHeaderMagic = 0x4f434653; // SFCO
+
+        public static CmifRequest CreateRequest(Span<byte> output, CmifRequestFormat format)
+        {
+            int totalSize = 16;
+
+            if (format.ObjectId != 0)
+            {
+                totalSize += Unsafe.SizeOf<CmifDomainInHeader>() + format.ObjectsCount * sizeof(int);
+            }
+
+            totalSize += Unsafe.SizeOf<CmifInHeader>() + format.DataSize;
+            totalSize = (totalSize + 1) & ~1;
+            int outPointerSizeTableOffset = totalSize;
+            int outPointerSizeTableSize = format.OutAutoBuffersCount + format.OutPointersCount;
+            totalSize += sizeof(ushort) * outPointerSizeTableSize;
+            int rawDataSizeInWords = (totalSize + sizeof(uint) - 1) / sizeof(uint);
+
+            CmifRequest request = new CmifRequest();
+
+            request.Hipc = HipcMessage.WriteMessage(output, new HipcMetadata()
+            {
+                Type = format.Context != 0 ? (int)CommandType.RequestWithContext : (int)CommandType.Request,
+                SendStaticsCount = format.InAutoBuffersCount + format.InPointersCount,
+                SendBuffersCount = format.InAutoBuffersCount + format.InBuffersCount,
+                ReceiveBuffersCount = format.OutAutoBuffersCount + format.OutBuffersCount,
+                ExchangeBuffersCount = format.InOutBuffersCount,
+                DataWordsCount = rawDataSizeInWords,
+                ReceiveStaticsCount = outPointerSizeTableSize + format.OutFixedPointersCount,
+                SendPid = format.SendPid,
+                CopyHandlesCount = format.HandlesCount,
+                MoveHandlesCount = 0
+            });
+
+            Span<uint> data = request.Hipc.DataWords;
+
+            if (format.ObjectId != 0)
+            {
+                ref CmifDomainInHeader domainHeader = ref MemoryMarshal.Cast<uint, CmifDomainInHeader>(data)[0];
+
+                int payloadSize = Unsafe.SizeOf<CmifInHeader>() + format.DataSize;
+
+                domainHeader = new CmifDomainInHeader()
+                {
+                    Type = CmifDomainRequestType.SendMessage,
+                    ObjectsCount = (byte)format.ObjectsCount,
+                    DataSize = (ushort)payloadSize,
+                    ObjectId = format.ObjectId,
+                    Padding = 0,
+                    Token = format.Context
+                };
+
+                data = data.Slice(Unsafe.SizeOf<CmifDomainInHeader>() / sizeof(uint));
+
+                request.Objects = data.Slice((payloadSize + sizeof(uint) - 1) / sizeof(uint));
+            }
+
+            ref CmifInHeader header = ref MemoryMarshal.Cast<uint, CmifInHeader>(data)[0];
+
+            header = new CmifInHeader()
+            {
+                Magic = CmifInHeaderMagic,
+                Version = format.Context != 0 ? 1u : 0u,
+                CommandId = format.RequestId,
+                Token = format.ObjectId != 0 ? 0u : format.Context
+            };
+
+            request.Data = MemoryMarshal.Cast<uint, byte>(data).Slice(Unsafe.SizeOf<CmifInHeader>());
+
+            int paddingSizeBefore = (rawDataSizeInWords - request.Hipc.DataWords.Length) * sizeof(uint);
+
+            Span<byte> outPointerTable = MemoryMarshal.Cast<uint, byte>(request.Hipc.DataWords).Slice(outPointerSizeTableOffset - paddingSizeBefore);
+            request.OutPointerSizes = MemoryMarshal.Cast<byte, ushort>(outPointerTable);
+            request.ServerPointerSize = format.ServerPointerSize;
+
+            return request;
+        }
+
+        public static Result ParseResponse(out CmifResponse response, Span<byte> input, bool isDomain, int size)
+        {
+            HipcMessage responseMessage = new HipcMessage(input);
+
+            Span<byte> data = MemoryMarshal.Cast<uint, byte>(responseMessage.Data.DataWords);
+            Span<uint> objects = Span<uint>.Empty;
+
+            if (isDomain)
+            {
+                data = data.Slice(Unsafe.SizeOf<CmifDomainOutHeader>());
+                objects = MemoryMarshal.Cast<byte, uint>(data.Slice(Unsafe.SizeOf<CmifOutHeader>() + size));
+            }
+
+            CmifOutHeader header = MemoryMarshal.Cast<byte, CmifOutHeader>(data)[0];
+
+            if (header.Magic != CmifOutHeaderMagic)
+            {
+                response = default;
+                return SfResult.InvalidOutHeader;
+            }
+
+            if (header.Result.IsFailure)
+            {
+                response = default;
+                return header.Result;
+            }
+
+            response = new CmifResponse()
+            {
+                Data = data.Slice(Unsafe.SizeOf<CmifOutHeader>()),
+                Objects = objects,
+                CopyHandles = responseMessage.Data.CopyHandles,
+                MoveHandles = responseMessage.Data.MoveHandles
+            };
+
+            return Result.Success;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifOutHeader.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifOutHeader.cs
new file mode 100644
index 0000000000..2828cde5e8
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifOutHeader.cs
@@ -0,0 +1,14 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    struct CmifOutHeader
+    {
+#pragma warning disable CS0649
+        public uint Magic;
+        public uint Version;
+        public Result Result;
+        public uint Token;
+#pragma warning restore CS0649
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs
new file mode 100644
index 0000000000..80772ad334
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs
@@ -0,0 +1,14 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    ref struct CmifRequest
+    {
+        public HipcMessageData Hipc;
+        public Span<byte> Data;
+        public Span<ushort> OutPointerSizes;
+        public Span<uint> Objects;
+        public int ServerPointerSize;
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequestFormat.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequestFormat.cs
new file mode 100644
index 0000000000..d11545786b
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequestFormat.cs
@@ -0,0 +1,24 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    struct CmifRequestFormat
+    {
+#pragma warning disable CS0649
+        public int ObjectId;
+        public uint RequestId;
+        public uint Context;
+        public int DataSize;
+        public int ServerPointerSize;
+        public int InAutoBuffersCount;
+        public int OutAutoBuffersCount;
+        public int InBuffersCount;
+        public int OutBuffersCount;
+        public int InOutBuffersCount;
+        public int InPointersCount;
+        public int OutPointersCount;
+        public int OutFixedPointersCount;
+        public int ObjectsCount;
+        public int HandlesCount;
+        public bool SendPid;
+#pragma warning restore CS0649
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifResponse.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifResponse.cs
new file mode 100644
index 0000000000..d1d8dc9c50
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifResponse.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    ref struct CmifResponse
+    {
+        public ReadOnlySpan<byte> Data;
+        public ReadOnlySpan<uint> Objects;
+        public ReadOnlySpan<int> CopyHandles;
+        public ReadOnlySpan<int> MoveHandles;
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CommandType.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CommandType.cs
new file mode 100644
index 0000000000..b3b05864eb
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CommandType.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    enum CommandType
+    {
+        Invalid = 0,
+        LegacyRequest = 1,
+        Close = 2,
+        LegacyControl = 3,
+        Request = 4,
+        Control = 5,
+        RequestWithContext = 6,
+        ControlWithContext = 7
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObject.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObject.cs
new file mode 100644
index 0000000000..1483968765
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObject.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    abstract partial class DomainServiceObject : ServerDomainBase, IServiceObject
+    {
+        public abstract ServerDomainBase GetServerDomain();
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectDispatchTable.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectDispatchTable.cs
new file mode 100644
index 0000000000..bcf311b2e9
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectDispatchTable.cs
@@ -0,0 +1,75 @@
+using Ryujinx.Horizon.Common;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    class DomainServiceObjectDispatchTable : ServiceDispatchTableBase
+    {
+        public override Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData)
+        {
+            return ProcessMessageImpl(ref context, ((DomainServiceObject)context.ServiceObject).GetServerDomain(), inRawData);
+        }
+
+        private Result ProcessMessageImpl(ref ServiceDispatchContext context, ServerDomainBase domain, ReadOnlySpan<byte> inRawData)
+        {
+            if (inRawData.Length < Unsafe.SizeOf<CmifDomainInHeader>())
+            {
+                return SfResult.InvalidHeaderSize;
+            }
+
+            var inHeader = MemoryMarshal.Cast<byte, CmifDomainInHeader>(inRawData)[0];
+
+            ReadOnlySpan<byte> inDomainRawData = inRawData.Slice(Unsafe.SizeOf<CmifDomainInHeader>());
+
+            int targetObjectId = inHeader.ObjectId;
+
+            switch (inHeader.Type)
+            {
+                case CmifDomainRequestType.SendMessage:
+                    var targetObject = domain.GetObject(targetObjectId);
+                    if (targetObject == null)
+                    {
+                        return SfResult.TargetNotFound;
+                    }
+
+                    if (inHeader.DataSize + inHeader.ObjectsCount * sizeof(int) > inDomainRawData.Length)
+                    {
+                        return SfResult.InvalidHeaderSize;
+                    }
+
+                    ReadOnlySpan<byte> inMessageRawData = inDomainRawData.Slice(0, inHeader.DataSize);
+
+                    if (inHeader.ObjectsCount > DomainServiceObjectProcessor.MaximumObjects)
+                    {
+                        return SfResult.InvalidInObjectsCount;
+                    }
+
+                    int[] inObjectIds = new int[inHeader.ObjectsCount];
+
+                    var domainProcessor = new DomainServiceObjectProcessor(domain, inObjectIds);
+
+                    if (context.Processor == null)
+                    {
+                        context.Processor = domainProcessor;
+                    }
+                    else
+                    {
+                        context.Processor.SetImplementationProcessor(domainProcessor);
+                    }
+
+                    context.ServiceObject = targetObject.ServiceObject;
+
+                    return targetObject.ProcessMessage(ref context, inMessageRawData);
+
+                case CmifDomainRequestType.Close:
+                    domain.UnregisterObject(targetObjectId);
+                    return Result.Success;
+
+                default:
+                    return SfResult.InvalidInHeader;
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectProcessor.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectProcessor.cs
new file mode 100644
index 0000000000..92d86196a0
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectProcessor.cs
@@ -0,0 +1,140 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    class DomainServiceObjectProcessor : ServerMessageProcessor
+    {
+        public const int MaximumObjects = 8;
+
+        private ServerMessageProcessor _implProcessor;
+        private readonly ServerDomainBase _domain;
+        private int _outObjectIdsOffset;
+        private readonly int[] _inObjectIds;
+        private readonly int[] _reservedObjectIds;
+        private ServerMessageRuntimeMetadata _implMetadata;
+
+        private int InObjectsCount => _inObjectIds.Length;
+        private int OutObjectsCount => _implMetadata.OutObjectsCount;
+        private int ImplOutHeadersSize => _implMetadata.OutHeadersSize;
+        private int ImplOutDataTotalSize => _implMetadata.OutDataSize + _implMetadata.OutHeadersSize;
+
+        public DomainServiceObjectProcessor(ServerDomainBase domain, int[] inObjectIds)
+        {
+            _domain = domain;
+            _inObjectIds = inObjectIds;
+            _reservedObjectIds = new int[MaximumObjects];
+        }
+
+        public override void SetImplementationProcessor(ServerMessageProcessor impl)
+        {
+            if (_implProcessor == null)
+            {
+                _implProcessor = impl;
+            }
+            else
+            {
+                _implProcessor.SetImplementationProcessor(impl);
+            }
+
+            _implMetadata = _implProcessor.GetRuntimeMetadata();
+        }
+
+        public override ServerMessageRuntimeMetadata GetRuntimeMetadata()
+        {
+            var runtimeMetadata = _implProcessor.GetRuntimeMetadata();
+
+            return new ServerMessageRuntimeMetadata(
+                (ushort)(runtimeMetadata.InDataSize + runtimeMetadata.InObjectsCount * sizeof(int)),
+                (ushort)(runtimeMetadata.OutDataSize + runtimeMetadata.OutObjectsCount * sizeof(int)),
+                (byte)(runtimeMetadata.InHeadersSize + Unsafe.SizeOf<CmifDomainInHeader>()),
+                (byte)(runtimeMetadata.OutHeadersSize + Unsafe.SizeOf<CmifDomainOutHeader>()),
+                0,
+                0);
+        }
+
+        public override Result PrepareForProcess(ref ServiceDispatchContext context, ServerMessageRuntimeMetadata runtimeMetadata)
+        {
+            if (_implMetadata.InObjectsCount != InObjectsCount)
+            {
+                return SfResult.InvalidInObjectsCount;
+            }
+
+            Result result = _domain.ReserveIds(new Span<int>(_reservedObjectIds).Slice(0, OutObjectsCount));
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            return _implProcessor.PrepareForProcess(ref context, runtimeMetadata);
+        }
+
+        public override Result GetInObjects(Span<ServiceObjectHolder> inObjects)
+        {
+            for (int i = 0; i < InObjectsCount; i++)
+            {
+                inObjects[i] = _domain.GetObject(_inObjectIds[i]);
+            }
+
+            return Result.Success;
+        }
+
+        public override HipcMessageData PrepareForReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
+        {
+            var response = _implProcessor.PrepareForReply(ref context, out outRawData, runtimeMetadata);
+
+            int outHeaderSize = Unsafe.SizeOf<CmifDomainOutHeader>();
+            int implOutDataTotalSize = ImplOutDataTotalSize;
+
+            DebugUtil.Assert(outHeaderSize + implOutDataTotalSize + OutObjectsCount * sizeof(int) <= outRawData.Length);
+
+            outRawData = outRawData.Slice(outHeaderSize);
+            _outObjectIdsOffset = (response.DataWords.Length * sizeof(uint) - outRawData.Length) + implOutDataTotalSize;
+
+            return response;
+        }
+
+        public override void PrepareForErrorReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
+        {
+            _implProcessor.PrepareForErrorReply(ref context, out outRawData, runtimeMetadata);
+
+            int outHeaderSize = Unsafe.SizeOf<CmifDomainOutHeader>();
+            int implOutDataTotalSize = ImplOutDataTotalSize;
+
+            DebugUtil.Assert(outHeaderSize + implOutDataTotalSize <= outRawData.Length);
+
+            outRawData = outRawData.Slice(outHeaderSize);
+
+            _domain.UnreserveIds(new Span<int>(_reservedObjectIds).Slice(0, OutObjectsCount));
+        }
+
+        public override void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span<ServiceObjectHolder> outObjects)
+        {
+            int outObjectsCount = OutObjectsCount;
+            Span<int> objectIds = _reservedObjectIds;
+
+            for (int i = 0; i < outObjectsCount; i++)
+            {
+                if (outObjects[i] == null)
+                {
+                    _domain.UnreserveIds(objectIds.Slice(i, 1));
+                    objectIds[i] = 0;
+                    continue;
+                }
+
+                _domain.RegisterObject(objectIds[i], outObjects[i]);
+            }
+
+            Span<int> outObjectIds = MemoryMarshal.Cast<byte, int>(MemoryMarshal.Cast<uint, byte>(response.DataWords).Slice(_outObjectIdsOffset));
+
+            for (int i = 0; i < outObjectsCount; i++)
+            {
+                outObjectIds[i] = objectIds[i];
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/HandlesToClose.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/HandlesToClose.cs
new file mode 100644
index 0000000000..0f3b259af0
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/HandlesToClose.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    struct HandlesToClose
+    {
+        private int _handle0;
+        private int _handle1;
+        private int _handle2;
+        private int _handle3;
+        private int _handle4;
+        private int _handle5;
+        private int _handle6;
+        private int _handle7;
+
+        public int Count;
+
+        public int this[int index]
+        {
+            get
+            {
+                return index switch
+                {
+                    0 => _handle0,
+                    1 => _handle1,
+                    2 => _handle2,
+                    3 => _handle3,
+                    4 => _handle4,
+                    5 => _handle5,
+                    6 => _handle6,
+                    7 => _handle7,
+                    _ => throw new IndexOutOfRangeException()
+                };
+            }
+            set
+            {
+                switch (index)
+                {
+                    case 0: _handle0 = value; break;
+                    case 1: _handle1 = value; break;
+                    case 2: _handle2 = value; break;
+                    case 3: _handle3 = value; break;
+                    case 4: _handle4 = value; break;
+                    case 5: _handle5 = value; break;
+                    case 6: _handle6 = value; break;
+                    case 7: _handle7 = value; break;
+                    default: throw new IndexOutOfRangeException();
+                }
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/InlineContext.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/InlineContext.cs
new file mode 100644
index 0000000000..ddb6943f3b
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/InlineContext.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    class InlineContext
+    {
+        public static int Set(int newContext)
+        {
+            // TODO: Implement (will require FS changes???)
+            return newContext;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/PointerAndSize.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/PointerAndSize.cs
new file mode 100644
index 0000000000..5af00077a7
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/PointerAndSize.cs
@@ -0,0 +1,17 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    struct PointerAndSize
+    {
+        public static PointerAndSize Empty => new PointerAndSize(0UL, 0UL);
+
+        public ulong Address { get; }
+        public ulong Size { get; }
+        public bool IsEmpty => Size == 0UL;
+
+        public PointerAndSize(ulong address, ulong size)
+        {
+            Address = address;
+            Size = size;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ScopedInlineContextChange.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ScopedInlineContextChange.cs
new file mode 100644
index 0000000000..eabe544f4f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ScopedInlineContextChange.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    struct ScopedInlineContextChange : IDisposable
+    {
+        private readonly int _previousContext;
+
+        public ScopedInlineContextChange(int newContext)
+        {
+            _previousContext = InlineContext.Set(newContext);
+        }
+
+        public void Dispose()
+        {
+            InlineContext.Set(_previousContext);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainBase.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainBase.cs
new file mode 100644
index 0000000000..f38fa03038
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainBase.cs
@@ -0,0 +1,15 @@
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    abstract class ServerDomainBase
+    {
+        public abstract Result ReserveIds(Span<int> outIds);
+        public abstract void UnreserveIds(ReadOnlySpan<int> ids);
+        public abstract void RegisterObject(int id, ServiceObjectHolder obj);
+
+        public abstract ServiceObjectHolder UnregisterObject(int id);
+        public abstract ServiceObjectHolder GetObject(int id);
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainManager.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainManager.cs
new file mode 100644
index 0000000000..62ee273802
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainManager.cs
@@ -0,0 +1,246 @@
+using Ryujinx.Horizon.Common;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    class ServerDomainManager
+    {
+        private class EntryManager
+        {
+            public class Entry
+            {
+                public int Id { get; }
+                public Domain Owner { get; set; }
+                public ServiceObjectHolder Obj { get; set; }
+                public LinkedListNode<Entry> Node { get; set; }
+
+                public Entry(int id)
+                {
+                    Id = id;
+                }
+            }
+
+            private readonly LinkedList<Entry> _freeList;
+            private readonly Entry[] _entries;
+
+            public EntryManager(int count)
+            {
+                _freeList = new LinkedList<Entry>();
+                _entries = new Entry[count];
+
+                for (int i = 0; i < count; i++)
+                {
+                    _freeList.AddLast(_entries[i] = new Entry(i + 1));
+                }
+            }
+
+            public Entry AllocateEntry()
+            {
+                lock (_freeList)
+                {
+                    if (_freeList.Count == 0)
+                    {
+                        return null;
+                    }
+
+                    var entry = _freeList.First.Value;
+                    _freeList.RemoveFirst();
+                    return entry;
+                }
+            }
+
+            public void FreeEntry(Entry entry)
+            {
+                lock (_freeList)
+                {
+                    DebugUtil.Assert(entry.Owner == null);
+                    DebugUtil.Assert(entry.Obj == null);
+                    _freeList.AddFirst(entry);
+                }
+            }
+
+            public Entry GetEntry(int id)
+            {
+                if (id == 0)
+                {
+                    return null;
+                }
+
+                int index = id - 1;
+
+                if ((uint)index >= (uint)_entries.Length)
+                {
+                    return null;
+                }
+
+                return _entries[index];
+            }
+        }
+
+        private class Domain : DomainServiceObject, IDisposable
+        {
+            private readonly ServerDomainManager _manager;
+            private readonly LinkedList<EntryManager.Entry> _entries;
+
+            public Domain(ServerDomainManager manager)
+            {
+                _manager = manager;
+                _entries = new LinkedList<EntryManager.Entry>();
+            }
+
+            public override ServiceObjectHolder GetObject(int id)
+            {
+                var entry = _manager._entryManager.GetEntry(id);
+                if (entry == null)
+                {
+                    return null;
+                }
+
+                lock (_manager._entryOwnerLock)
+                {
+                    if (entry.Owner != this)
+                    {
+                        return null;
+                    }
+                }
+
+                return entry.Obj.Clone();
+            }
+
+            public override ServerDomainBase GetServerDomain()
+            {
+                return this;
+            }
+
+            public override void RegisterObject(int id, ServiceObjectHolder obj)
+            {
+                var entry = _manager._entryManager.GetEntry(id);
+                DebugUtil.Assert(entry != null);
+
+                lock (_manager._entryOwnerLock)
+                {
+                    DebugUtil.Assert(entry.Owner == null);
+                    entry.Owner = this;
+                    entry.Node = _entries.AddLast(entry);
+                }
+
+                entry.Obj = obj;
+            }
+
+            public override Result ReserveIds(Span<int> outIds)
+            {
+                for (int i = 0; i < outIds.Length; i++)
+                {
+                    var entry = _manager._entryManager.AllocateEntry();
+                    if (entry == null)
+                    {
+                        return SfResult.OutOfDomainEntries;
+                    }
+
+                    DebugUtil.Assert(entry.Owner == null);
+
+                    outIds[i] = entry.Id;
+                }
+
+                return Result.Success;
+            }
+
+            public override ServiceObjectHolder UnregisterObject(int id)
+            {
+                var entry = _manager._entryManager.GetEntry(id);
+                if (entry == null)
+                {
+                    return null;
+                }
+
+                ServiceObjectHolder obj;
+
+                lock (_manager._entryOwnerLock)
+                {
+                    if (entry.Owner != this)
+                    {
+                        return null;
+                    }
+
+                    entry.Owner = null;
+                    obj = entry.Obj;
+                    entry.Obj = null;
+                    _entries.Remove(entry.Node);
+                    entry.Node = null;
+                }
+
+                _manager._entryManager.FreeEntry(entry);
+
+                return obj;
+            }
+
+            public override void UnreserveIds(ReadOnlySpan<int> ids)
+            {
+                for (int i = 0; i < ids.Length; i++)
+                {
+                    var entry = _manager._entryManager.GetEntry(ids[i]);
+
+                    DebugUtil.Assert(entry != null);
+                    DebugUtil.Assert(entry.Owner == null);
+
+                    _manager._entryManager.FreeEntry(entry);
+                }
+            }
+
+            public void Dispose()
+            {
+                foreach (var entry in _entries)
+                {
+                    if (entry.Obj.ServiceObject is IDisposable disposableObj)
+                    {
+                        disposableObj.Dispose();
+                    }
+                }
+
+                _manager.FreeDomain(this);
+            }
+        }
+
+        private readonly EntryManager _entryManager;
+        private readonly object _entryOwnerLock;
+        private readonly HashSet<Domain> _domains;
+        private int _maxDomains;
+
+        public ServerDomainManager(int entryCount, int maxDomains)
+        {
+            _entryManager = new EntryManager(entryCount);
+            _entryOwnerLock = new object();
+            _domains = new HashSet<Domain>();
+            _maxDomains = maxDomains;
+        }
+
+        public DomainServiceObject AllocateDomainServiceObject()
+        {
+            lock (_domains)
+            {
+                if (_domains.Count == _maxDomains)
+                {
+                    return null;
+                }
+
+                var domain = new Domain(this);
+                _domains.Add(domain);
+                return domain;
+            }
+        }
+
+        public static void DestroyDomainServiceObject(DomainServiceObject obj)
+        {
+            ((Domain)obj).Dispose();
+        }
+
+        private void FreeDomain(Domain domain)
+        {
+            lock (_domains)
+            {
+                _domains.Remove(domain);
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageProcessor.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageProcessor.cs
new file mode 100644
index 0000000000..e765023818
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageProcessor.cs
@@ -0,0 +1,18 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    abstract class ServerMessageProcessor
+    {
+        public abstract void SetImplementationProcessor(ServerMessageProcessor impl);
+        public abstract ServerMessageRuntimeMetadata GetRuntimeMetadata();
+
+        public abstract Result PrepareForProcess(scoped ref ServiceDispatchContext context, ServerMessageRuntimeMetadata runtimeMetadata);
+        public abstract Result GetInObjects(Span<ServiceObjectHolder> inObjects);
+        public abstract HipcMessageData PrepareForReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata);
+        public abstract void PrepareForErrorReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata);
+        public abstract void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span<ServiceObjectHolder> outObjects);
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageRuntimeMetadata.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageRuntimeMetadata.cs
new file mode 100644
index 0000000000..18a404302d
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageRuntimeMetadata.cs
@@ -0,0 +1,29 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    struct ServerMessageRuntimeMetadata
+    {
+        public ushort InDataSize { get; }
+        public ushort OutDataSize { get; }
+        public byte InHeadersSize { get; }
+        public byte OutHeadersSize { get; }
+        public byte InObjectsCount { get; }
+        public byte OutObjectsCount { get; }
+        public int UnfixedOutPointerSizeOffset => InDataSize + InHeadersSize + 0x10;
+
+        public ServerMessageRuntimeMetadata(
+            ushort inDataSize,
+            ushort outDataSize,
+            byte inHeadersSize,
+            byte outHeadersSize,
+            byte inObjectsCount,
+            byte outObjectsCount)
+        {
+            InDataSize = inDataSize;
+            OutDataSize = outDataSize;
+            InHeadersSize = inHeadersSize;
+            OutHeadersSize = outHeadersSize;
+            InObjectsCount = inObjectsCount;
+            OutObjectsCount = outObjectsCount;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchContext.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchContext.cs
new file mode 100644
index 0000000000..3339a1a609
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchContext.cs
@@ -0,0 +1,18 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    ref struct ServiceDispatchContext
+    {
+        public IServiceObject ServiceObject;
+        public ServerSessionManager Manager;
+        public ServerSession Session;
+        public ServerMessageProcessor Processor;
+        public HandlesToClose HandlesToClose;
+        public PointerAndSize PointerBuffer;
+        public ReadOnlySpan<byte> InMessageBuffer;
+        public Span<byte> OutMessageBuffer;
+        public HipcMessage Request;
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchMeta.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchMeta.cs
new file mode 100644
index 0000000000..7fbd8eb849
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchMeta.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    struct ServiceDispatchMeta
+    {
+        public ServiceDispatchTableBase DispatchTable { get; }
+
+        public ServiceDispatchMeta(ServiceDispatchTableBase dispatchTable)
+        {
+            DispatchTable = dispatchTable;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTable.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTable.cs
new file mode 100644
index 0000000000..145c178391
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTable.cs
@@ -0,0 +1,33 @@
+using Ryujinx.Horizon.Common;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    class ServiceDispatchTable : ServiceDispatchTableBase
+    {
+        private readonly string _objectName;
+        private readonly IReadOnlyDictionary<int, CommandHandler> _entries;
+
+        public ServiceDispatchTable(string objectName, IReadOnlyDictionary<int, CommandHandler> entries)
+        {
+            _objectName = objectName;
+            _entries = entries;
+        }
+
+        public override Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData)
+        {
+            return ProcessMessageImpl(ref context, inRawData, _entries, _objectName);
+        }
+
+        public static ServiceDispatchTableBase Create(IServiceObject instance)
+        {
+            if (instance is DomainServiceObject)
+            {
+                return new DomainServiceObjectDispatchTable();
+            }
+
+            return new ServiceDispatchTable(instance.GetType().Name, instance.GetCommandHandlers());
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs
new file mode 100644
index 0000000000..a0e28ca8fd
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs
@@ -0,0 +1,90 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    abstract class ServiceDispatchTableBase
+    {
+        private const uint MaxCmifVersion = 1;
+
+        public abstract Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData);
+
+        protected Result ProcessMessageImpl(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData, IReadOnlyDictionary<int, CommandHandler> entries, string objectName)
+        {
+            if (inRawData.Length < Unsafe.SizeOf<CmifInHeader>())
+            {
+                Logger.Warning?.Print(LogClass.KernelIpc, $"Request message size 0x{inRawData.Length:X} is invalid");
+
+                return SfResult.InvalidHeaderSize;
+            }
+
+            CmifInHeader inHeader = MemoryMarshal.Cast<byte, CmifInHeader>(inRawData)[0];
+
+            if (inHeader.Magic != CmifMessage.CmifInHeaderMagic || inHeader.Version > MaxCmifVersion)
+            {
+                Logger.Warning?.Print(LogClass.KernelIpc, $"Request message header magic value 0x{inHeader.Magic:X} is invalid");
+
+                return SfResult.InvalidInHeader;
+            }
+
+            ReadOnlySpan<byte> inMessageRawData = inRawData[Unsafe.SizeOf<CmifInHeader>()..];
+            uint commandId = inHeader.CommandId;
+
+            var outHeader = Span<CmifOutHeader>.Empty;
+
+            if (!entries.TryGetValue((int)commandId, out var commandHandler))
+            {
+                Logger.Warning?.Print(LogClass.KernelIpc, $"{objectName} command ID 0x{commandId:X} is not implemented");
+
+                if (HorizonStatic.Options.IgnoreMissingServices)
+                {
+                    // If ignore missing services is enabled, just pretend that everything is fine.
+                    var response = PrepareForStubReply(ref context, out Span<byte> outRawData);
+                    CommandHandler.GetCmifOutHeaderPointer(ref outHeader, ref outRawData);
+                    outHeader[0] = new CmifOutHeader() { Magic = CmifMessage.CmifOutHeaderMagic, Result = Result.Success };
+
+                    return Result.Success;
+                }
+
+                return SfResult.UnknownCommandId;
+            }
+
+            Logger.Trace?.Print(LogClass.KernelIpc, $"{objectName}.{commandHandler.MethodName} called");
+
+            Result commandResult = commandHandler.Invoke(ref outHeader, ref context, inMessageRawData);
+
+            if (commandResult.Module == SfResult.ModuleId ||
+                commandResult.Module == HipcResult.ModuleId)
+            {
+                Logger.Warning?.Print(LogClass.KernelIpc, $"{commandHandler.MethodName} returned error {commandResult}");
+            }
+
+            if (SfResult.RequestContextChanged(commandResult))
+            {
+                return commandResult;
+            }
+
+            if (outHeader.IsEmpty)
+            {
+                commandResult.AbortOnSuccess();
+                return commandResult;
+            }
+
+            outHeader[0] = new CmifOutHeader() { Magic = CmifMessage.CmifOutHeaderMagic, Result = commandResult };
+
+            return Result.Success;
+        }
+
+        private static HipcMessageData PrepareForStubReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData)
+        {
+            var response = HipcMessage.WriteResponse(context.OutMessageBuffer, 0, 0x20 / sizeof(uint), 0, 0);
+            outRawData = MemoryMarshal.Cast<uint, byte>(response.DataWords);
+            return response;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceObjectHolder.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceObjectHolder.cs
new file mode 100644
index 0000000000..6e87e3405f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceObjectHolder.cs
@@ -0,0 +1,34 @@
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+    class ServiceObjectHolder
+    {
+        public IServiceObject ServiceObject { get; }
+
+        private readonly ServiceDispatchMeta _dispatchMeta;
+
+        public ServiceObjectHolder(ServiceObjectHolder objectHolder)
+        {
+            ServiceObject = objectHolder.ServiceObject;
+            _dispatchMeta = objectHolder._dispatchMeta;
+        }
+
+        public ServiceObjectHolder(IServiceObject serviceImpl)
+        {
+            ServiceObject = serviceImpl;
+            _dispatchMeta = new ServiceDispatchMeta(ServiceDispatchTable.Create(serviceImpl));
+        }
+
+        public ServiceObjectHolder Clone()
+        {
+            return new ServiceObjectHolder(this);
+        }
+
+        public Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData)
+        {
+            return _dispatchMeta.DispatchTable.ProcessMessage(ref context, inRawData);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/CmifCommandAttribute.cs b/Ryujinx.Horizon/Sdk/Sf/CmifCommandAttribute.cs
new file mode 100644
index 0000000000..51a7b59761
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/CmifCommandAttribute.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    class CmifCommandAttribute : Attribute
+    {
+        public uint CommandId { get; }
+
+        public CmifCommandAttribute(uint commandId)
+        {
+            CommandId = commandId;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/CommandArg.cs b/Ryujinx.Horizon/Sdk/Sf/CommandArg.cs
new file mode 100644
index 0000000000..8f367b4e01
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/CommandArg.cs
@@ -0,0 +1,56 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+    enum CommandArgType : byte
+    {
+        Invalid,
+
+        Buffer,
+        InArgument,
+        InCopyHandle,
+        InMoveHandle,
+        InObject,
+        OutArgument,
+        OutCopyHandle,
+        OutMoveHandle,
+        OutObject,
+        ProcessId
+    }
+
+    struct CommandArg
+    {
+        public CommandArgType Type { get; }
+        public HipcBufferFlags BufferFlags { get; }
+        public ushort BufferFixedSize { get; }
+        public int ArgSize { get; }
+        public int ArgAlignment { get; }
+
+        public CommandArg(CommandArgType type)
+        {
+            Type = type;
+            BufferFlags = default;
+            BufferFixedSize = 0;
+            ArgSize = 0;
+            ArgAlignment = 0;
+        }
+
+        public CommandArg(CommandArgType type, int argSize, int argAlignment)
+        {
+            Type = type;
+            BufferFlags = default;
+            BufferFixedSize = 0;
+            ArgSize = argSize;
+            ArgAlignment = argAlignment;
+        }
+
+        public CommandArg(HipcBufferFlags flags, ushort fixedSize = 0)
+        {
+            Type = CommandArgType.Buffer;
+            BufferFlags = flags;
+            BufferFixedSize = fixedSize;
+            ArgSize = 0;
+            ArgAlignment = 0;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/CommandArgAttributes.cs b/Ryujinx.Horizon/Sdk/Sf/CommandArgAttributes.cs
new file mode 100644
index 0000000000..5b7c302f2b
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/CommandArgAttributes.cs
@@ -0,0 +1,38 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+    [AttributeUsage(AttributeTargets.Parameter)]
+    class BufferAttribute : Attribute
+    {
+        public HipcBufferFlags Flags { get; }
+        public ushort FixedSize { get; }
+
+        public BufferAttribute(HipcBufferFlags flags)
+        {
+            Flags = flags;
+        }
+
+        public BufferAttribute(HipcBufferFlags flags, ushort fixedSize)
+        {
+            Flags = flags | HipcBufferFlags.FixedSize;
+            FixedSize = fixedSize;
+        }
+    }
+
+    [AttributeUsage(AttributeTargets.Parameter)]
+    class ClientProcessIdAttribute : Attribute
+    {
+    }
+
+    [AttributeUsage(AttributeTargets.Parameter)]
+    class CopyHandleAttribute : Attribute
+    {
+    }
+
+    [AttributeUsage(AttributeTargets.Parameter)]
+    class MoveHandleAttribute : Attribute
+    {
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/CommandHandler.cs b/Ryujinx.Horizon/Sdk/Sf/CommandHandler.cs
new file mode 100644
index 0000000000..ae42a8ef58
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/CommandHandler.cs
@@ -0,0 +1,57 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+    class CommandHandler
+    {
+        public delegate Result MethodInvoke(
+            ref ServiceDispatchContext context,
+            HipcCommandProcessor processor,
+            ServerMessageRuntimeMetadata runtimeMetadata,
+            ReadOnlySpan<byte> inRawData,
+            ref Span<CmifOutHeader> outHeader);
+
+        private readonly MethodInvoke _invoke;
+        private readonly HipcCommandProcessor _processor;
+
+        public string MethodName => _invoke.Method.Name;
+
+        public CommandHandler(MethodInvoke invoke, params CommandArg[] args)
+        {
+            _invoke = invoke;
+            _processor = new HipcCommandProcessor(args);
+        }
+
+        public Result Invoke(ref Span<CmifOutHeader> outHeader, ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData)
+        {
+            if (context.Processor == null)
+            {
+                context.Processor = _processor;
+            }
+            else
+            {
+                context.Processor.SetImplementationProcessor(_processor);
+            }
+
+            var runtimeMetadata = context.Processor.GetRuntimeMetadata();
+            Result result = context.Processor.PrepareForProcess(ref context, runtimeMetadata);
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            return _invoke(ref context, _processor, runtimeMetadata, inRawData, ref outHeader);
+        }
+
+        public static void GetCmifOutHeaderPointer(ref Span<CmifOutHeader> outHeader, ref Span<byte> outRawData)
+        {
+            outHeader = MemoryMarshal.Cast<byte, CmifOutHeader>(outRawData).Slice(0, 1);
+            outRawData = outRawData.Slice(Unsafe.SizeOf<CmifOutHeader>());
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs b/Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs
new file mode 100644
index 0000000000..9a3a511ade
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs
@@ -0,0 +1,68 @@
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using Ryujinx.Memory;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+    static class CommandSerialization
+    {
+        public static ReadOnlySpan<byte> GetReadOnlySpan(PointerAndSize bufferRange)
+        {
+            return HorizonStatic.AddressSpace.GetSpan(bufferRange.Address, checked((int)bufferRange.Size));
+        }
+
+        public static WritableRegion GetWritableRegion(PointerAndSize bufferRange)
+        {
+            return HorizonStatic.AddressSpace.GetWritableRegion(bufferRange.Address, checked((int)bufferRange.Size));
+        }
+
+        public static ref T GetRef<T>(PointerAndSize bufferRange) where T : unmanaged
+        {
+            var writableRegion = GetWritableRegion(bufferRange);
+            return ref MemoryMarshal.Cast<byte, T>(writableRegion.Memory.Span)[0];
+        }
+
+        public static object DeserializeArg<T>(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData, int offset) where T : unmanaged
+        {
+            return MemoryMarshal.Cast<byte, T>(inRawData.Slice(offset, Unsafe.SizeOf<T>()))[0];
+        }
+
+        public static T DeserializeArg<T>(ReadOnlySpan<byte> inRawData, int offset) where T : unmanaged
+        {
+            return MemoryMarshal.Cast<byte, T>(inRawData.Slice(offset, Unsafe.SizeOf<T>()))[0];
+        }
+
+        public static ulong DeserializeClientProcessId(ref ServiceDispatchContext context)
+        {
+            return context.Request.Pid;
+        }
+
+        public static int DeserializeCopyHandle(ref ServiceDispatchContext context, int index)
+        {
+            return context.Request.Data.CopyHandles[index];
+        }
+
+        public static int DeserializeMoveHandle(ref ServiceDispatchContext context, int index)
+        {
+            return context.Request.Data.MoveHandles[index];
+        }
+
+        public static void SerializeArg<T>(Span<byte> outRawData, int offset, T value) where T : unmanaged
+        {
+            MemoryMarshal.Cast<byte, T>(outRawData.Slice(offset, Unsafe.SizeOf<T>()))[0] = (T)value;
+        }
+
+        public static void SerializeCopyHandle(HipcMessageData response, int index, int value)
+        {
+            response.CopyHandles[index] = value;
+        }
+
+        public static void SerializeMoveHandle(HipcMessageData response, int index, int value)
+        {
+            response.MoveHandles[index] = value;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/Api.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/Api.cs
new file mode 100644
index 0000000000..deac524c72
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/Api.cs
@@ -0,0 +1,89 @@
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    static class Api
+    {
+        public const int TlsMessageBufferSize = 0x100;
+
+        public static Result Receive(out ReceiveResult recvResult, int sessionHandle, Span<byte> messageBuffer)
+        {
+            Result result = ReceiveImpl(sessionHandle, messageBuffer);
+
+            if (result == KernelResult.PortRemoteClosed)
+            {
+                recvResult = ReceiveResult.Closed;
+
+                return Result.Success;
+            }
+            else if (result == KernelResult.ReceiveListBroken)
+            {
+                recvResult = ReceiveResult.NeedsRetry;
+
+                return Result.Success;
+            }
+
+            recvResult = ReceiveResult.Success;
+
+            return result;
+        }
+
+        private static Result ReceiveImpl(int sessionHandle, Span<byte> messageBuffer)
+        {
+            Span<int> handles = stackalloc int[1];
+
+            handles[0] = sessionHandle;
+
+            var tlsSpan = HorizonStatic.AddressSpace.GetSpan(HorizonStatic.ThreadContext.TlsAddress, TlsMessageBufferSize);
+
+            if (messageBuffer == tlsSpan)
+            {
+                return HorizonStatic.Syscall.ReplyAndReceive(out _, handles, 0, -1L);
+            }
+            else
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        public static Result Reply(int sessionHandle, ReadOnlySpan<byte> messageBuffer)
+        {
+            Result result = ReplyImpl(sessionHandle, messageBuffer);
+
+            result.AbortUnless(KernelResult.TimedOut, KernelResult.PortRemoteClosed);
+
+            return Result.Success;
+        }
+
+        private static Result ReplyImpl(int sessionHandle, ReadOnlySpan<byte> messageBuffer)
+        {
+            Span<int> handles = stackalloc int[1];
+
+            handles[0] = sessionHandle;
+
+            var tlsSpan = HorizonStatic.AddressSpace.GetSpan(HorizonStatic.ThreadContext.TlsAddress, TlsMessageBufferSize);
+
+            if (messageBuffer == tlsSpan)
+            {
+                return HorizonStatic.Syscall.ReplyAndReceive(out _, handles, sessionHandle, 0);
+            }
+            else
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        public static Result CreateSession(out int serverHandle, out int clientHandle)
+        {
+            Result result = HorizonStatic.Syscall.CreateSession(out serverHandle, out clientHandle, false, null);
+
+            if (result == KernelResult.OutOfResource)
+            {
+                return HipcResult.OutOfSessions;
+            }
+
+            return result;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/Header.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/Header.cs
new file mode 100644
index 0000000000..cdb50b5789
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/Header.cs
@@ -0,0 +1,65 @@
+using Ryujinx.Common.Utilities;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    struct Header
+    {
+        private uint _word0;
+        private uint _word1;
+
+        public CommandType Type
+        {
+            get => (CommandType)_word0.Extract(0, 16);
+            set => _word0 = _word0.Insert(0, 16, (uint)value);
+        }
+
+        public int SendStaticsCount
+        {
+            get => (int)_word0.Extract(16, 4);
+            set => _word0 = _word0.Insert(16, 4, (uint)value);
+        }
+
+        public int SendBuffersCount
+        {
+            get => (int)_word0.Extract(20, 4);
+            set => _word0 = _word0.Insert(20, 4, (uint)value);
+        }
+
+        public int ReceiveBuffersCount
+        {
+            get => (int)_word0.Extract(24, 4);
+            set => _word0 = _word0.Insert(24, 4, (uint)value);
+        }
+
+        public int ExchangeBuffersCount
+        {
+            get => (int)_word0.Extract(28, 4);
+            set => _word0 = _word0.Insert(28, 4, (uint)value);
+        }
+
+        public int DataWordsCount
+        {
+            get => (int)_word1.Extract(0, 10);
+            set => _word1 = _word1.Insert(0, 10, (uint)value);
+        }
+
+        public int ReceiveStaticMode
+        {
+            get => (int)_word1.Extract(10, 4);
+            set => _word1 = _word1.Insert(10, 4, (uint)value);
+        }
+
+        public int ReceiveListOffset
+        {
+            get => (int)_word1.Extract(20, 11);
+            set => _word1 = _word1.Insert(20, 11, (uint)value);
+        }
+
+        public bool HasSpecialHeader
+        {
+            get => _word1.Extract(31);
+            set => _word1 = _word1.Insert(31, value);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs
new file mode 100644
index 0000000000..7778d5bca3
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs
@@ -0,0 +1,15 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    struct HipcBufferDescriptor
+    {
+#pragma warning disable CS0649
+        private uint _sizeLow;
+        private uint _addressLow;
+        private uint _word2;
+#pragma warning restore CS0649
+
+        public ulong Address => _addressLow | (((ulong)_word2 << 4) & 0xf00000000UL) | (((ulong)_word2 << 34) & 0x7000000000UL);
+        public ulong Size => _sizeLow | ((ulong)_word2 << 8) & 0xf00000000UL;
+        public HipcBufferMode Mode => (HipcBufferMode)(_word2 & 3);
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferFlags.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferFlags.cs
new file mode 100644
index 0000000000..594af2c84a
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferFlags.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    [Flags]
+    enum HipcBufferFlags : byte
+    {
+        In = 1 << 0,
+        Out = 1 << 1,
+        MapAlias = 1 << 2,
+        Pointer = 1 << 3,
+        FixedSize = 1 << 4,
+        AutoSelect = 1 << 5,
+        MapTransferAllowsNonSecure = 1 << 6,
+        MapTransferAllowsNonDevice = 1 << 7
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferMode.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferMode.cs
new file mode 100644
index 0000000000..4ef6374ba8
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferMode.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    enum HipcBufferMode
+    {
+        Normal = 0,
+        NonSecure = 1,
+        Invalid = 2,
+        NonDevice = 3
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcManager.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcManager.cs
new file mode 100644
index 0000000000..ea2ec65056
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcManager.cs
@@ -0,0 +1,115 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    partial class HipcManager : IServiceObject
+    {
+        private readonly ServerDomainSessionManager _manager;
+        private readonly ServerSession _session;
+
+        public HipcManager(ServerDomainSessionManager manager, ServerSession session)
+        {
+            _manager = manager;
+            _session = session;
+        }
+
+        [CmifCommand(0)]
+        public Result ConvertCurrentObjectToDomain(out int objectId)
+        {
+            objectId = 0;
+
+            var domain = _manager.Domain.AllocateDomainServiceObject();
+            if (domain == null)
+            {
+                return HipcResult.OutOfDomains;
+            }
+
+            bool succeeded = false;
+
+            try
+            {
+                Span<int> objectIds = stackalloc int[1];
+
+                Result result = domain.ReserveIds(objectIds);
+
+                if (result.IsFailure)
+                {
+                    return result;
+                }
+
+                objectId = objectIds[0];
+                succeeded = true;
+            }
+            finally
+            {
+                if (!succeeded)
+                {
+                    ServerDomainManager.DestroyDomainServiceObject(domain);
+                }
+            }
+
+            domain.RegisterObject(objectId, _session.ServiceObjectHolder);
+            _session.ServiceObjectHolder = new ServiceObjectHolder(domain);
+
+            return Result.Success;
+        }
+
+        [CmifCommand(1)]
+        public Result CopyFromCurrentDomain([MoveHandle] out int clientHandle, int objectId)
+        {
+            clientHandle = 0;
+
+            if (!(_session.ServiceObjectHolder.ServiceObject is DomainServiceObject domain))
+            {
+                return HipcResult.TargetNotDomain;
+            }
+
+            var obj = domain.GetObject(objectId);
+            if (obj == null)
+            {
+                return HipcResult.DomainObjectNotFound;
+            }
+
+            Api.CreateSession(out int serverHandle, out clientHandle).AbortOnFailure();
+            _manager.RegisterSession(serverHandle, obj).AbortOnFailure();
+
+            return Result.Success;
+        }
+
+        [CmifCommand(2)]
+        public Result CloneCurrentObject([MoveHandle] out int clientHandle)
+        {
+            return CloneCurrentObjectImpl(out clientHandle, _manager);
+        }
+
+        [CmifCommand(3)]
+        public void QueryPointerBufferSize(out ushort size)
+        {
+            size = (ushort)_session.PointerBuffer.Size;
+        }
+
+        [CmifCommand(4)]
+        public Result CloneCurrentObjectEx([MoveHandle] out int clientHandle, uint tag)
+        {
+            return CloneCurrentObjectImpl(out clientHandle, _manager.GetSessionManagerByTag(tag));
+        }
+
+        private Result CloneCurrentObjectImpl(out int clientHandle, ServerSessionManager manager)
+        {
+            clientHandle = 0;
+
+            var clone = _session.ServiceObjectHolder.Clone();
+            if (clone == null)
+            {
+                return HipcResult.DomainObjectNotFound;
+            }
+
+            Api.CreateSession(out int serverHandle, out clientHandle).AbortOnFailure();
+            manager.RegisterSession(serverHandle, clone).AbortOnFailure();
+
+            return Result.Success;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs
new file mode 100644
index 0000000000..3017f40419
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs
@@ -0,0 +1,222 @@
+using Ryujinx.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    ref struct HipcMessage
+    {
+        public const int AutoReceiveStatic = byte.MaxValue;
+
+        public HipcMetadata Meta;
+        public HipcMessageData Data;
+        public ulong Pid;
+
+        public HipcMessage(Span<byte> data)
+        {
+            int initialLength = data.Length;
+
+            Header header = MemoryMarshal.Cast<byte, Header>(data)[0];
+
+            data = data.Slice(Unsafe.SizeOf<Header>());
+
+            int receiveStaticsCount = 0;
+            ulong pid = 0;
+
+            if (header.ReceiveStaticMode != 0)
+            {
+                if (header.ReceiveStaticMode == 2)
+                {
+                    receiveStaticsCount = AutoReceiveStatic;
+                }
+                else if (header.ReceiveStaticMode > 2)
+                {
+                    receiveStaticsCount = header.ReceiveStaticMode - 2;
+                }
+            }
+
+            SpecialHeader specialHeader = default;
+
+            if (header.HasSpecialHeader)
+            {
+                specialHeader = MemoryMarshal.Cast<byte, SpecialHeader>(data)[0];
+
+                data = data.Slice(Unsafe.SizeOf<SpecialHeader>());
+
+                if (specialHeader.SendPid)
+                {
+                    pid = MemoryMarshal.Cast<byte, ulong>(data)[0];
+
+                    data = data.Slice(sizeof(ulong));
+                }
+            }
+
+            Meta = new HipcMetadata()
+            {
+                Type = (int)header.Type,
+                SendStaticsCount = header.SendStaticsCount,
+                SendBuffersCount = header.SendBuffersCount,
+                ReceiveBuffersCount = header.ReceiveBuffersCount,
+                ExchangeBuffersCount = header.ExchangeBuffersCount,
+                DataWordsCount = header.DataWordsCount,
+                ReceiveStaticsCount = receiveStaticsCount,
+                SendPid = specialHeader.SendPid,
+                CopyHandlesCount = specialHeader.CopyHandlesCount,
+                MoveHandlesCount = specialHeader.MoveHandlesCount
+            };
+
+            Data = CreateMessageData(Meta, data, initialLength);
+            Pid = pid;
+        }
+
+        public static HipcMessageData WriteResponse(
+            Span<byte> destination,
+            int sendStaticCount,
+            int dataWordsCount,
+            int copyHandlesCount,
+            int moveHandlesCount)
+        {
+            return WriteMessage(destination, new HipcMetadata()
+            {
+                SendStaticsCount = sendStaticCount,
+                DataWordsCount = dataWordsCount,
+                CopyHandlesCount = copyHandlesCount,
+                MoveHandlesCount = moveHandlesCount
+            });
+        }
+
+        public static HipcMessageData WriteMessage(Span<byte> destination, HipcMetadata meta)
+        {
+            int initialLength = destination.Length;
+
+            bool hasSpecialHeader = meta.SendPid || meta.CopyHandlesCount != 0 || meta.MoveHandlesCount != 0;
+
+            MemoryMarshal.Cast<byte, Header>(destination)[0] = new Header()
+            {
+                Type = (CommandType)meta.Type,
+                SendStaticsCount = meta.SendStaticsCount,
+                SendBuffersCount = meta.SendBuffersCount,
+                ReceiveBuffersCount = meta.ReceiveBuffersCount,
+                ExchangeBuffersCount = meta.ExchangeBuffersCount,
+                DataWordsCount = meta.DataWordsCount,
+                ReceiveStaticMode = meta.ReceiveStaticsCount != 0 ? (meta.ReceiveStaticsCount != AutoReceiveStatic ? meta.ReceiveStaticsCount + 2 : 2) : 0,
+                HasSpecialHeader = hasSpecialHeader
+            };
+
+            destination = destination.Slice(Unsafe.SizeOf<Header>());
+
+            if (hasSpecialHeader)
+            {
+                MemoryMarshal.Cast<byte, SpecialHeader>(destination)[0] = new SpecialHeader()
+                {
+                    SendPid = meta.SendPid,
+                    CopyHandlesCount = meta.CopyHandlesCount,
+                    MoveHandlesCount = meta.MoveHandlesCount
+                };
+
+                destination = destination.Slice(Unsafe.SizeOf<SpecialHeader>());
+
+                if (meta.SendPid)
+                {
+                    destination = destination.Slice(sizeof(ulong));
+                }
+            }
+
+            return CreateMessageData(meta, destination, initialLength);
+        }
+
+        private static HipcMessageData CreateMessageData(HipcMetadata meta, Span<byte> data, int initialLength)
+        {
+            Span<int> copyHandles = Span<int>.Empty;
+
+            if (meta.CopyHandlesCount != 0)
+            {
+                copyHandles = MemoryMarshal.Cast<byte, int>(data).Slice(0, meta.CopyHandlesCount);
+
+                data = data.Slice(meta.CopyHandlesCount * sizeof(int));
+            }
+
+            Span<int> moveHandles = Span<int>.Empty;
+
+            if (meta.MoveHandlesCount != 0)
+            {
+                moveHandles = MemoryMarshal.Cast<byte, int>(data).Slice(0, meta.MoveHandlesCount);
+
+                data = data.Slice(meta.MoveHandlesCount * sizeof(int));
+            }
+
+            Span<HipcStaticDescriptor> sendStatics = Span<HipcStaticDescriptor>.Empty;
+
+            if (meta.SendStaticsCount != 0)
+            {
+                sendStatics = MemoryMarshal.Cast<byte, HipcStaticDescriptor>(data).Slice(0, meta.SendStaticsCount);
+
+                data = data.Slice(meta.SendStaticsCount * Unsafe.SizeOf<HipcStaticDescriptor>());
+            }
+
+            Span<HipcBufferDescriptor> sendBuffers = Span<HipcBufferDescriptor>.Empty;
+
+            if (meta.SendBuffersCount != 0)
+            {
+                sendBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data).Slice(0, meta.SendBuffersCount);
+
+                data = data.Slice(meta.SendBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>());
+            }
+
+            Span<HipcBufferDescriptor> receiveBuffers = Span<HipcBufferDescriptor>.Empty;
+
+            if (meta.ReceiveBuffersCount != 0)
+            {
+                receiveBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data).Slice(0, meta.ReceiveBuffersCount);
+
+                data = data.Slice(meta.ReceiveBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>());
+            }
+
+            Span<HipcBufferDescriptor> exchangeBuffers = Span<HipcBufferDescriptor>.Empty;
+
+            if (meta.ExchangeBuffersCount != 0)
+            {
+                exchangeBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data).Slice(0, meta.ExchangeBuffersCount);
+
+                data = data.Slice(meta.ExchangeBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>());
+            }
+
+            Span<uint> dataWords = Span<uint>.Empty;
+
+            if (meta.DataWordsCount != 0)
+            {
+                int dataOffset = initialLength - data.Length;
+                int dataOffsetAligned = BitUtils.AlignUp(dataOffset, 0x10);
+
+                int padding = (dataOffsetAligned - dataOffset) / sizeof(uint);
+
+                dataWords = MemoryMarshal.Cast<byte, uint>(data).Slice(padding, meta.DataWordsCount - padding);
+
+                data = data.Slice(meta.DataWordsCount * sizeof(uint));
+            }
+
+            Span<HipcReceiveListEntry> receiveList = Span<HipcReceiveListEntry>.Empty;
+
+            if (meta.ReceiveStaticsCount != 0)
+            {
+                int receiveListSize = meta.ReceiveStaticsCount == AutoReceiveStatic ? 1 : meta.ReceiveStaticsCount;
+
+                receiveList = MemoryMarshal.Cast<byte, HipcReceiveListEntry>(data).Slice(0, receiveListSize);
+            }
+
+            return new HipcMessageData()
+            {
+                SendStatics = sendStatics,
+                SendBuffers = sendBuffers,
+                ReceiveBuffers = receiveBuffers,
+                ExchangeBuffers = exchangeBuffers,
+                DataWords = dataWords,
+                ReceiveList = receiveList,
+                CopyHandles = copyHandles,
+                MoveHandles = moveHandles
+            };
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs
new file mode 100644
index 0000000000..c83c422cab
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    ref struct HipcMessageData
+    {
+        public Span<HipcStaticDescriptor> SendStatics;
+        public Span<HipcBufferDescriptor> SendBuffers;
+        public Span<HipcBufferDescriptor> ReceiveBuffers;
+        public Span<HipcBufferDescriptor> ExchangeBuffers;
+        public Span<uint> DataWords;
+        public Span<HipcReceiveListEntry> ReceiveList;
+        public Span<int> CopyHandles;
+        public Span<int> MoveHandles;
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMetadata.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMetadata.cs
new file mode 100644
index 0000000000..fe13137a69
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMetadata.cs
@@ -0,0 +1,16 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    struct HipcMetadata
+    {
+        public int Type;
+        public int SendStaticsCount;
+        public int SendBuffersCount;
+        public int ReceiveBuffersCount;
+        public int ExchangeBuffersCount;
+        public int DataWordsCount;
+        public int ReceiveStaticsCount;
+        public bool SendPid;
+        public int CopyHandlesCount;
+        public int MoveHandlesCount;
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcReceiveListEntry.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcReceiveListEntry.cs
new file mode 100644
index 0000000000..94bf096857
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcReceiveListEntry.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    struct HipcReceiveListEntry
+    {
+        private uint _addressLow;
+        private uint _word1;
+
+        public HipcReceiveListEntry(ulong address, ulong size)
+        {
+            _addressLow = (uint)address;
+            _word1 = (ushort)(address >> 32) | (uint)(size << 16);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcResult.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcResult.cs
new file mode 100644
index 0000000000..ef989a9866
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcResult.cs
@@ -0,0 +1,22 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    static class HipcResult
+    {
+        public const int ModuleId = 11;
+
+        public static Result OutOfSessionMemory => new Result(ModuleId, 102);
+        public static Result OutOfSessions => new Result(ModuleId, 131);
+        public static Result PointerBufferTooSmall => new Result(ModuleId, 141);
+        public static Result OutOfDomains => new Result(ModuleId, 200);
+
+        public static Result InvalidRequestSize => new Result(ModuleId, 402);
+        public static Result UnknownCommandType => new Result(ModuleId, 403);
+
+        public static Result InvalidCmifRequest => new Result(ModuleId, 420);
+
+        public static Result TargetNotDomain => new Result(ModuleId, 491);
+        public static Result DomainObjectNotFound => new Result(ModuleId, 492);
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcStaticDescriptor.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcStaticDescriptor.cs
new file mode 100644
index 0000000000..5cebf47c8c
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcStaticDescriptor.cs
@@ -0,0 +1,22 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    struct HipcStaticDescriptor
+    {
+        private readonly ulong _data;
+
+        public ulong Address => ((((_data >> 2) & 0x70) | ((_data >> 12) & 0xf)) << 32) | (_data >> 32);
+        public ushort Size => (ushort)(_data >> 16);
+        public int ReceiveIndex => (int)(_data & 0xf);
+
+        public HipcStaticDescriptor(ulong address, ushort size, int receiveIndex)
+        {
+            ulong data = (uint)(receiveIndex & 0xf) | ((uint)size << 16);
+
+            data |= address << 32;
+            data |= (address >> 20) & 0xf000;
+            data |= (address >> 30) & 0xffc0;
+
+            _data = data;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ManagerOptions.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ManagerOptions.cs
new file mode 100644
index 0000000000..e087cb2235
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ManagerOptions.cs
@@ -0,0 +1,20 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    struct ManagerOptions
+    {
+        public static ManagerOptions Default => new ManagerOptions(0, 0, 0, false);
+
+        public int PointerBufferSize { get; }
+        public int MaxDomains { get; }
+        public int MaxDomainObjects { get; }
+        public bool CanDeferInvokeRequest { get; }
+
+        public ManagerOptions(int pointerBufferSize, int maxDomains, int maxDomainObjects, bool canDeferInvokeRequest)
+        {
+            PointerBufferSize = pointerBufferSize;
+            MaxDomains = maxDomains;
+            MaxDomainObjects = maxDomainObjects;
+            CanDeferInvokeRequest = canDeferInvokeRequest;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ReceiveResult.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ReceiveResult.cs
new file mode 100644
index 0000000000..7c380a0113
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ReceiveResult.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    enum ReceiveResult
+    {
+        Success,
+        Closed,
+        NeedsRetry
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/Server.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/Server.cs
new file mode 100644
index 0000000000..923f2d52d9
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/Server.cs
@@ -0,0 +1,36 @@
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sm;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    class Server : MultiWaitHolderOfHandle
+    {
+        public int PortIndex { get; }
+        public int PortHandle { get; }
+        public ServiceName Name { get; }
+        public bool Managed { get; }
+        public ServiceObjectHolder StaticObject { get; }
+
+        public Server(
+            int portIndex,
+            int portHandle,
+            ServiceName name,
+            bool managed,
+            ServiceObjectHolder staticHoder) : base(portHandle)
+        {
+            PortHandle = portHandle;
+            Name = name;
+            Managed = managed;
+
+            if (staticHoder != null)
+            {
+                StaticObject = staticHoder;
+            }
+            else
+            {
+                PortIndex = portIndex;
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerDomainSessionManager.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerDomainSessionManager.cs
new file mode 100644
index 0000000000..d920a65917
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerDomainSessionManager.cs
@@ -0,0 +1,23 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    class ServerDomainSessionManager : ServerSessionManager
+    {
+        public ServerDomainManager Domain { get; }
+
+        public ServerDomainSessionManager(int entryCount, int maxDomains)
+        {
+            Domain = new ServerDomainManager(entryCount, maxDomains);
+        }
+
+        protected override Result DispatchManagerRequest(ServerSession session, Span<byte> inMessage, Span<byte> outMessage)
+        {
+            HipcManager hipcManager = new HipcManager(this, session);
+
+            return DispatchRequest(new ServiceObjectHolder(hipcManager), session, inMessage, outMessage);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs
new file mode 100644
index 0000000000..5bb2de25dd
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs
@@ -0,0 +1,198 @@
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sm;
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    class ServerManager : ServerManagerBase, IDisposable
+    {
+        private readonly SmApi _sm;
+        private readonly int _pointerBufferSize;
+        private readonly bool _canDeferInvokeRequest;
+        private readonly int _maxSessions;
+
+        private ulong _pointerBuffersBaseAddress;
+        private ulong _savedMessagesBaseAddress;
+
+        private readonly object _resourceLock;
+        private readonly ulong[] _sessionAllocationBitmap;
+        private readonly HashSet<ServerSession> _sessions;
+        private readonly HashSet<Server> _servers;
+
+        public ServerManager(HeapAllocator allocator, SmApi sm, int maxPorts, ManagerOptions options, int maxSessions) : base(sm, options)
+        {
+            _sm = sm;
+            _pointerBufferSize = options.PointerBufferSize;
+            _canDeferInvokeRequest = options.CanDeferInvokeRequest;
+            _maxSessions = maxSessions;
+
+            if (allocator != null)
+            {
+                _pointerBuffersBaseAddress = allocator.Allocate((ulong)maxSessions * (ulong)options.PointerBufferSize);
+
+                if (options.CanDeferInvokeRequest)
+                {
+                    _savedMessagesBaseAddress = allocator.Allocate((ulong)maxSessions * (ulong)Api.TlsMessageBufferSize);
+                }
+            }
+
+            _resourceLock = new object();
+            _sessionAllocationBitmap = new ulong[(maxSessions + 63) / 64];
+            _sessions = new HashSet<ServerSession>();
+            _servers = new HashSet<Server>();
+        }
+
+        private PointerAndSize GetObjectBySessionIndex(ServerSession session, ulong baseAddress, ulong size)
+        {
+            return new PointerAndSize(baseAddress + (ulong)session.SessionIndex * size, size);
+        }
+
+        protected override ServerSession AllocateSession(int sessionHandle, ServiceObjectHolder obj)
+        {
+            int sessionIndex = -1;
+
+            lock (_resourceLock)
+            {
+                if (_sessions.Count >= _maxSessions)
+                {
+                    return null;
+                }
+
+                for (int i = 0; i <_sessionAllocationBitmap.Length; i++)
+                {
+                    ref ulong mask = ref _sessionAllocationBitmap[i];
+
+                    if (mask != ulong.MaxValue)
+                    {
+                        int bit = BitOperations.TrailingZeroCount(~mask);
+                        sessionIndex = i * 64 + bit;
+                        mask |= 1UL << bit;
+
+                        break;
+                    }
+                }
+
+                if (sessionIndex == -1)
+                {
+                    return null;
+                }
+
+                ServerSession session = new ServerSession(sessionIndex, sessionHandle, obj);
+
+                _sessions.Add(session);
+
+                return session;
+            }
+        }
+
+        protected override void FreeSession(ServerSession session)
+        {
+            if (session.ServiceObjectHolder.ServiceObject is IDisposable disposableObj)
+            {
+                disposableObj.Dispose();
+            }
+
+            lock (_resourceLock)
+            {
+                _sessionAllocationBitmap[session.SessionIndex / 64] &= ~(1UL << (session.SessionIndex & 63));
+                _sessions.Remove(session);
+            }
+        }
+
+        protected override Server AllocateServer(
+            int portIndex,
+            int portHandle,
+            ServiceName name,
+            bool managed,
+            ServiceObjectHolder staticHoder)
+        {
+            lock (_resourceLock)
+            {
+                Server server = new Server(portIndex, portHandle, name, managed, staticHoder);
+
+                _servers.Add(server);
+
+                return server;
+            }
+        }
+
+        protected override void DestroyServer(Server server)
+        {
+            lock (_resourceLock)
+            {
+                server.UnlinkFromMultiWaitHolder();
+                Os.FinalizeMultiWaitHolder(server);
+
+                if (server.Managed)
+                {
+                    // We should AbortOnFailure, but sometimes SM is already gone when this is called,
+                    // so let's just ignore potential errors.
+                    _sm.UnregisterService(server.Name);
+
+                    HorizonStatic.Syscall.CloseHandle(server.PortHandle);
+                }
+
+                _servers.Remove(server);
+            }
+        }
+
+        protected override PointerAndSize GetSessionPointerBuffer(ServerSession session)
+        {
+            if (_pointerBufferSize > 0)
+            {
+                return GetObjectBySessionIndex(session, _pointerBuffersBaseAddress, (ulong)_pointerBufferSize);
+            }
+            else
+            {
+                return PointerAndSize.Empty;
+            }
+        }
+
+        protected override PointerAndSize GetSessionSavedMessageBuffer(ServerSession session)
+        {
+            if (_canDeferInvokeRequest)
+            {
+                return GetObjectBySessionIndex(session, _savedMessagesBaseAddress, Api.TlsMessageBufferSize);
+            }
+            else
+            {
+                return PointerAndSize.Empty;
+            }
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                lock (_resourceLock)
+                {
+                    ServerSession[] sessionsToClose = new ServerSession[_sessions.Count];
+
+                    _sessions.CopyTo(sessionsToClose);
+
+                    foreach (ServerSession session in sessionsToClose)
+                    {
+                        CloseSessionImpl(session);
+                    }
+
+                    Server[] serversToClose = new Server[_servers.Count];
+
+                    _servers.CopyTo(serversToClose);
+
+                    foreach (Server server in serversToClose)
+                    {
+                        DestroyServer(server);
+                    }
+                }
+            }
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs
new file mode 100644
index 0000000000..68cae6bc4d
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs
@@ -0,0 +1,307 @@
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sm;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    class ServerManagerBase : ServerDomainSessionManager
+    {
+        private readonly SmApi _sm;
+
+        private bool _canDeferInvokeRequest;
+
+        private readonly MultiWait _multiWait;
+        private readonly MultiWait _waitList;
+
+        private readonly object _multiWaitSelectionLock;
+        private readonly object _waitListLock;
+
+        private readonly Event _requestStopEvent;
+        private readonly Event _notifyEvent;
+
+        private readonly MultiWaitHolderBase _requestStopEventHolder;
+        private readonly MultiWaitHolderBase _notifyEventHolder;
+
+        private enum UserDataTag
+        {
+            Server = 1,
+            Session = 2
+        }
+
+        public ServerManagerBase(SmApi sm, ManagerOptions options) : base(options.MaxDomainObjects, options.MaxDomains)
+        {
+            _sm = sm;
+            _canDeferInvokeRequest = options.CanDeferInvokeRequest;
+
+            _multiWait = new MultiWait();
+            _waitList = new MultiWait();
+
+            _multiWaitSelectionLock = new object();
+            _waitListLock = new object();
+
+            _requestStopEvent = new Event(EventClearMode.ManualClear);
+            _notifyEvent = new Event(EventClearMode.ManualClear);
+
+            _requestStopEventHolder = new MultiWaitHolderOfEvent(_requestStopEvent);
+            _multiWait.LinkMultiWaitHolder(_requestStopEventHolder);
+            _notifyEventHolder = new MultiWaitHolderOfEvent(_notifyEvent);
+            _multiWait.LinkMultiWaitHolder(_notifyEventHolder);
+        }
+
+        public void RegisterObjectForServer(IServiceObject staticObject, int portHandle)
+        {
+            RegisterServerImpl(0, new ServiceObjectHolder(staticObject), portHandle);
+        }
+
+        public Result RegisterObjectForServer(IServiceObject staticObject, ServiceName name, int maxSessions)
+        {
+            return RegisterServerImpl(0, new ServiceObjectHolder(staticObject), name, maxSessions);
+        }
+
+        public void RegisterServer(int portIndex, int portHandle)
+        {
+            RegisterServerImpl(portIndex, null, portHandle);
+        }
+
+        public Result RegisterServer(int portIndex, ServiceName name, int maxSessions)
+        {
+            return RegisterServerImpl(portIndex, null, name, maxSessions);
+        }
+
+        private void RegisterServerImpl(int portIndex, ServiceObjectHolder staticHolder, int portHandle)
+        {
+            Server server = AllocateServer(portIndex, portHandle, ServiceName.Invalid, managed: false, staticHolder);
+            RegisterServerImpl(server);
+        }
+
+        private Result RegisterServerImpl(int portIndex, ServiceObjectHolder staticHolder, ServiceName name, int maxSessions)
+        {
+            Result result = _sm.RegisterService(out int portHandle, name, maxSessions, isLight: false);
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            Server server = AllocateServer(portIndex, portHandle, name, managed: true, staticHolder);
+            RegisterServerImpl(server);
+
+            return Result.Success;
+        }
+
+        private void RegisterServerImpl(Server server)
+        {
+            server.UserData = UserDataTag.Server;
+
+            _multiWait.LinkMultiWaitHolder(server);
+        }
+
+        protected virtual Result OnNeedsToAccept(int portIndex, Server server)
+        {
+            throw new NotSupportedException();
+        }
+
+        public void ServiceRequests()
+        {
+            while (WaitAndProcessRequestsImpl());
+        }
+
+        public void WaitAndProcessRequests()
+        {
+            WaitAndProcessRequestsImpl();
+        }
+
+        private bool WaitAndProcessRequestsImpl()
+        {
+            try
+            {
+                MultiWaitHolder multiWait = WaitSignaled();
+
+                if (multiWait == null)
+                {
+                    return false;
+                }
+
+                DebugUtil.Assert(Process(multiWait).IsSuccess);
+
+                return HorizonStatic.ThreadContext.Running;
+            }
+            catch (ThreadTerminatedException)
+            {
+                return false;
+            }
+        }
+
+        private MultiWaitHolder WaitSignaled()
+        {
+            lock (_multiWaitSelectionLock)
+            {
+                while (true)
+                {
+                    ProcessWaitList();
+
+                    MultiWaitHolder selected = _multiWait.WaitAny();
+
+                    if (selected == _requestStopEventHolder)
+                    {
+                        return null;
+                    }
+                    else if (selected == _notifyEventHolder)
+                    {
+                        _notifyEvent.Clear();
+                    }
+                    else
+                    {
+                        selected.UnlinkFromMultiWaitHolder();
+
+                        return selected;
+                    }
+                }
+            }
+        }
+
+        public void ResumeProcessing()
+        {
+            _requestStopEvent.Clear();
+        }
+
+        public void RequestStopProcessing()
+        {
+            _requestStopEvent.Signal();
+        }
+
+        protected override void RegisterSessionToWaitList(ServerSession session)
+        {
+            session.HasReceived = false;
+            session.UserData = UserDataTag.Session;
+            RegisterToWaitList(session);
+        }
+
+        private void RegisterToWaitList(MultiWaitHolder holder)
+        {
+            lock (_waitListLock)
+            {
+                _waitList.LinkMultiWaitHolder(holder);
+                _notifyEvent.Signal();
+            }
+        }
+
+        private void ProcessWaitList()
+        {
+            lock (_waitListLock)
+            {
+                _multiWait.MoveAllFrom(_waitList);
+            }
+        }
+
+        private Result Process(MultiWaitHolder holder)
+        {
+            switch ((UserDataTag)holder.UserData)
+            {
+                case UserDataTag.Server:
+                    return ProcessForServer(holder);
+                case UserDataTag.Session:
+                    return ProcessForSession(holder);
+                default:
+                    throw new NotImplementedException(((UserDataTag)holder.UserData).ToString());
+            }
+        }
+
+        private Result ProcessForServer(MultiWaitHolder holder)
+        {
+            DebugUtil.Assert((UserDataTag)holder.UserData == UserDataTag.Server);
+
+            Server server = (Server)holder;
+
+            try
+            {
+                if (server.StaticObject != null)
+                {
+                    return AcceptSession(server.PortHandle, server.StaticObject.Clone());
+                }
+                else
+                {
+                    return OnNeedsToAccept(server.PortIndex, server);
+                }
+            }
+            finally
+            {
+                RegisterToWaitList(server);
+            }
+        }
+
+        private Result ProcessForSession(MultiWaitHolder holder)
+        {
+            DebugUtil.Assert((UserDataTag)holder.UserData == UserDataTag.Session);
+
+            ServerSession session = (ServerSession)holder;
+
+            using var tlsMessage = HorizonStatic.AddressSpace.GetWritableRegion(HorizonStatic.ThreadContext.TlsAddress, Api.TlsMessageBufferSize);
+
+            Result result;
+
+            if (_canDeferInvokeRequest)
+            {
+                // If the request is deferred, we save the message on a temporary buffer to process it later.
+                using var savedMessage = HorizonStatic.AddressSpace.GetWritableRegion(session.SavedMessage.Address, (int)session.SavedMessage.Size);
+
+                DebugUtil.Assert(tlsMessage.Memory.Length == savedMessage.Memory.Length);
+
+                if (!session.HasReceived)
+                {
+                    result = ReceiveRequest(session, tlsMessage.Memory.Span);
+
+                    if (result.IsFailure)
+                    {
+                        return result;
+                    }
+
+                    session.HasReceived = true;
+                    tlsMessage.Memory.Span.CopyTo(savedMessage.Memory.Span);
+                }
+                else
+                {
+                    savedMessage.Memory.Span.CopyTo(tlsMessage.Memory.Span);
+                }
+
+                result = ProcessRequest(session, tlsMessage.Memory.Span);
+
+                if (result.IsFailure && !SfResult.Invalidated(result))
+                {
+                    return result;
+                }
+            }
+            else
+            {
+                if (!session.HasReceived)
+                {
+                    result = ReceiveRequest(session, tlsMessage.Memory.Span);
+
+                    if (result.IsFailure)
+                    {
+                        return result;
+                    }
+
+                    session.HasReceived = true;
+                }
+
+                result = ProcessRequest(session, tlsMessage.Memory.Span);
+
+                if (result.IsFailure)
+                {
+                    // Those results are not valid because the service does not support deferral.
+                    if (SfResult.RequestDeferred(result) || SfResult.Invalidated(result))
+                    {
+                        result.AbortOnFailure();
+                    }
+
+                    return result;
+                }
+            }
+
+            return Result.Success;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSession.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSession.cs
new file mode 100644
index 0000000000..eb98fefd0e
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSession.cs
@@ -0,0 +1,23 @@
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    class ServerSession : MultiWaitHolderOfHandle
+    {
+        public ServiceObjectHolder ServiceObjectHolder { get; set; }
+        public PointerAndSize PointerBuffer { get; set; }
+        public PointerAndSize SavedMessage { get; set; }
+        public int SessionIndex { get; }
+        public int SessionHandle { get; }
+        public bool IsClosed { get; set; }
+        public bool HasReceived { get; set; }
+
+        public ServerSession(int index, int handle, ServiceObjectHolder obj) : base(handle)
+        {
+            ServiceObjectHolder = obj;
+            SessionIndex = index;
+            SessionHandle = handle;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSessionManager.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSessionManager.cs
new file mode 100644
index 0000000000..e85892f26d
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSessionManager.cs
@@ -0,0 +1,335 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sm;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    class ServerSessionManager
+    {
+        public Result AcceptSession(int portHandle, ServiceObjectHolder obj)
+        {
+            return AcceptSession(out _, portHandle, obj);
+        }
+
+        private Result AcceptSession(out ServerSession session, int portHandle, ServiceObjectHolder obj)
+        {
+            return AcceptSessionImpl(out session, portHandle, obj);
+        }
+
+        private Result AcceptSessionImpl(out ServerSession session, int portHandle, ServiceObjectHolder obj)
+        {
+            session = null;
+
+            Result result = HorizonStatic.Syscall.AcceptSession(out int sessionHandle, portHandle);
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            bool succeeded = false;
+
+            try
+            {
+                result = RegisterSessionImpl(out session, sessionHandle, obj);
+
+                if (result.IsFailure)
+                {
+                    return result;
+                }
+
+                succeeded = true;
+            }
+            finally
+            {
+                if (!succeeded)
+                {
+                    HorizonStatic.Syscall.CloseHandle(sessionHandle);
+                }
+            }
+
+            return Result.Success;
+        }
+
+        public Result RegisterSession(int sessionHandle, ServiceObjectHolder obj)
+        {
+            return RegisterSession(out _, sessionHandle, obj);
+        }
+
+        public Result RegisterSession(out ServerSession session, int sessionHandle, ServiceObjectHolder obj)
+        {
+            return RegisterSessionImpl(out session, sessionHandle, obj);
+        }
+
+        private Result RegisterSessionImpl(out ServerSession session, int sessionHandle, ServiceObjectHolder obj)
+        {
+            Result result = CreateSessionImpl(out session, sessionHandle, obj);
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            session.PointerBuffer = GetSessionPointerBuffer(session);
+            session.SavedMessage = GetSessionSavedMessageBuffer(session);
+
+            RegisterSessionToWaitList(session);
+            return Result.Success;
+        }
+
+        protected virtual void RegisterSessionToWaitList(ServerSession session)
+        {
+            throw new NotSupportedException();
+        }
+
+        private Result CreateSessionImpl(out ServerSession session, int sessionHandle, ServiceObjectHolder obj)
+        {
+            session = AllocateSession(sessionHandle, obj);
+
+            if (session == null)
+            {
+                return HipcResult.OutOfSessionMemory;
+            }
+
+            return Result.Success;
+        }
+
+        protected virtual ServerSession AllocateSession(int sessionHandle, ServiceObjectHolder obj)
+        {
+            throw new NotSupportedException();
+        }
+
+        protected virtual void FreeSession(ServerSession session)
+        {
+            throw new NotSupportedException();
+        }
+
+        protected virtual Server AllocateServer(
+            int portIndex,
+            int portHandle,
+            ServiceName name,
+            bool managed,
+            ServiceObjectHolder staticHoder)
+        {
+            throw new NotSupportedException();
+        }
+
+        protected virtual void DestroyServer(Server server)
+        {
+            throw new NotSupportedException();
+        }
+
+        protected virtual PointerAndSize GetSessionPointerBuffer(ServerSession session)
+        {
+            throw new NotSupportedException();
+        }
+
+        protected virtual PointerAndSize GetSessionSavedMessageBuffer(ServerSession session)
+        {
+            throw new NotSupportedException();
+        }
+
+        private void DestroySession(ServerSession session)
+        {
+            FreeSession(session);
+        }
+
+        protected void CloseSessionImpl(ServerSession session)
+        {
+            int sessionHandle = session.Handle;
+            Os.FinalizeMultiWaitHolder(session);
+            DestroySession(session);
+            HorizonStatic.Syscall.CloseHandle(sessionHandle).AbortOnFailure();
+        }
+
+        private static CommandType GetCmifCommandType(ReadOnlySpan<byte> message)
+        {
+            return MemoryMarshal.Cast<byte, Header>(message)[0].Type;
+        }
+
+        public Result ProcessRequest(ServerSession session, Span<byte> message)
+        {
+            if (session.IsClosed || GetCmifCommandType(message) == CommandType.Close)
+            {
+                CloseSessionImpl(session);
+                return Result.Success;
+            }
+            else
+            {
+                Result result = ProcessRequestImpl(session, message, message);
+
+                if (result.IsSuccess)
+                {
+                    RegisterSessionToWaitList(session);
+                    return Result.Success;
+                }
+                else if (SfResult.RequestContextChanged(result))
+                {
+                    return result;
+                }
+                else
+                {
+                    Logger.Warning?.Print(LogClass.KernelIpc, $"Request processing returned error {result}");
+
+                    CloseSessionImpl(session);
+                    return Result.Success;
+                }
+            }
+        }
+
+        private Result ProcessRequestImpl(ServerSession session, Span<byte> inMessage, Span<byte> outMessage)
+        {
+            CommandType commandType = GetCmifCommandType(inMessage);
+
+            using var _ = new ScopedInlineContextChange(GetInlineContext(commandType, inMessage));
+
+            switch (commandType)
+            {
+                case CommandType.Request:
+                case CommandType.RequestWithContext:
+                    return DispatchRequest(session.ServiceObjectHolder, session, inMessage, outMessage);
+                case CommandType.Control:
+                case CommandType.ControlWithContext:
+                    return DispatchManagerRequest(session, inMessage, outMessage);
+                default:
+                    return HipcResult.UnknownCommandType;
+            }
+        }
+
+        private static int GetInlineContext(CommandType commandType, ReadOnlySpan<byte> inMessage)
+        {
+            switch (commandType)
+            {
+                case CommandType.RequestWithContext:
+                case CommandType.ControlWithContext:
+                    if (inMessage.Length >= 0x10)
+                    {
+                        return MemoryMarshal.Cast<byte, int>(inMessage)[3];
+                    }
+                    break;
+            }
+
+            return 0;
+        }
+
+        protected Result ReceiveRequest(ServerSession session, Span<byte> message)
+        {
+            return ReceiveRequestImpl(session, message);
+        }
+
+        private Result ReceiveRequestImpl(ServerSession session, Span<byte> message)
+        {
+            PointerAndSize pointerBuffer = session.PointerBuffer;
+
+            while (true)
+            {
+                if (pointerBuffer.Address != 0)
+                {
+                    HipcMessageData messageData = HipcMessage.WriteMessage(message, new HipcMetadata()
+                    {
+                        Type = (int)CommandType.Invalid,
+                        ReceiveStaticsCount = HipcMessage.AutoReceiveStatic
+                    });
+
+                    messageData.ReceiveList[0] = new HipcReceiveListEntry(pointerBuffer.Address, pointerBuffer.Size);
+                }
+                else
+                {
+                    MemoryMarshal.Cast<byte, Header>(message)[0] = new Header()
+                    {
+                        Type = CommandType.Invalid
+                    };
+                }
+
+                Result result = Api.Receive(out ReceiveResult recvResult, session.Handle, message);
+
+                if (result.IsFailure)
+                {
+                    return result;
+                }
+
+                switch (recvResult)
+                {
+                    case ReceiveResult.Success:
+                        session.IsClosed = false;
+                        return Result.Success;
+                    case ReceiveResult.Closed:
+                        session.IsClosed = true;
+                        return Result.Success;
+                }
+            }
+        }
+
+        protected virtual Result DispatchManagerRequest(ServerSession session, Span<byte> inMessage, Span<byte> outMessage)
+        {
+            return SfResult.NotSupported;
+        }
+
+        protected virtual Result DispatchRequest(
+            ServiceObjectHolder objectHolder,
+            ServerSession session,
+            Span<byte> inMessage,
+            Span<byte> outMessage)
+        {
+            HipcMessage request;
+
+            try
+            {
+                request = new HipcMessage(inMessage);
+            }
+            catch (ArgumentOutOfRangeException)
+            {
+                return HipcResult.InvalidRequestSize;
+            }
+
+            var dispatchCtx = new ServiceDispatchContext()
+            {
+                ServiceObject = objectHolder.ServiceObject,
+                Manager = this,
+                Session = session,
+                HandlesToClose = new HandlesToClose(),
+                PointerBuffer = session.PointerBuffer,
+                InMessageBuffer = inMessage,
+                OutMessageBuffer = outMessage,
+                Request = request
+            };
+
+            ReadOnlySpan<byte> inRawData = MemoryMarshal.Cast<uint, byte>(dispatchCtx.Request.Data.DataWords);
+
+            int inRawSize = dispatchCtx.Request.Meta.DataWordsCount * sizeof(uint);
+
+            if (inRawSize < 0x10)
+            {
+                return HipcResult.InvalidRequestSize;
+            }
+
+            Result result = objectHolder.ProcessMessage(ref dispatchCtx, inRawData);
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            result = Api.Reply(session.SessionHandle, outMessage);
+
+            ref var handlesToClose = ref dispatchCtx.HandlesToClose;
+
+            for (int i = 0; i < handlesToClose.Count; i++)
+            {
+                HorizonStatic.Syscall.CloseHandle(handlesToClose[i]).AbortOnFailure();
+            }
+
+            return result;
+        }
+
+        public ServerSessionManager GetSessionManagerByTag(uint tag)
+        {
+            // Official FW does not do anything with the tag currently.
+            return this;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/SpecialHeader.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/SpecialHeader.cs
new file mode 100644
index 0000000000..8b747626d4
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/SpecialHeader.cs
@@ -0,0 +1,27 @@
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+    struct SpecialHeader
+    {
+        private uint _word;
+
+        public bool SendPid
+        {
+            get => _word.Extract(0);
+            set => _word = _word.Insert(0, value);
+        }
+
+        public int CopyHandlesCount
+        {
+            get => (int)_word.Extract(1, 4);
+            set => _word = _word.Insert(1, 4, (uint)value);
+        }
+
+        public int MoveHandlesCount
+        {
+            get => (int)_word.Extract(5, 4);
+            set => _word = _word.Insert(5, 4, (uint)value);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs b/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs
new file mode 100644
index 0000000000..53202edeeb
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs
@@ -0,0 +1,421 @@
+using Ryujinx.Common;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+    class HipcCommandProcessor : ServerMessageProcessor
+    {
+        private readonly CommandArg[] _args;
+
+        private readonly int[] _inOffsets;
+        private readonly int[] _outOffsets;
+        private readonly PointerAndSize[] _bufferRanges;
+
+        private readonly bool _hasInProcessIdHolder;
+        private readonly int _inObjectsCount;
+        private readonly int _outObjectsCount;
+        private readonly int _inMapAliasBuffersCount;
+        private readonly int _outMapAliasBuffersCount;
+        private readonly int _inPointerBuffersCount;
+        private readonly int _outPointerBuffersCount;
+        private readonly int _outFixedSizePointerBuffersCount;
+        private readonly int _inMoveHandlesCount;
+        private readonly int _inCopyHandlesCount;
+        private readonly int _outMoveHandlesCount;
+        private readonly int _outCopyHandlesCount;
+
+        public int FunctionArgumentsCount => _args.Length;
+
+        public int InRawDataSize => BitUtils.AlignUp(_inOffsets[^1], sizeof(ushort));
+        public int OutRawDataSize => BitUtils.AlignUp(_outOffsets[^1], sizeof(uint));
+
+        private int OutUnfixedSizePointerBuffersCount => _outPointerBuffersCount - _outFixedSizePointerBuffersCount;
+
+        public HipcCommandProcessor(CommandArg[] args)
+        {
+            _args = args;
+
+            for (int i = 0; i < args.Length; i++)
+            {
+                var argInfo = args[i];
+
+                switch (argInfo.Type)
+                {
+                    case CommandArgType.Buffer:
+                        var flags = argInfo.BufferFlags;
+
+                        if (flags.HasFlag(HipcBufferFlags.In))
+                        {
+                            if (flags.HasFlag(HipcBufferFlags.AutoSelect))
+                            {
+                                _inMapAliasBuffersCount++;
+                                _inPointerBuffersCount++;
+                            }
+                            else if (flags.HasFlag(HipcBufferFlags.MapAlias))
+                            {
+                                _inMapAliasBuffersCount++;
+                            }
+                            else if (flags.HasFlag(HipcBufferFlags.Pointer))
+                            {
+                                _inPointerBuffersCount++;
+                            }
+                        }
+                        else
+                        {
+                            bool autoSelect = flags.HasFlag(HipcBufferFlags.AutoSelect);
+                            if (autoSelect || flags.HasFlag(HipcBufferFlags.Pointer))
+                            {
+                                _outPointerBuffersCount++;
+
+                                if (flags.HasFlag(HipcBufferFlags.FixedSize))
+                                {
+                                    _outFixedSizePointerBuffersCount++;
+                                }
+                            }
+
+                            if (autoSelect || flags.HasFlag(HipcBufferFlags.MapAlias))
+                            {
+                                _outMapAliasBuffersCount++;
+                            }
+                        }
+                        break;
+                    case CommandArgType.InCopyHandle:
+                        _inCopyHandlesCount++;
+                        break;
+                    case CommandArgType.InMoveHandle:
+                        _inMoveHandlesCount++;
+                        break;
+                    case CommandArgType.InObject:
+                        _inObjectsCount++;
+                        break;
+                    case CommandArgType.ProcessId:
+                        _hasInProcessIdHolder = true;
+                        break;
+                    case CommandArgType.OutCopyHandle:
+                        _outCopyHandlesCount++;
+                        break;
+                    case CommandArgType.OutMoveHandle:
+                        _outMoveHandlesCount++;
+                        break;
+                    case CommandArgType.OutObject:
+                        _outObjectsCount++;
+                        break;
+                }
+            }
+
+            _inOffsets = RawDataOffsetCalculator.Calculate(args.Where(x => x.Type == CommandArgType.InArgument).ToArray());
+            _outOffsets = RawDataOffsetCalculator.Calculate(args.Where(x => x.Type == CommandArgType.OutArgument).ToArray());
+            _bufferRanges = new PointerAndSize[args.Length];
+        }
+
+        public int GetInArgOffset(int argIndex)
+        {
+            return _inOffsets[argIndex];
+        }
+
+        public int GetOutArgOffset(int argIndex)
+        {
+            return _outOffsets[argIndex];
+        }
+
+        public PointerAndSize GetBufferRange(int argIndex)
+        {
+            return _bufferRanges[argIndex];
+        }
+
+        public Result ProcessBuffers(ref ServiceDispatchContext context, bool[] isBufferMapAlias, ServerMessageRuntimeMetadata runtimeMetadata)
+        {
+            bool mapAliasBuffersValid = true;
+
+            ulong pointerBufferTail = context.PointerBuffer.Address;
+            ulong pointerBufferHead = pointerBufferTail + context.PointerBuffer.Size;
+
+            int sendMapAliasIndex = 0;
+            int recvMapAliasIndex = 0;
+            int sendPointerIndex = 0;
+            int unfixedRecvPointerIndex = 0;
+
+            for (int i = 0; i < _args.Length; i++)
+            {
+                if (_args[i].Type != CommandArgType.Buffer)
+                {
+                    continue;
+                }
+
+                var flags = _args[i].BufferFlags;
+                bool isMapAlias;
+
+                if (flags.HasFlag(HipcBufferFlags.MapAlias))
+                {
+                    isMapAlias = true;
+                }
+                else if (flags.HasFlag(HipcBufferFlags.Pointer))
+                {
+                    isMapAlias = false;
+                }
+                else /* if (flags.HasFlag(HipcBufferFlags.HipcAutoSelect)) */
+                {
+                    var descriptor = flags.HasFlag(HipcBufferFlags.In)
+                        ? context.Request.Data.SendBuffers[sendMapAliasIndex]
+                        : context.Request.Data.ReceiveBuffers[recvMapAliasIndex];
+
+                    isMapAlias = descriptor.Address != 0UL;
+                }
+
+                isBufferMapAlias[i] = isMapAlias;
+
+                if (isMapAlias)
+                {
+                    var descriptor = flags.HasFlag(HipcBufferFlags.In)
+                        ? context.Request.Data.SendBuffers[sendMapAliasIndex++]
+                        : context.Request.Data.ReceiveBuffers[recvMapAliasIndex++];
+
+                    _bufferRanges[i] = new PointerAndSize(descriptor.Address, descriptor.Size);
+
+                    if (!IsMapTransferModeValid(flags, descriptor.Mode))
+                    {
+                        mapAliasBuffersValid = false;
+                    }
+                }
+                else
+                {
+                    if (flags.HasFlag(HipcBufferFlags.In))
+                    {
+                        var descriptor = context.Request.Data.SendStatics[sendPointerIndex++];
+                        ulong address = descriptor.Address;
+                        ulong size = descriptor.Size;
+                        _bufferRanges[i] = new PointerAndSize(address, size);
+
+                        if (size != 0)
+                        {
+                            pointerBufferTail = Math.Max(pointerBufferTail, address + size);
+                        }
+                    }
+                    else /* if (flags.HasFlag(HipcBufferFlags.Out)) */
+                    {
+                        ulong size;
+
+                        if (flags.HasFlag(HipcBufferFlags.FixedSize))
+                        {
+                            size = _args[i].BufferFixedSize;
+                        }
+                        else
+                        {
+                            var data = MemoryMarshal.Cast<uint, byte>(context.Request.Data.DataWords);
+                            var recvPointerSizes = MemoryMarshal.Cast<byte, ushort>(data.Slice(runtimeMetadata.UnfixedOutPointerSizeOffset));
+                            size = recvPointerSizes[unfixedRecvPointerIndex++];
+                        }
+
+                        pointerBufferHead = BitUtils.AlignDown(pointerBufferHead - size, 0x10UL);
+                        _bufferRanges[i] = new PointerAndSize(pointerBufferHead, size);
+                    }
+                }
+            }
+
+            if (!mapAliasBuffersValid)
+            {
+                return HipcResult.InvalidCmifRequest;
+            }
+
+            if (_outPointerBuffersCount != 0 && pointerBufferTail > pointerBufferHead)
+            {
+                return HipcResult.PointerBufferTooSmall;
+            }
+
+            return Result.Success;
+        }
+
+        private static bool IsMapTransferModeValid(HipcBufferFlags flags, HipcBufferMode mode)
+        {
+            if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure))
+            {
+                return mode == HipcBufferMode.NonSecure;
+            }
+            else if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
+            {
+                return mode == HipcBufferMode.NonDevice;
+            }
+            else
+            {
+                return mode == HipcBufferMode.Normal;
+            }
+        }
+
+        public void SetOutBuffers(HipcMessageData response, bool[] isBufferMapAlias)
+        {
+            int recvPointerIndex = 0;
+
+            for (int i = 0; i < _args.Length; i++)
+            {
+                if (_args[i].Type != CommandArgType.Buffer)
+                {
+                    continue;
+                }
+
+                var flags = _args[i].BufferFlags;
+                if (flags.HasFlag(HipcBufferFlags.Out))
+                {
+                    var buffer = _bufferRanges[i];
+
+                    if (flags.HasFlag(HipcBufferFlags.Pointer))
+                    {
+                        response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
+                    }
+                    else if (flags.HasFlag(HipcBufferFlags.AutoSelect))
+                    {
+                        if (!isBufferMapAlias[i])
+                        {
+                            response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
+                        }
+                        else
+                        {
+                            response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(0UL, 0, recvPointerIndex);
+                        }
+                    }
+
+                    recvPointerIndex++;
+                }
+            }
+        }
+
+        public override void SetImplementationProcessor(ServerMessageProcessor impl)
+        {
+            // We don't need to do anything here as this should be always the last processor to be called.
+        }
+
+        public override ServerMessageRuntimeMetadata GetRuntimeMetadata()
+        {
+            return new ServerMessageRuntimeMetadata(
+                (ushort)InRawDataSize,
+                (ushort)OutRawDataSize,
+                (byte)Unsafe.SizeOf<CmifInHeader>(),
+                (byte)Unsafe.SizeOf<CmifOutHeader>(),
+                (byte)_inObjectsCount,
+                (byte)_outObjectsCount);
+        }
+
+        public override Result PrepareForProcess(ref ServiceDispatchContext context, ServerMessageRuntimeMetadata runtimeMetadata)
+        {
+            ref var meta = ref context.Request.Meta;
+            bool requestValid = true;
+            requestValid &= meta.SendPid == _hasInProcessIdHolder;
+            requestValid &= meta.SendStaticsCount == _inPointerBuffersCount;
+            requestValid &= meta.SendBuffersCount == _inMapAliasBuffersCount;
+            requestValid &= meta.ReceiveBuffersCount == _outMapAliasBuffersCount;
+            requestValid &= meta.ExchangeBuffersCount == 0;
+            requestValid &= meta.CopyHandlesCount == _inCopyHandlesCount;
+            requestValid &= meta.MoveHandlesCount == _inMoveHandlesCount;
+
+            int rawSizeInBytes = meta.DataWordsCount * sizeof(uint);
+            int commandRawSize = BitUtils.AlignUp(runtimeMetadata.UnfixedOutPointerSizeOffset + (OutUnfixedSizePointerBuffersCount * sizeof(ushort)), sizeof(uint));
+            requestValid &= rawSizeInBytes >= commandRawSize;
+
+            return requestValid ? Result.Success : HipcResult.InvalidCmifRequest;
+        }
+
+        public Result GetInObjects(ServerMessageProcessor processor, Span<IServiceObject> objects)
+        {
+            if (objects.Length == 0)
+            {
+                return Result.Success;
+            }
+
+            ServiceObjectHolder[] inObjects = new ServiceObjectHolder[objects.Length];
+            Result result = processor.GetInObjects(inObjects);
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            int inObjectIndex = 0;
+
+            for (int i = 0; i < _args.Length; i++)
+            {
+                if (_args[i].Type == CommandArgType.InObject)
+                {
+                    int index = inObjectIndex++;
+                    var inObject = inObjects[index];
+
+                    objects[index] = inObject?.ServiceObject;
+                }
+            }
+
+            return Result.Success;
+        }
+
+        public override Result GetInObjects(Span<ServiceObjectHolder> inObjects)
+        {
+            return SfResult.NotSupported;
+        }
+
+        public override HipcMessageData PrepareForReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
+        {
+            int rawDataSize = OutRawDataSize + runtimeMetadata.OutHeadersSize;
+            var response = HipcMessage.WriteResponse(
+                context.OutMessageBuffer,
+                _outPointerBuffersCount,
+                (BitUtils.AlignUp(rawDataSize, 4) + 0x10) / sizeof(uint),
+                _outCopyHandlesCount,
+                _outMoveHandlesCount + runtimeMetadata.OutObjectsCount);
+            outRawData = MemoryMarshal.Cast<uint, byte>(response.DataWords);
+            return response;
+        }
+
+        public override void PrepareForErrorReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
+        {
+            int rawDataSize = runtimeMetadata.OutHeadersSize;
+            var response = HipcMessage.WriteResponse(
+                context.OutMessageBuffer,
+                0,
+                (BitUtils.AlignUp(rawDataSize, 4) + 0x10) / sizeof(uint),
+                0,
+                0);
+            outRawData = MemoryMarshal.Cast<uint, byte>(response.DataWords);
+        }
+
+        public void SetOutObjects(ref ServiceDispatchContext context, HipcMessageData response, Span<IServiceObject> objects)
+        {
+            if (objects.Length == 0)
+            {
+                return;
+            }
+
+            ServiceObjectHolder[] outObjects = new ServiceObjectHolder[objects.Length];
+
+            for (int i = 0; i < objects.Length; i++)
+            {
+                outObjects[i] = objects[i] != null ? new ServiceObjectHolder(objects[i]) : null;
+            }
+
+            context.Processor.SetOutObjects(ref context, response, outObjects);
+        }
+
+        public override void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span<ServiceObjectHolder> outObjects)
+        {
+            for (int index = 0; index < _outObjectsCount; index++)
+            {
+                SetOutObjectImpl(index, response, context.Manager, outObjects[index]);
+            }
+        }
+
+        private void SetOutObjectImpl(int index, HipcMessageData response, ServerSessionManager manager, ServiceObjectHolder obj)
+        {
+            if (obj == null)
+            {
+                response.MoveHandles[index] = 0;
+                return;
+            }
+
+            Api.CreateSession(out int serverHandle, out int clientHandle).AbortOnFailure();
+            manager.RegisterSession(serverHandle, obj).AbortOnFailure();
+            response.MoveHandles[index] = clientHandle;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/IServiceObject.cs b/Ryujinx.Horizon/Sdk/Sf/IServiceObject.cs
new file mode 100644
index 0000000000..afa57fef9d
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/IServiceObject.cs
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+    interface IServiceObject
+    {
+        IReadOnlyDictionary<int, CommandHandler> GetCommandHandlers();
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/RawDataOffsetCalculator.cs b/Ryujinx.Horizon/Sdk/Sf/RawDataOffsetCalculator.cs
new file mode 100644
index 0000000000..982f454f01
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/RawDataOffsetCalculator.cs
@@ -0,0 +1,51 @@
+using Ryujinx.Common;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+    static class RawDataOffsetCalculator
+    {
+        public static int[] Calculate(CommandArg[] args)
+        {
+            int[] offsets = new int[args.Length + 1];
+
+            if (args.Length != 0)
+            {
+                int argsCount = args.Length;
+
+                int[] sizes = new int[argsCount];
+                int[] aligns = new int[argsCount];
+                int[] map = new int[argsCount];
+
+                for (int i = 0; i < argsCount; i++)
+                {
+                    sizes[i] = args[i].ArgSize;
+                    aligns[i] = args[i].ArgAlignment;
+                    map[i] = i;
+                }
+
+                for (int i = 1; i < argsCount; i++)
+                {
+                    for (int j = i; j > 0 && aligns[map[j - 1]] > aligns[map[j]]; j--)
+                    {
+                        var temp = map[j - 1];
+                        map[j - 1] = map[j];
+                        map[j] = temp;
+                    }
+                }
+
+                int offset = 0;
+
+                foreach (int i in map)
+                {
+                    offset = BitUtils.AlignUp(offset, aligns[i]);
+                    offsets[i] = offset;
+                    offset += sizes[i];
+                }
+
+                offsets[argsCount] = offset;
+            }
+
+            return offsets;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/SfResult.cs b/Ryujinx.Horizon/Sdk/Sf/SfResult.cs
new file mode 100644
index 0000000000..6aa11ba5fd
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/SfResult.cs
@@ -0,0 +1,31 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+    static class SfResult
+    {
+        public const int ModuleId = 10;
+
+        public static Result NotSupported => new Result(ModuleId, 1);
+        public static Result InvalidHeaderSize => new Result(ModuleId, 202);
+        public static Result InvalidInHeader => new Result(ModuleId, 211);
+        public static Result InvalidOutHeader => new Result(ModuleId, 212);
+        public static Result UnknownCommandId => new Result(ModuleId, 221);
+        public static Result InvalidOutRawSize => new Result(ModuleId, 232);
+        public static Result InvalidInObjectsCount => new Result(ModuleId, 235);
+        public static Result InvalidOutObjectsCount => new Result(ModuleId, 236);
+        public static Result InvalidInObject => new Result(ModuleId, 239);
+
+        public static Result TargetNotFound => new Result(ModuleId, 261);
+
+        public static Result OutOfDomainEntries => new Result(ModuleId, 301);
+
+        public static Result InvalidatedByUser => new Result(ModuleId, 802);
+        public static Result RequestDeferredByUser => new Result(ModuleId, 812);
+
+        public static bool RequestContextChanged(Result result) => result.InRange(800, 899);
+        public static bool Invalidated(Result result) => result.InRange(801, 809);
+
+        public static bool RequestDeferred(Result result) => result.InRange(811, 819);
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sm/ServiceName.cs b/Ryujinx.Horizon/Sdk/Sm/ServiceName.cs
new file mode 100644
index 0000000000..dbb300785f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sm/ServiceName.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sm
+{
+    [StructLayout(LayoutKind.Sequential, Pack = 1)]
+    struct ServiceName
+    {
+        public static ServiceName Invalid { get; } = new ServiceName(0);
+
+        public bool IsInvalid => Packed == 0;
+
+        public int Length => sizeof(ulong);
+
+        public ulong Packed { get; }
+
+        public byte this[int index]
+        {
+            get
+            {
+                if ((uint)index >= sizeof(ulong))
+                {
+                    throw new IndexOutOfRangeException();
+                }
+
+                return (byte)(Packed >> (index * 8));
+            }
+        }
+
+        private ServiceName(ulong packed)
+        {
+            Packed = packed;
+        }
+
+        public static ServiceName Encode(string name)
+        {
+            ulong packed = 0;
+
+            for (int index = 0; index < sizeof(ulong); index++)
+            {
+                if (index < name.Length)
+                {
+                    packed |= (ulong)(byte)name[index] << (index * 8);
+                }
+                else
+                {
+                    break;
+                }
+            }
+
+            return new ServiceName(packed);
+        }
+
+        public override bool Equals(object obj)
+        {
+            return obj is ServiceName serviceName && serviceName.Equals(this);
+        }
+
+        public bool Equals(ServiceName other)
+        {
+            return other.Packed == Packed;
+        }
+
+        public override int GetHashCode()
+        {
+            return Packed.GetHashCode();
+        }
+
+        public static bool operator ==(ServiceName lhs, ServiceName rhs)
+        {
+            return lhs.Equals(rhs);
+        }
+
+        public static bool operator !=(ServiceName lhs, ServiceName rhs)
+        {
+            return !lhs.Equals(rhs);
+        }
+
+        public override string ToString()
+        {
+            string name = string.Empty;
+
+            for (int index = 0; index < sizeof(ulong); index++)
+            {
+                byte character = (byte)(Packed >> (index * 8));
+
+                if (character == 0)
+                {
+                    break;
+                }
+
+                name += (char)character;
+            }
+
+            return name;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sm/SmApi.cs b/Ryujinx.Horizon/Sdk/Sm/SmApi.cs
new file mode 100644
index 0000000000..e4b0eea1cd
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sm/SmApi.cs
@@ -0,0 +1,107 @@
+using Ryujinx.Common.Memory;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sm
+{
+    class SmApi
+    {
+        private int _portHandle;
+
+        public Result Initialize()
+        {
+            Result result = HorizonStatic.Syscall.ConnectToNamedPort(out int portHandle, "sm:");
+
+            while (result == KernelResult.NotFound)
+            {
+                HorizonStatic.Syscall.SleepThread(50000000L);
+                result = HorizonStatic.Syscall.ConnectToNamedPort(out portHandle, "sm:");
+            }
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            _portHandle = portHandle;
+
+            return RegisterClient();
+        }
+
+        private Result RegisterClient()
+        {
+            Span<byte> data = stackalloc byte[8];
+
+            SpanWriter writer = new SpanWriter(data);
+
+            writer.Write(0UL);
+
+            return ServiceUtil.SendRequest(out _, _portHandle, 0, sendPid: true, data);
+        }
+
+        public Result GetServiceHandle(out int handle, ServiceName name)
+        {
+            Span<byte> data = stackalloc byte[8];
+
+            SpanWriter writer = new SpanWriter(data);
+
+            writer.Write(name);
+
+            Result result = ServiceUtil.SendRequest(out CmifResponse response, _portHandle, 1, sendPid: false, data);
+
+            if (result.IsFailure)
+            {
+                handle = 0;
+                return result;
+            }
+
+            handle = response.MoveHandles[0];
+            return Result.Success;
+        }
+
+        public Result RegisterService(out int handle, ServiceName name, int maxSessions, bool isLight)
+        {
+            Span<byte> data = stackalloc byte[16];
+
+            SpanWriter writer = new SpanWriter(data);
+
+            writer.Write(name);
+            writer.Write(isLight ? 1 : 0);
+            writer.Write(maxSessions);
+
+            Result result = ServiceUtil.SendRequest(out CmifResponse response, _portHandle, 2, sendPid: false, data);
+
+            if (result.IsFailure)
+            {
+                handle = 0;
+                return result;
+            }
+
+            handle = response.MoveHandles[0];
+            return Result.Success;
+        }
+
+        public Result UnregisterService(ServiceName name)
+        {
+            Span<byte> data = stackalloc byte[8];
+
+            SpanWriter writer = new SpanWriter(data);
+
+            writer.Write(name);
+
+            return ServiceUtil.SendRequest(out _, _portHandle, 3, sendPid: false, data);
+        }
+
+        public Result DetachClient()
+        {
+            Span<byte> data = stackalloc byte[8];
+
+            SpanWriter writer = new SpanWriter(data);
+
+            writer.Write(0UL);
+
+            return ServiceUtil.SendRequest(out _, _portHandle, 4, sendPid: true, data);
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/ServiceEntry.cs b/Ryujinx.Horizon/ServiceEntry.cs
new file mode 100644
index 0000000000..3fea46c193
--- /dev/null
+++ b/Ryujinx.Horizon/ServiceEntry.cs
@@ -0,0 +1,25 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Memory;
+using System;
+
+namespace Ryujinx.Horizon
+{
+    public struct ServiceEntry
+    {
+        private readonly Action _entrypoint;
+        private readonly HorizonOptions _options;
+
+        internal ServiceEntry(Action entrypoint, HorizonOptions options)
+        {
+            _entrypoint = entrypoint;
+            _options = options;
+        }
+
+        public void Start(ISyscallApi syscallApi, IVirtualMemoryManager addressSpace, IThreadContext threadContext)
+        {
+            HorizonStatic.Register(_options, syscallApi, addressSpace, threadContext, (int)threadContext.GetX(1));
+
+            _entrypoint();
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/ServiceTable.cs b/Ryujinx.Horizon/ServiceTable.cs
new file mode 100644
index 0000000000..933b6a59b6
--- /dev/null
+++ b/Ryujinx.Horizon/ServiceTable.cs
@@ -0,0 +1,22 @@
+using Ryujinx.Horizon.LogManager;
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon
+{
+    public static class ServiceTable
+    {
+        public static IEnumerable<ServiceEntry> GetServices(HorizonOptions options)
+        {
+            List<ServiceEntry> entries = new List<ServiceEntry>();
+
+            void RegisterService<T>() where T : IService
+            {
+                entries.Add(new ServiceEntry(T.Main, options));
+            }
+
+            RegisterService<LmMain>();
+
+            return entries;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs b/Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs
new file mode 100644
index 0000000000..fed420aa85
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs
@@ -0,0 +1,20 @@
+using Ryujinx.Horizon.Sdk.Sm;
+
+namespace Ryujinx.Horizon.Sm.Impl
+{
+    struct ServiceInfo
+    {
+        public ServiceName Name;
+        public ulong OwnerProcessId;
+        public int PortHandle;
+
+        public void Free()
+        {
+            HorizonStatic.Syscall.CloseHandle(PortHandle);
+
+            Name = ServiceName.Invalid;
+            OwnerProcessId = 0L;
+            PortHandle = 0;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs b/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs
new file mode 100644
index 0000000000..cdf2d17f1b
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs
@@ -0,0 +1,197 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf;
+using Ryujinx.Horizon.Sdk.Sm;
+
+namespace Ryujinx.Horizon.Sm.Impl
+{
+    class ServiceManager
+    {
+        private const int MaxServicesCount = 256;
+
+        private readonly ServiceInfo[] _services;
+
+        public ServiceManager()
+        {
+            _services = new ServiceInfo[MaxServicesCount];
+        }
+
+        public Result GetService(out int handle, ulong processId, ServiceName name)
+        {
+            handle = 0;
+            Result result = ValidateServiceName(name);
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            // TODO: Validation with GetProcessInfo etc.
+
+            int serviceIndex = GetServiceInfo(name);
+
+            if (serviceIndex < 0)
+            {
+                return SfResult.RequestDeferredByUser;
+            }
+
+            result = GetServiceImpl(out handle, ref _services[serviceIndex]);
+
+            if (result == KernelResult.SessionCountExceeded)
+            {
+                return SmResult.OutOfSessions;
+            }
+
+            return result;
+        }
+
+        private Result GetServiceImpl(out int handle, ref ServiceInfo serviceInfo)
+        {
+            return HorizonStatic.Syscall.ConnectToPort(out handle, serviceInfo.PortHandle);
+        }
+
+        public Result RegisterService(out int handle, ulong processId, ServiceName name, int maxSessions, bool isLight)
+        {
+            handle = 0;
+            Result result = ValidateServiceName(name);
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            // TODO: Validation with GetProcessInfo etc.
+
+            if (HasServiceInfo(name))
+            {
+                return SmResult.AlreadyRegistered;
+            }
+
+            return RegisterServiceImpl(out handle, processId, name, maxSessions, isLight);
+        }
+
+        public Result RegisterServiceForSelf(out int handle, ServiceName name, int maxSessions)
+        {
+            return RegisterServiceImpl(out handle, Os.GetCurrentProcessId(), name, maxSessions, false);
+        }
+
+        private Result RegisterServiceImpl(out int handle, ulong processId, ServiceName name, int maxSessions, bool isLight)
+        {
+            handle = 0;
+
+            Result result = ValidateServiceName(name);
+
+            if (!result.IsSuccess)
+            {
+                return result;
+            }
+
+            if (HasServiceInfo(name))
+            {
+                return SmResult.AlreadyRegistered;
+            }
+
+            int freeServiceIndex = GetFreeService();
+
+            if (freeServiceIndex < 0)
+            {
+                return SmResult.OutOfServices;
+            }
+
+            ref ServiceInfo freeService = ref _services[freeServiceIndex];
+
+            result = HorizonStatic.Syscall.CreatePort(out handle, out int clientPort, maxSessions, isLight, null);
+
+            if (!result.IsSuccess)
+            {
+                return result;
+            }
+
+            freeService.PortHandle = clientPort;
+            freeService.Name = name;
+            freeService.OwnerProcessId = processId;
+
+            return Result.Success;
+        }
+
+        public Result UnregisterService(ulong processId, ServiceName name)
+        {
+            Result result = ValidateServiceName(name);
+
+            if (result.IsFailure)
+            {
+                return result;
+            }
+
+            // TODO: Validation with GetProcessInfo etc.
+
+            int serviceIndex = GetServiceInfo(name);
+
+            if (serviceIndex < 0)
+            {
+                return SmResult.NotRegistered;
+            }
+
+            ref var serviceInfo = ref _services[serviceIndex];
+
+            if (serviceInfo.OwnerProcessId != processId)
+            {
+                return SmResult.NotAllowed;
+            }
+
+            serviceInfo.Free();
+            return Result.Success;
+        }
+
+        private static Result ValidateServiceName(ServiceName name)
+        {
+            if (name[0] == 0)
+            {
+                return SmResult.InvalidServiceName;
+            }
+
+            int nameLength = 1;
+
+            for (; nameLength < name.Length; nameLength++)
+            {
+                if (name[nameLength] == 0)
+                {
+                    break;
+                }
+            }
+
+            while (nameLength < name.Length)
+            {
+                if (name[nameLength++] != 0)
+                {
+                    return SmResult.InvalidServiceName;
+                }
+            }
+
+            return Result.Success;
+        }
+
+        private bool HasServiceInfo(ServiceName name)
+        {
+            return GetServiceInfo(name) != -1;
+        }
+
+        private int GetFreeService()
+        {
+            return GetServiceInfo(ServiceName.Invalid);
+        }
+
+        private int GetServiceInfo(ServiceName name)
+        {
+            for (int index = 0; index < MaxServicesCount; index++)
+            {
+                if (_services[index].Name == name)
+                {
+                    return index;
+                }
+            }
+
+            return -1;
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sm/ManagerService.cs b/Ryujinx.Horizon/Sm/ManagerService.cs
new file mode 100644
index 0000000000..1719dcfd5f
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/ManagerService.cs
@@ -0,0 +1,8 @@
+using Ryujinx.Horizon.Sdk.Sf;
+
+namespace Ryujinx.Horizon.Sm
+{
+    partial class ManagerService : IServiceObject
+    {
+    }
+}
diff --git a/Ryujinx.Horizon/Sm/SmMain.cs b/Ryujinx.Horizon/Sm/SmMain.cs
new file mode 100644
index 0000000000..8c37bece57
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/SmMain.cs
@@ -0,0 +1,30 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using Ryujinx.Horizon.Sdk.Sm;
+using Ryujinx.Horizon.Sm.Impl;
+
+namespace Ryujinx.Horizon.Sm
+{
+    public class SmMain
+    {
+        private enum PortIndex
+        {
+            User,
+            Manager
+        }
+
+        private const int MaxPortsCount = 2;
+
+        private readonly ServerManager _serverManager = new ServerManager(null, null, MaxPortsCount, ManagerOptions.Default, 0);
+        private readonly ServiceManager _serviceManager = new ServiceManager();
+
+        public void Main()
+        {
+            HorizonStatic.Syscall.ManageNamedPort(out int smHandle, "sm:", 64).AbortOnFailure();
+
+            _serverManager.RegisterServer((int)PortIndex.User, smHandle);
+            _serviceManager.RegisterServiceForSelf(out int smmHandle, ServiceName.Encode("sm:m"), 1).AbortOnFailure();
+            _serverManager.RegisterServer((int)PortIndex.Manager, smmHandle);
+            _serverManager.ServiceRequests();
+        }
+    }
+}
diff --git a/Ryujinx.Horizon/Sm/SmResult.cs b/Ryujinx.Horizon/Sm/SmResult.cs
new file mode 100644
index 0000000000..3063445dc8
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/SmResult.cs
@@ -0,0 +1,19 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sm
+{
+    static class SmResult
+    {
+        private const int ModuleId = 21;
+
+        public static Result OutOfProcess => new Result(ModuleId, 1);
+        public static Result InvalidClient => new Result(ModuleId, 2);
+        public static Result OutOfSessions => new Result(ModuleId, 3);
+        public static Result AlreadyRegistered => new Result(ModuleId, 4);
+        public static Result OutOfServices => new Result(ModuleId, 5);
+        public static Result InvalidServiceName => new Result(ModuleId, 6);
+        public static Result NotRegistered => new Result(ModuleId, 7);
+        public static Result NotAllowed => new Result(ModuleId, 8);
+        public static Result TooLargeAccessControl => new Result(ModuleId, 9);
+    }
+}
diff --git a/Ryujinx.Horizon/Sm/UserService.cs b/Ryujinx.Horizon/Sm/UserService.cs
new file mode 100644
index 0000000000..d3b4537bf9
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/UserService.cs
@@ -0,0 +1,66 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf;
+using Ryujinx.Horizon.Sdk.Sm;
+using Ryujinx.Horizon.Sm.Impl;
+
+namespace Ryujinx.Horizon.Sm
+{
+    partial class UserService : IServiceObject
+    {
+        private readonly ServiceManager _serviceManager;
+
+        private ulong _clientProcessId;
+        private bool _initialized;
+
+        public UserService(ServiceManager serviceManager)
+        {
+            _serviceManager = serviceManager;
+        }
+
+        [CmifCommand(0)]
+        public Result Initialize([ClientProcessId] ulong clientProcessId)
+        {
+            _clientProcessId = clientProcessId;
+            _initialized = true;
+
+            return Result.Success;
+        }
+
+        [CmifCommand(1)]
+        public Result GetService([MoveHandle] out int handle, ServiceName name)
+        {
+            if (!_initialized)
+            {
+                handle = 0;
+
+                return SmResult.InvalidClient;
+            }
+
+            return _serviceManager.GetService(out handle, _clientProcessId, name);
+        }
+
+        [CmifCommand(2)]
+        public Result RegisterService([MoveHandle] out int handle, ServiceName name, int maxSessions, bool isLight)
+        {
+            if (!_initialized)
+            {
+                handle = 0;
+
+                return SmResult.InvalidClient;
+            }
+
+            return _serviceManager.RegisterService(out handle, _clientProcessId, name, maxSessions, isLight);
+        }
+
+        [CmifCommand(3)]
+        public Result UnregisterService(ServiceName name)
+        {
+            if (!_initialized)
+            {
+                return SmResult.InvalidClient;
+            }
+
+            return _serviceManager.UnregisterService(_clientProcessId, name);
+        }
+    }
+}
diff --git a/Ryujinx.sln b/Ryujinx.sln
index 1eaf006c30..007252fd13 100644
--- a/Ryujinx.sln
+++ b/Ryujinx.sln
@@ -79,7 +79,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.LocaleGenerator", "Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "Ryujinx.Horizon\Ryujinx.Horizon.csproj", "{AF34127A-3A92-43E5-8496-14960A50B1F1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -227,10 +231,18 @@ Global
 		{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
+		{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE